Removed the revision number.
[selector.git] / selector.c
index 0bac7b0..5c9d85f 100644 (file)
@@ -35,6 +35,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <errno.h>
 #include <ncurses.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
@@ -42,7 +43,7 @@
 #include <regex.h>
 #include <locale.h>
 
-#define VERSION "1.0"
+#define VERSION "1.0.1"
 
 #define BUFFER_SIZE 4096
 
@@ -65,9 +66,22 @@ int error_flash = 0;
 
 int attr_modeline, attr_focus_line, attr_error;
 
+/********************************************************************/
+
+/* malloc with error checking.  */
+
+void *safe_malloc(size_t n) {
+  void *p = malloc(n);
+  if (!p && n != 0) {
+    printf("Can not allocate memory: %s\n", strerror(errno));
+    exit(EXIT_FAILURE);
+  }
+  return p;
+}
+
 /*********************************************************************/
 
-void inject_into_tty_buffer(char *string) {
+void inject_into_tty_buffer(char *string, int add_control_qs) {
   struct termios oldtio, newtio;
   const char *k;
   const char control_q = '\021';
@@ -93,7 +107,7 @@ void check_opt(int argc, char **argv, int n_opt, int n, const char *help) {
   if(n_opt + n >= argc) {
     fprintf(stderr, "Selector: Missing argument for %s, expecting %s.\n",
             argv[n_opt], help);
-    exit(1);
+    exit(EXIT_FAILURE);
   }
 }
 
@@ -114,7 +128,7 @@ int string_to_positive_integer(char *string) {
     fprintf(stderr,
             "Selector: Value `%s' is not a positive integer.\n",
             string);
-    exit(1);
+    exit(EXIT_FAILURE);
   }
 
   return result;
@@ -128,25 +142,61 @@ void error_feedback() {
   }
 }
 
+void print_help(FILE *out) {
+
+  fprintf(out, "Selector version %s (%s)\n", VERSION, UNAME);
+  fprintf(out, "Written by Francois Fleuret <francois@fleuret.org>.\n");
+  fprintf(out, "\n");
+  fprintf(out, "Usage: selector [options] [<filename1> [<filename2> ...]]\n");
+  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");
+}
+
+/*********************************************************************/
+
 /* 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 {
+struct hash_table_t {
   int size;
   int *entries;
-} hash_table_t;
+};
 
-hash_table_t *new_hash_table(int size) {
+struct hash_table_t *new_hash_table(int size) {
   int k;
-  hash_table_t *hash_table;
+  struct hash_table_t *hash_table;
 
-  hash_table = (hash_table_t *) malloc(sizeof(hash_table_t));
+  hash_table = safe_malloc(sizeof(struct hash_table_t));
 
   hash_table->size = size;
-  hash_table->entries = (int *) malloc(hash_table->size * sizeof(int));
+  hash_table->entries = safe_malloc(hash_table->size * sizeof(int));
 
   for(k = 0; k < hash_table->size; k++) {
     hash_table->entries[k] = -1;
@@ -155,7 +205,7 @@ hash_table_t *new_hash_table(int size) {
   return hash_table;
 }
 
-void free_hash_table(hash_table_t *hash_table) {
+void free_hash_table(struct hash_table_t *hash_table) {
   free(hash_table->entries);
   free(hash_table);
 }
@@ -164,7 +214,7 @@ void free_hash_table(hash_table_t *hash_table) {
    string was not already in the table, returns -1. Otherwise, returns
    the previous index it had. */
 
-int add_and_get_previous_index(hash_table_t *hash_table,
+int add_and_get_previous_index(struct hash_table_t *hash_table,
                                const char *new_string, int new_index,
                                char **strings) {
 
@@ -264,10 +314,10 @@ void initialize_matcher(int use_regexp, int case_sensitive,
     }
 
     matcher->splitted_patterns =
-      (char *) malloc((strlen(pattern) + 1) * sizeof(char));
+      safe_malloc((strlen(pattern) + 1) * sizeof(char));
 
     matcher->patterns =
-      (char **) malloc(matcher->nb_patterns * sizeof(char *));
+      safe_malloc(matcher->nb_patterns * sizeof(char *));
 
     strcpy(matcher->splitted_patterns, pattern);
 
@@ -615,7 +665,7 @@ void update_screen(int *current_focus_line, int *displayed_focus_line,
 
 /*********************************************************************/
 
-void store_line(hash_table_t *hash_table,
+void store_line(struct hash_table_t *hash_table,
                 const char *new_line,
                 int *nb_lines, char **lines) {
   int dup;
@@ -646,7 +696,7 @@ void store_line(hash_table_t *hash_table,
   }
 
   if(dup < 0) {
-    lines[*nb_lines] = (char *) malloc((strlen(new_line) + 1) * sizeof(char));
+    lines[*nb_lines] = safe_malloc((strlen(new_line) + 1) * sizeof(char));
     strcpy(lines[*nb_lines], new_line);
   } else {
     /* The string was already in there, so we do not allocate a new
@@ -658,7 +708,7 @@ void store_line(hash_table_t *hash_table,
   (*nb_lines)++;
 }
 
-void read_file(hash_table_t *hash_table,
+void read_file(struct hash_table_t *hash_table,
                const char *input_filename,
                int nb_lines_max, int *nb_lines, char **lines) {
 
@@ -670,7 +720,7 @@ void read_file(hash_table_t *hash_table,
 
   if(!file) {
     fprintf(stderr, "Selector: Can not open `%s'.\n", input_filename);
-    exit(1);
+    exit(EXIT_FAILURE);
   }
 
   start = 0;
@@ -706,7 +756,7 @@ void read_file(hash_table_t *hash_table,
               BUFFER_SIZE);
       fprintf(stderr, raw_line);
       fprintf(stderr, "\n");
-      exit(1);
+      exit(EXIT_FAILURE);
     }
 
     /* If we got a line, we replace the carriage return by a \0 to
@@ -741,11 +791,11 @@ int main(int argc, char **argv) {
 
   char **lines, **labels;
   int nb_lines;
-  hash_table_t *hash_table;
+  struct hash_table_t *hash_table;
 
-  if(!ttyname(STDIN_FILENO)) {
+  if(!isatty(STDIN_FILENO)) {
     fprintf(stderr, "Selector: The standard input is not a tty.\n");
-    exit(1);
+    exit(EXIT_FAILURE);
   }
 
   color_fg_modeline  = COLOR_WHITE;
@@ -761,8 +811,8 @@ int main(int argc, char **argv) {
   i = 1;
 
   while(!error && !show_help &&
-        i < argc && argv[i][0] == '-' &&
-        !rest_are_files) {
+        i < argc &&
+        argv[i][0] == '-' && !rest_are_files) {
 
     if(strcmp(argv[i], "-o") == 0) {
       check_opt(argc, argv, i, 1, "<output filename>");
@@ -841,7 +891,7 @@ int main(int argc, char **argv) {
     else if(strcmp(argv[i], "-t") == 0) {
       check_opt(argc, argv, i, 1, "<title>");
       free(title);
-      title = (char *) malloc((strlen(argv[i+1]) + 1) * sizeof(char));
+      title = safe_malloc((strlen(argv[i+1]) + 1) * sizeof(char));
       strcpy(title, argv[i+1]);
       i += 2;
     }
@@ -879,48 +929,16 @@ int main(int argc, char **argv) {
   }
 
   if(show_help || error) {
-    FILE *out;
-    if(show_help) {
-      out = stdout;
+    if(error) {
+      print_help(stderr);
+      exit(EXIT_FAILURE);
     } 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);
+      print_help(stdout);
+      exit(EXIT_SUCCESS);
+    }
   }
 
-  lines = (char **) malloc(nb_lines_max * sizeof(char *));
+  lines = safe_malloc(nb_lines_max * sizeof(char *));
 
   nb_lines = 0;
 
@@ -970,7 +988,7 @@ int main(int argc, char **argv) {
      label_separator and transform control characters to printable
      ones */
 
-  labels = (char **) malloc(nb_lines * sizeof(char *));
+  labels = safe_malloc(nb_lines * sizeof(char *));
 
   for(l = 0; l < nb_lines; l++) {
     char *s, *t;
@@ -983,7 +1001,7 @@ int main(int argc, char **argv) {
       e += strlen(u);
     }
 
-    labels[l] = (char *) malloc((e + 1) * sizeof(char));
+    labels[l] = safe_malloc((e + 1) * sizeof(char));
     t = lines[l];
     s = labels[l];
     while(*t && *t != label_separator) {
@@ -1002,7 +1020,6 @@ int main(int argc, char **argv) {
   initscr();
   cbreak();
   noecho();
-  /* nonl(); */
   intrflush(stdscr, FALSE);
 
   /* So that the arrow keys work */
@@ -1024,7 +1041,7 @@ int main(int argc, char **argv) {
       endwin();
       fprintf(stderr, "Selector: Color numbers have to be between 0 and %d.\n",
               COLORS - 1);
-      exit(1);
+      exit(EXIT_FAILURE);
     }
 
     init_pair(1, color_fg_modeline, color_bg_modeline);
@@ -1128,7 +1145,8 @@ int main(int argc, char **argv) {
     }
 
     else if(key == '\014') { /* ^L */
-      /* I suspect that we may sometime mess up the display */
+      /* I suspect that we may sometime mess up the display, so ^L is
+         here to force a full refresh */
       clear();
     }
 
@@ -1161,7 +1179,7 @@ int main(int argc, char **argv) {
     }
 
     if(output_to_vt_buffer && t) {
-      inject_into_tty_buffer(t);
+      inject_into_tty_buffer(t, add_control_qs);
     }
 
     if(output_filename[0]) {
@@ -1175,7 +1193,7 @@ int main(int argc, char **argv) {
         fprintf(stderr,
                 "Selector: Can not open %s for writing.\n",
                 output_filename);
-        exit(1);
+        exit(EXIT_FAILURE);
       }
       fclose(out);
     }
@@ -1193,5 +1211,5 @@ int main(int argc, char **argv) {
   free(lines);
   free(title);
 
-  exit(0);
+  exit(EXIT_SUCCESS);
 }