The help is now written to stdout for -h and stderr for an error.
[selector.git] / selector.c
index 6c0f7f5..7dc1848 100644 (file)
@@ -91,7 +91,7 @@ void inject_into_tty_buffer(char *string) {
 
 void check_opt(int argc, char **argv, int n_opt, int n, const char *help) {
   if(n_opt + n >= argc) {
-    fprintf(stderr, "Missing argument for %s, expecting %s.\n",
+    fprintf(stderr, "Selector: Missing argument for %s, expecting %s.\n",
             argv[n_opt], help);
     exit(1);
   }
@@ -111,7 +111,7 @@ int string_to_positive_integer(char *string) {
   } else error = 1;
 
   if(error) {
-    fprintf(stderr, "Value `%s' is not a positive integer.\n", string);
+    fprintf(stderr, "Selector: Value `%s' is not a positive integer.\n", string);
     exit(1);
   }
 
@@ -126,62 +126,78 @@ void error_feedback() {
   }
 }
 
-/*********************************************************************
- A quick and dirty hash table
+/* A quick and dirty hash table */
+
+/* The table itself stores indexes of the strings taken in a char
+   **table. When a string is added, if it was already in the table,
+   **the new index replaces the previous one.  */
+
+typedef struct {
+  int size;
+  int *entries;
+} hash_table_t;
+
+hash_table_t *new_hash_table(int size) {
+  int k;
+  hash_table_t *hash_table;
+
+  hash_table = (hash_table_t *) malloc(sizeof(hash_table_t));
 
- The table itself stores indexes of the strings taken in a char
- **table. When a string is added, if it was already in the table, the
- new index replaces the previous one. */
+  hash_table->size = size;
+  hash_table->entries = (int *) malloc(hash_table->size * sizeof(int));
 
-int *new_hash_table(int hash_table_size) {
-  int *result, k;
-  result = (int *) malloc(hash_table_size * sizeof(int));
-  for(k = 0; k < hash_table_size; k++) {
-    result[k] = -1;
+  for(k = 0; k < hash_table->size; k++) {
+    hash_table->entries[k] = -1;
   }
-  return result;
+
+  return hash_table;
+}
+
+void free_hash_table(hash_table_t *hash_table) {
+  free(hash_table->entries);
+  free(hash_table);
 }
 
 /* Adds new_string in the table, associated to new_index. If this
    string was not already in the table, returns -1. Otherwise, returns
    the previous index it had. */
 
-int add_and_get_previous_index(const char *new_string, int new_index,
-                               char **strings,
-                               int *hash_table, int hash_table_size) {
+int add_and_get_previous_index(hash_table_t *hash_table,
+                               const char *new_string, int new_index,
+                               char **strings) {
 
   unsigned int code = 0;
   int k;
 
   /* This is my recipe. I checked, it seems to work (as long as
-     hash_table_size is not a multiple of 387433 that should be
+     hash_table->size is not a multiple of 387433 that should be
      okay) */
 
   for(k = 0; new_string[k]; k++) {
     code = code * 387433 + (unsigned int) (new_string[k]);
   }
 
-  code = code % hash_table_size;
+  code = code % hash_table->size;
 
-  while(hash_table[code] >= 0) {
+  while(hash_table->entries[code] >= 0) {
     /* There is a string with that code */
-    if(strcmp(new_string, strings[hash_table[code]]) == 0) {
+    if(strcmp(new_string, strings[hash_table->entries[code]]) == 0) {
       /* It is the same string, we keep a copy of the stored index */
-      int result = hash_table[code];
+      int result = hash_table->entries[code];
       /* Put the new one */
-      hash_table[code] = new_index;
+      hash_table->entries[code] = new_index;
       /* And return the previous one */
       return result;
     }
     /* This collision was not the same string, let's move to the next
        in the table */
-    code = (code + 1) % hash_table_size;
+    code = (code + 1) % hash_table->size;
   }
 
   /* This string was not already in there, store the index in the
      table and return -1 */
 
-  hash_table[code] = new_index;
+  hash_table->entries[code] = new_index;
   return -1;
 }
 
@@ -574,9 +590,9 @@ void update_screen(int *current_focus_line, int *displayed_focus_line,
 
 /*********************************************************************/
 
-void store_line(const char *t,
-                int nb_lines_max, int *nb_lines, char **lines,
-                int hash_table_size, int *hash_table) {
+void store_line(hash_table_t *hash_table,
+                const char *t,
+                int nb_lines_max, int *nb_lines, char **lines) {
   int dup;
 
   /* Remove the zsh history prefix */
@@ -598,7 +614,7 @@ void store_line(const char *t,
      the list if necessary */
 
   if(hash_table) {
-    dup = add_and_get_previous_index(t, *nb_lines, lines, hash_table, hash_table_size);
+    dup = add_and_get_previous_index(hash_table, t, *nb_lines, lines);
   } else {
     dup = -1;
   }
@@ -616,9 +632,9 @@ void store_line(const char *t,
   (*nb_lines)++;
 }
 
-void read_file(const char *input_filename,
-               int nb_lines_max, int *nb_lines, char **lines,
-               int hash_table_size, int *hash_table) {
+void read_file(hash_table_t *hash_table,
+               const char *input_filename,
+               int nb_lines_max, int *nb_lines, char **lines) {
 
   char raw_line[BUFFER_SIZE];
   int start, end, k;
@@ -627,7 +643,7 @@ void read_file(const char *input_filename,
   file = fopen(input_filename, "r");
 
   if(!file) {
-    fprintf(stderr, "Can not open `%s'.\n", input_filename);
+    fprintf(stderr, "Selector: Can not open `%s'.\n", input_filename);
     exit(1);
   }
 
@@ -651,7 +667,7 @@ void read_file(const char *input_filename,
 
     if(eol == BUFFER_SIZE) {
       raw_line[BUFFER_SIZE - 1] = '\0';
-      fprintf(stderr, "Line too long (max is %d characters):\n", BUFFER_SIZE);
+      fprintf(stderr, "Selector: Line too long (max is %d characters):\n", BUFFER_SIZE);
       fprintf(stderr, raw_line);
       fprintf(stderr, "\n");
       exit(1);
@@ -659,9 +675,8 @@ void read_file(const char *input_filename,
 
     raw_line[eol] = '\0';
 
-    store_line(raw_line + start,
-               nb_lines_max, nb_lines, lines,
-               hash_table_size, hash_table);
+    store_line(hash_table, raw_line + start,
+               nb_lines_max, nb_lines, lines);
 
     start = eol + 1;
   }
@@ -686,10 +701,11 @@ int main(int argc, char **argv) {
   int color_fg_highlight, color_bg_highlight;
 
   char **lines, **labels;
-  int nb_lines, hash_table_size, *hash_table;
+  int nb_lines;
+  hash_table_t *hash_table;
 
   if(!ttyname(STDIN_FILENO)) {
-    fprintf(stderr, "The standard input is not a tty.\n");
+    fprintf(stderr, "Selector: The standard input is not a tty.\n");
     exit(1);
   }
 
@@ -814,68 +830,78 @@ int main(int argc, char **argv) {
     }
 
     else {
-      fprintf(stderr, "Unknown option %s.\n", argv[i]);
+      fprintf(stderr, "Selector: Unknown option %s.\n", argv[i]);
       error = 1;
     }
   }
 
   if(show_help || error) {
-    fprintf(stderr, "Selector version %s-R%s\n", VERSION, REVISION_NUMBER);
-    fprintf(stderr, "Written by Francois Fleuret <francois@fleuret.org>.\n");
-    fprintf(stderr, "Usage: %s [options] [<filename1> [<filename2> ...]]\n", argv[0]);
-    fprintf(stderr, "\n");
-    fprintf(stderr, " -h      show this help\n");
-    fprintf(stderr, " -v      inject the selected line in the tty\n");
-    fprintf(stderr, " -w      quote control characters with ^Qs when using -v\n");
-    fprintf(stderr, " -d      remove duplicated lines\n");
-    fprintf(stderr, " -b      remove the bash history line prefix\n");
-    fprintf(stderr, " -z      remove the zsh history line prefix\n");
-    fprintf(stderr, " -i      invert the order of lines\n");
-    fprintf(stderr, " -e      start in regexp mode\n");
-    fprintf(stderr, " -a      start in case sensitive mode\n");
-    fprintf(stderr, " -m      monochrome mode\n");
-    fprintf(stderr, " -q      make a flash instead of a beep on an edition error\n");
-    fprintf(stderr, " --      all following arguments are filenames\n");
-    fprintf(stderr, " -t <title>\n");
-    fprintf(stderr, "         add a title in the modeline\n");
-    fprintf(stderr, " -c <fg modeline> <bg modeline> <fg highlight> <bg highlight>\n");
-    fprintf(stderr, "         set the display colors\n");
-    fprintf(stderr, " -o <output filename>\n");
-    fprintf(stderr, "         set a file to write the selected line to\n");
-    fprintf(stderr, " -s <pattern separator>\n");
-    fprintf(stderr, "         set the symbol to separate substrings in the pattern\n");
-    fprintf(stderr, " -x <label separator>\n");
-    fprintf(stderr, "         set the symbol to terminate the label\n");
-    fprintf(stderr, " -l <max number of lines>\n");
-    fprintf(stderr, "         set the maximum number of lines to take into account\n");
-    fprintf(stderr, "\n");
+    FILE *out;
+    if(show_help) {
+      out = stdout;
+    } else {
+      out = stderr;
+    }
+
+    fprintf(out, "Selector version %s-R%s\n", VERSION, REVISION_NUMBER);
+    fprintf(out, "Written by Francois Fleuret <francois@fleuret.org>.\n");
+    fprintf(out, "\n");
+    fprintf(out, "Usage: %s [options] [<filename1> [<filename2> ...]]\n", argv[0]);
+    fprintf(out, "\n");
+    fprintf(out, " -h      show this help\n");
+    fprintf(out, " -v      inject the selected line in the tty\n");
+    fprintf(out, " -w      quote control characters with ^Qs when using -v\n");
+    fprintf(out, " -d      remove duplicated lines\n");
+    fprintf(out, " -b      remove the bash history line prefix\n");
+    fprintf(out, " -z      remove the zsh history line prefix\n");
+    fprintf(out, " -i      invert the order of lines\n");
+    fprintf(out, " -e      start in regexp mode\n");
+    fprintf(out, " -a      start in case sensitive mode\n");
+    fprintf(out, " -m      monochrome mode\n");
+    fprintf(out, " -q      make a flash instead of a beep on an edition error\n");
+    fprintf(out, " --      all following arguments are filenames\n");
+    fprintf(out, " -t <title>\n");
+    fprintf(out, "         add a title in the modeline\n");
+    fprintf(out, " -c <fg modeline> <bg modeline> <fg highlight> <bg highlight>\n");
+    fprintf(out, "         set the display colors\n");
+    fprintf(out, " -o <output filename>\n");
+    fprintf(out, "         set a file to write the selected line to\n");
+    fprintf(out, " -s <pattern separator>\n");
+    fprintf(out, "         set the symbol to separate substrings in the pattern\n");
+    fprintf(out, " -x <label separator>\n");
+    fprintf(out, "         set the symbol to terminate the label\n");
+    fprintf(out, " -l <max number of lines>\n");
+    fprintf(out, "         set the maximum number of lines to take into account\n");
+    fprintf(out, "\n");
     exit(error);
   }
 
   lines = (char **) malloc(nb_lines_max * sizeof(char *));
 
   nb_lines = 0;
-  hash_table_size = nb_lines_max * 10;
-  hash_table = 0;
 
   if(remove_duplicates) {
-    hash_table = new_hash_table(hash_table_size);
+    hash_table = new_hash_table(nb_lines_max * 10);
+  } else {
+    hash_table = 0;
   }
 
   if(input_filename[0]) {
-    read_file(input_filename,
-              nb_lines_max, &nb_lines, lines,
-              hash_table_size, hash_table);
+    read_file(hash_table,
+              input_filename,
+              nb_lines_max, &nb_lines, lines);
   }
 
   while(i < argc) {
-    read_file(argv[i],
-              nb_lines_max, &nb_lines, lines,
-              hash_table_size, hash_table);
+    read_file(hash_table,
+              argv[i],
+              nb_lines_max, &nb_lines, lines);
     i++;
   }
 
-  free(hash_table);
+  if(hash_table) {
+    free_hash_table(hash_table);
+  }
 
   /* Now remove the null strings */
 
@@ -950,7 +976,7 @@ int main(int argc, char **argv) {
        color_bg_highlight < 0 || color_bg_highlight >= COLORS) {
       echo();
       endwin();
-      fprintf(stderr, "Color numbers have to be between 0 and %d.\n", COLORS - 1);
+      fprintf(stderr, "Selector: Color numbers have to be between 0 and %d.\n", COLORS - 1);
       exit(1);
     }
 
@@ -1099,7 +1125,7 @@ int main(int argc, char **argv) {
         }
         fprintf(out, "\n");
       } else {
-        fprintf(stderr, "Can not open %s for writing.\n", output_filename);
+        fprintf(stderr, "Selector: Can not open %s for writing.\n", output_filename);
         exit(1);
       }
       fclose(out);