]> git.refcnt.org Git - colorize.git/blobdiff - colorize.c
Merge branch 'config_file'
[colorize.git] / colorize.c
index f80bdced0626687af9494834053e7991c89576b2..147e684a3c30aef2c3c9ca3d19975837116bc2ce 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <time.h>
 #include <unistd.h>
+#include <wordexp.h>
 
 #ifndef DEBUG
 # define DEBUG 0
@@ -216,10 +217,22 @@ static const struct {
     { bg_colors, COUNT_OF (bg_colors, struct color), "background" },
 };
 
+static unsigned int opts_set;
+enum {
+    OPT_ATTR_SET = 0x01,
+    OPT_EXCLUDE_RANDOM_SET = 0x02,
+    OPT_OMIT_COLOR_EMPTY_SET = 0x04
+};
+static struct {
+    char *attr;
+    char *exclude_random;
+} opts_arg = { NULL, NULL };
+
 enum {
     OPT_ATTR = 1,
     OPT_CLEAN,
     OPT_CLEAN_ALL,
+    OPT_CONFIG,
     OPT_EXCLUDE_RANDOM,
     OPT_OMIT_COLOR_EMPTY,
     OPT_HELP,
@@ -230,6 +243,7 @@ static const struct option long_opts[] = {
     { "attr",             required_argument, &opt_type, OPT_ATTR             },
     { "clean",            no_argument,       &opt_type, OPT_CLEAN            },
     { "clean-all",        no_argument,       &opt_type, OPT_CLEAN_ALL        },
+    { "config",           required_argument, &opt_type, OPT_CONFIG           },
     { "exclude-random",   required_argument, &opt_type, OPT_EXCLUDE_RANDOM   },
     { "omit-color-empty", no_argument,       &opt_type, OPT_OMIT_COLOR_EMPTY },
     { "help",             no_argument,       &opt_type, OPT_HELP             },
@@ -270,13 +284,14 @@ static const char *program_name;
 #if DEBUG
 static void print_tstamp (FILE *);
 #endif
-static void process_opts (int, char **);
+static void process_opts (int, char **, char **);
 static void process_opt_attr (const char *, const bool);
 static void write_attr (const struct attr *, unsigned int *, const bool);
 static void process_opt_exclude_random (const char *, const bool);
 static void parse_conf (const char *, struct conf *);
 static void assign_conf (const char *, struct conf *, const char *, char *);
 static void init_conf_vars (const struct conf *);
+static void init_opts_vars (void);
 static void print_hint (void);
 static void print_help (void);
 static void print_version (void);
@@ -319,6 +334,7 @@ static void *realloc_wrap_debug (void *, size_t, const char *, unsigned int);
 static void free_wrap (void **);
 static char *strdup_wrap (const char *, const char *, unsigned int);
 static char *str_concat_wrap (const char *, const char *, const char *, unsigned int);
+static char *expand_string (const char *);
 static bool get_bytes_size (unsigned long, struct bytes_size *);
 static char *get_file_type (mode_t);
 static bool has_color_name (const char *, const char *);
@@ -342,11 +358,7 @@ main (int argc, char **argv)
 
     const char *file = NULL;
 
-    char *conf_file;
-    uid_t uid;
-    struct passwd *passwd;
-    size_t size;
-
+    char *conf_file = NULL;
     struct conf config = { NULL, NULL, NULL, NULL };
 
     program_name = argv[0];
@@ -361,22 +373,43 @@ main (int argc, char **argv)
 
     attr[0] = '\0';
 
+    process_opts (argc, argv, &conf_file);
+
 #ifdef CONF_FILE_TEST
     conf_file = to_str (CONF_FILE_TEST);
 #elif !defined(TEST)
-    uid = getuid ();
-    errno = 0;
-    if ((passwd = getpwuid (uid)) == NULL)
+    if (conf_file == NULL)
       {
-        if (errno == 0)
-          vfprintf_diag ("password file entry for uid %lu not found", (unsigned long)uid);
-        else
-          perror ("getpwuid");
-        exit (EXIT_FAILURE);
+        uid_t uid;
+        struct passwd *passwd;
+        size_t size;
+
+        uid = getuid ();
+        errno = 0;
+        if ((passwd = getpwuid (uid)) == NULL)
+          {
+            if (errno == 0)
+              vfprintf_diag ("password file entry for uid %lu not found", (unsigned long)uid);
+            else
+              perror ("getpwuid");
+            exit (EXIT_FAILURE);
+          }
+        size = strlen (passwd->pw_dir) + 1 + strlen (CONF_FILE) + 1;
+        conf_file = xmalloc (size);
+        snprintf (conf_file, size, "%s/%s", passwd->pw_dir, CONF_FILE);
+      }
+    else
+      {
+        char *s;
+        if ((s = expand_string (conf_file)))
+          {
+            free (conf_file);
+            conf_file = s;
+          }
+        errno = 0;
+        if (access (conf_file, F_OK) == -1)
+          vfprintf_fail (formats[FMT_FILE], conf_file, strerror (errno));
       }
-    size = strlen (passwd->pw_dir) + 1 + strlen (CONF_FILE) + 1;
-    conf_file = xmalloc (size);
-    snprintf (conf_file, size, "%s/%s", passwd->pw_dir, CONF_FILE);
 #endif
 #if defined(CONF_FILE_TEST) || !defined(TEST)
     if (access (conf_file, F_OK) != -1)
@@ -387,7 +420,7 @@ main (int argc, char **argv)
 #endif
     init_conf_vars (&config);
 
-    process_opts (argc, argv);
+    init_opts_vars ();
 
     arg_cnt = argc - optind;
 
@@ -455,6 +488,10 @@ print_tstamp (FILE *log)
 }
 #endif
 
+#define DUP_CONFIG()               \
+    *conf_file = xstrdup (optarg); \
+    break;
+
 #define PRINT_HELP_EXIT() \
     print_help ();        \
     exit (EXIT_SUCCESS);
@@ -466,10 +503,10 @@ print_tstamp (FILE *log)
 extern char *optarg;
 
 static void
-process_opts (int argc, char **argv)
+process_opts (int argc, char **argv, char **conf_file)
 {
     int opt;
-    while ((opt = getopt_long (argc, argv, "hV", long_opts, NULL)) != -1)
+    while ((opt = getopt_long (argc, argv, "c:hV", long_opts, NULL)) != -1)
       {
         switch (opt)
           {
@@ -477,8 +514,8 @@ process_opts (int argc, char **argv)
               switch (opt_type)
                 {
                   case OPT_ATTR:
-                    attr[0] = '\0'; /* Clear attr string to discard values from the config file.  */
-                    process_opt_attr (optarg, true);
+                    opts_set |= OPT_ATTR_SET;
+                    opts_arg.attr = xstrdup (optarg);
                     break;
                   case OPT_CLEAN:
                     clean = true;
@@ -486,11 +523,14 @@ process_opts (int argc, char **argv)
                   case OPT_CLEAN_ALL:
                     clean_all = true;
                     break;
+                  case OPT_CONFIG:
+                    DUP_CONFIG ();
                   case OPT_EXCLUDE_RANDOM:
-                    process_opt_exclude_random (optarg, true);
+                    opts_set |= OPT_EXCLUDE_RANDOM_SET;
+                    opts_arg.exclude_random = xstrdup (optarg);
                     break;
                   case OPT_OMIT_COLOR_EMPTY:
-                    omit_color_empty = true;
+                    opts_set |= OPT_OMIT_COLOR_EMPTY_SET;
                     break;
                   case OPT_HELP:
                     PRINT_HELP_EXIT ();
@@ -500,6 +540,8 @@ process_opts (int argc, char **argv)
                     ABORT_TRACE ();
                 }
               break;
+            case 'c':
+              DUP_CONFIG ();
             case 'h':
               PRINT_HELP_EXIT ();
             case 'V':
@@ -526,7 +568,7 @@ process_opt_attr (const char *p, const bool is_opt)
     };
     unsigned int attr_types = 0;
     const char *desc_type[2] = { "--attr switch", "attr conf option" };
-    unsigned int DESC_TYPE = is_opt ? DESC_OPTION : DESC_CONF;
+    const unsigned int DESC_TYPE = is_opt ? DESC_OPTION : DESC_CONF;
 
     while (*p)
       {
@@ -604,11 +646,29 @@ process_opt_exclude_random (const char *s, const bool is_opt)
                      is_opt ? "--exlude-random switch" : "exclude-random conf option");
 }
 
+static void
+init_opts_vars (void)
+{
+    if (opts_set & OPT_ATTR_SET)
+      {
+        attr[0] = '\0'; /* Clear attr string to discard values from the config file.  */
+        process_opt_attr (opts_arg.attr, true);
+      }
+    if (opts_set & OPT_EXCLUDE_RANDOM_SET)
+      process_opt_exclude_random (opts_arg.exclude_random, true);
+    if (opts_set & OPT_OMIT_COLOR_EMPTY_SET)
+      omit_color_empty = true;
+
+    free (opts_arg.attr);
+    free (opts_arg.exclude_random);
+}
+
 #define IS_SPACE(c) ((c) == ' ' || (c) == '\t')
 
 static void
 parse_conf (const char *conf_file, struct conf *config)
 {
+    unsigned int cnt = 0;
     char line[256 + 1];
     FILE *conf;
 
@@ -620,8 +680,9 @@ parse_conf (const char *conf_file, struct conf *config)
         char *assign, *comment, *opt, *value;
         char *p;
 
+        cnt++;
         if (strlen (line) > (sizeof (line) - 2))
-          vfprintf_fail ("%s: line exceeds maximum of %u characters", conf_file, (unsigned int)(sizeof (line) - 2));
+          vfprintf_fail ("%s: line %u exceeds maximum of %u characters", conf_file, cnt, (unsigned int)(sizeof (line) - 2));
         if ((p = strrchr (line, '\n')))
           *p = '\0';
 /* NAME PARSING (start) */
@@ -743,6 +804,7 @@ print_help (void)
     };
     const struct opt_data opts_data[] = {
         { "attr",           NULL, "=ATTR1,ATTR2,..." },
+        { "config",         "c",  "=PATH"            },
         { "exclude-random", NULL, "=COLOR"           },
         { "help",           "h",  NULL               },
         { "version",        "V",  NULL               },
@@ -782,9 +844,12 @@ print_help (void)
         if (opt_data)
           {
             if (opt_data->short_opt)
-              printf ("\t\t-%s, --%s\n", opt_data->short_opt, opt->name);
+              printf ("\t\t-%s, --%s", opt_data->short_opt, opt->name);
             else
-              printf ("\t\t    --%s%s\n", opt->name, opt_data->arg);
+              printf ("\t\t    --%s", opt->name);
+            if (opt_data->arg)
+              printf ("%s", opt_data->arg);
+            printf ("\n");
           }
         else
           printf ("\t\t    --%s\n", opt->name);
@@ -1664,6 +1729,20 @@ str_concat_wrap (const char *str1, const char *str2, const char *file, unsigned
     return str;
 }
 
+static char *
+expand_string (const char *str)
+{
+    char *s = NULL;
+    wordexp_t p;
+
+    wordexp (str, &p, 0);
+    if (p.we_wordc >= 1)
+      s = xstrdup (p.we_wordv[0]);
+    wordfree (&p);
+
+    return s;
+}
+
 static bool
 get_bytes_size (unsigned long bytes, struct bytes_size *bytes_size)
 {