X-Git-Url: https://www.fleuret.org/cgi-bin/gitweb/gitweb.cgi?a=blobdiff_plain;f=selector.c;h=30f3f19779123fe224c143ee1442f6c0f790c745;hb=e7d64e4b607e8e4ca95c789df4244c583943c7d7;hp=b757357d63380a7e5ae2dc1231ea833159dae2ba;hpb=56b5c4cef39a4e3734e651331b579627f1e4ed01;p=selector.git diff --git a/selector.c b/selector.c index b757357..30f3f19 100644 --- a/selector.c +++ b/selector.c @@ -22,8 +22,12 @@ * */ -// To use it as a super-history-search for bash: -// selector -q -b -i -d -v -w -l ${HISTSIZE} <(history) +/* + + To use it as a super-history-search for bash: + selector -q -b -i -d -v -w -l ${HISTSIZE} <(history) + +*/ #define _GNU_SOURCE @@ -40,9 +44,9 @@ #define VERSION "1.0" -const int buffer_size = 4096; +#define BUFFER_SIZE 4096 -// Yeah, global variables! +/* Yeah, global variables! */ int nb_lines_max = 1000; char pattern_separator = ';'; @@ -61,33 +65,33 @@ int error_flash = 0; int attr_modeline, attr_focus_line, attr_error; -////////////////////////////////////////////////////////////////////// +/*********************************************************************/ void inject_into_tty_buffer(char *string) { struct termios oldtio, newtio; const char *k; + const char control_q = '\021'; tcgetattr(STDIN_FILENO, &oldtio); memset(&newtio, 0, sizeof(newtio)); - // Set input mode (non-canonical, *no echo*,...) + /* Set input mode (non-canonical, *no echo*,...) */ tcsetattr(STDIN_FILENO, TCSANOW, &newtio); - const char control_q = '\021'; - // Put the selected string in the tty input buffer + /* Put the selected string in the tty input buffer */ for(k = string; *k; k++) { if(add_control_qs && !(*k >= ' ' && *k <= '~')) { - // Add ^Q to quote control characters + /* Add ^Q to quote control characters */ ioctl(STDIN_FILENO, TIOCSTI, &control_q); } ioctl(STDIN_FILENO, TIOCSTI, k); } - // Restore the old settings + /* Restore the old settings */ tcsetattr(STDIN_FILENO, TCSANOW, &oldtio); } -////////////////////////////////////////////////////////////////////// +/*********************************************************************/ 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); } @@ -107,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); } @@ -122,66 +126,84 @@ 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. +/* 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 test_and_add(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 okay) + /* 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 + 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) { - // There is a string with that code - if(strcmp(new_string, strings[hash_table[code]]) == 0) { - // It is the same string, we keep a copy of the stored index - int result = hash_table[code]; - // Put the new one - hash_table[code] = new_index; - // And return the previous one + while(hash_table->entries[code] >= 0) { + /* There is a string with that code */ + 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->entries[code]; + /* Put the new one */ + 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; + /* This collision was not the same string, let's move to the next + in the table */ + 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; + /* This string was not already in there, store the index in the + table and return -1 */ + + hash_table->entries[code] = new_index; return -1; } -////////////////////////////////////////////////////////////////////// -// A matcher matches either with a collection of substrings, or with a -// regexp +/********************************************************************* + A matcher matches either with a collection of substrings, or with a + regexp */ typedef struct { regex_t preg; @@ -221,7 +243,8 @@ void free_matcher(matcher_t *matcher) { void initialize_matcher(int use_regexp, int case_sensitive, matcher_t *matcher, const char *pattern) { const char *s; - char *t; + char *t, *last_pattern_start; + int n; if(use_regexp) { matcher->nb_patterns = -1; @@ -242,8 +265,8 @@ void initialize_matcher(int use_regexp, int case_sensitive, strcpy(matcher->splitted_patterns, pattern); - int n = 0; - char *last_pattern_start = matcher->splitted_patterns; + n = 0; + last_pattern_start = matcher->splitted_patterns; for(t = matcher->splitted_patterns; n < matcher->nb_patterns; t++) { if(*t == pattern_separator || *t == '\0') { *t = '\0'; @@ -254,13 +277,13 @@ void initialize_matcher(int use_regexp, int case_sensitive, } } -////////////////////////////////////////////////////////////////////// -// Buffer edition +/********************************************************************* + Buffer edition */ void delete_char(char *buffer, int *position) { if(buffer[*position]) { int c = *position; - while(c < buffer_size && buffer[c]) { + while(c < BUFFER_SIZE && buffer[c]) { buffer[c] = buffer[c+1]; c++; } @@ -284,7 +307,7 @@ void backspace_char(char *buffer, int *position) { } void insert_char(char *buffer, int *position, char character) { - if(strlen(buffer) < buffer_size - 1) { + if(strlen(buffer) < BUFFER_SIZE - 1) { int c = *position; char t = buffer[c], u; while(t) { @@ -313,7 +336,7 @@ void kill_after_cursor(char *buffer, int *position) { buffer[*position] = '\0'; } -////////////////////////////////////////////////////////////////////// +/*********************************************************************/ int previous_visible(int current_line, int nb_lines, char **lines, matcher_t *matcher) { int line = current_line - 1; @@ -331,20 +354,20 @@ int next_visible(int current_line, int nb_lines, char **lines, matcher_t *matche return -1; } -////////////////////////////////////////////////////////////////////// +/*********************************************************************/ -// The value passed to this routine in current_focus_line is the index -// of the line we should have highlited if there was no motion and if -// it matched the matcher. So, the line actually highlighted is the -// first one matching the matcher in that order: (1) -// current_focus_line after motion, (2) the first with a greater -// index, (3) the first with a lesser index. +/* The value passed to this routine in current_focus_line is the index + of the line we should have highlighted if there was no motion and if + it matched the matcher. So, the line actually highlighted is the + first one matching the matcher in that order: (1) + current_focus_line after motion, (2) the first with a greater + index, (3) the first with a lesser index. -// The index of the line actually shown highlighted is written in -// displayed_focus_line (it can be -1) + The index of the line actually shown highlighted is written in + displayed_focus_line (it can be -1) -// If there is a motion and a line is actually shown highlighted, its -// value is written in current_focus_line. + If there is a motion and a line is actually shown highlighted, its + value is written in current_focus_line. */ void update_screen(int *current_focus_line, int *displayed_focus_line, int motion, @@ -352,23 +375,24 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, int cursor_position, char *pattern) { - char buffer[buffer_size]; + char buffer[BUFFER_SIZE]; matcher_t matcher; int k, l, m; + int console_width, console_height; + int nb_printed_lines = 0; + int cursor_x; initialize_matcher(use_regexp, case_sensitive, &matcher, pattern); - int console_width = getmaxx(stdscr); - int console_height = getmaxy(stdscr); - - // First, we find a visible line. - - int nb_printed_lines = 0; + console_width = getmaxx(stdscr); + console_height = getmaxy(stdscr); use_default_colors(); addstr("\n"); + /* First, we find a visible line. */ + if(matcher.regexp_error) { attron(attr_error); addnstr("Regexp syntax error", console_width); @@ -384,12 +408,12 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, } } - // If we found a visible line and we should move, let's move + /* If we found a visible line and we should move, let's move */ if(new_focus_line >= 0 && motion != 0) { int l = new_focus_line; if(motion > 0) { - // We want to go down, let's find the first visible line below + /* We want to go down, let's find the first visible line below */ for(m = 0; l >= 0 && m < motion; m++) { l = next_visible(l, nb_lines, lines, &matcher); if(l >= 0) { @@ -397,7 +421,7 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, } } } else { - // We want to go up, let's find the first visible line above + /* We want to go up, let's find the first visible line above */ for(m = 0; l >= 0 && m < -motion; m++) { l = previous_visible(l, nb_lines, lines, &matcher); if(l >= 0) { @@ -407,14 +431,15 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, } } - // Here new_focus_line is either a line number matching the pattern, or -1 + /* Here new_focus_line is either a line number matching the pattern, or -1 */ if(new_focus_line >= 0) { int first_line = new_focus_line, last_line = new_focus_line, nb_match = 1; - // We find the first and last line to show, so that the total of - // visible lines between them (them included) is console_height-1 + /* We find the first and last line to show, so that the total of + visible lines between them (them included) is + console_height-1 */ while(nb_match < console_height-1 && (first_line > 0 || last_line < nb_lines - 1)) { @@ -440,19 +465,19 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, } } - // Now we display them + /* Now we display them */ for(l = first_line; l <= last_line; l++) { if(match(lines[l], &matcher)) { int k = 0; - while(lines[l][k] && k < buffer_size - 2 && k < console_width - 2) { + while(lines[l][k] && k < BUFFER_SIZE - 2 && k < console_width - 2) { buffer[k] = lines[l][k]; k++; } - // We fill the rest of the line with blanks if this is the - // highlighted line + /* We fill the rest of the line with blanks if this is the + highlighted line */ if(l == new_focus_line) { while(k < console_width) { @@ -465,7 +490,7 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, clrtoeol(); - // Highlight the highlighted line ... + /* Highlight the highlighted line ... */ if(l == new_focus_line) { attron(attr_focus_line); @@ -479,8 +504,8 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, } } - // If we are on a focused line and we moved, this become the new - // focus line + /* If we are on a focused line and we moved, this become the new + focus line */ if(motion != 0) { *current_focus_line = new_focus_line; @@ -502,7 +527,7 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, clrtobot(); - // Draw the modeline + /* Draw the modeline */ move(0, 0); @@ -514,10 +539,10 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, move(0, 0); - // There must be a more elegant way of moving the cursor at a - // location met during display + /* There must be a more elegant way of moving the cursor at a + location met during display */ - int cursor_x = 0; + cursor_x = 0; if(title) { addstr(title); @@ -557,28 +582,73 @@ void update_screen(int *current_focus_line, int *displayed_focus_line, attroff(attr_modeline); - // We are done + /* We are done */ refresh(); free_matcher(&matcher); } -////////////////////////////////////////////////////////////////////// +/*********************************************************************/ + +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 */ + + if(zsh_history && *t == ':') { + while(*t && *t != ';') t++; + if(*t == ';') t++; + } + + /* Remove the bash history prefix */ + + if(bash_history) { + while(*t == ' ') t++; + while(*t >= '0' && *t <= '9') t++; + while(*t == ' ') t++; + } + + /* Check for duplicates with the hash table and insert the line in + the list if necessary */ + + if(hash_table) { + dup = add_and_get_previous_index(hash_table, t, *nb_lines, lines); + } else { + dup = -1; + } + + if(dup < 0) { + lines[*nb_lines] = (char *) malloc((strlen(t) + 1) * sizeof(char)); + strcpy(lines[*nb_lines], t); + } else { + /* The string was already in there, so we do not allocate a new + string but use the pointer to the first occurence of it */ + lines[*nb_lines] = lines[dup]; + lines[dup] = 0; + } + + (*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]; + char raw_line[BUFFER_SIZE]; + int start, end, k; + FILE *file; - FILE *file = fopen(input_filename, "r"); + 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); } - int start = 0, end = 0, k; + start = 0; + end = 0; while(*nb_lines < nb_lines_max && (end > start || !feof(file))) { int eol = start; @@ -591,13 +661,13 @@ void read_file(const char *input_filename, end -= start; eol -= start; start = 0; - end += fread(raw_line + end, sizeof(char), buffer_size - end, file); + end += fread(raw_line + end, sizeof(char), BUFFER_SIZE - end, file); while(eol < end && raw_line[eol] != '\n') eol++; } - if(eol == buffer_size) { - raw_line[buffer_size - 1] = '\0'; - fprintf(stderr, "Line too long:\n"); + if(eol == BUFFER_SIZE) { + raw_line[BUFFER_SIZE - 1] = '\0'; + fprintf(stderr, "Selector: Line too long (max is %d characters):\n", BUFFER_SIZE); fprintf(stderr, raw_line); fprintf(stderr, "\n"); exit(1); @@ -605,67 +675,40 @@ void read_file(const char *input_filename, raw_line[eol] = '\0'; - char *t = raw_line + start; - - // Remove the zsh history prefix - - if(zsh_history && *t == ':') { - while(*t && *t != ';') t++; - if(*t == ';') t++; - } - - // Remove the bash history prefix - - if(bash_history) { - while(*t == ' ') t++; - while(*t >= '0' && *t <= '9') t++; - while(*t == ' ') t++; - } - - // Check for duplicates with the hash table and insert the line - // in the list if necessary - - int dup; - - if(hash_table) { - dup = test_and_add(t, *nb_lines, lines, hash_table, hash_table_size); - } else { - dup = -1; - } - - if(dup < 0) { - lines[*nb_lines] = (char *) malloc((strlen(t) + 1) * sizeof(char)); - strcpy(lines[*nb_lines], t); - } else { - // The string was already in there, so we do not allocate a - // new string but use the pointer to the first occurence of it - lines[*nb_lines] = lines[dup]; - lines[dup] = 0; - } - - (*nb_lines)++; + store_line(hash_table, raw_line + start, + nb_lines_max, nb_lines, lines); start = eol + 1; } + + fclose(file); } -////////////////////////////////////////////////////////////////////// +/*********************************************************************/ int main(int argc, char **argv) { - if(!ttyname(STDIN_FILENO)) { - fprintf(stderr, "The standard input is not a tty.\n"); - exit(1); - } - - char input_filename[buffer_size], output_filename[buffer_size]; + char input_filename[BUFFER_SIZE], output_filename[BUFFER_SIZE]; + char pattern[BUFFER_SIZE]; int i, k, l, n; + int cursor_position; int error = 0, show_help = 0; int rest_are_files = 0; + int key; + int current_focus_line, displayed_focus_line; int color_fg_modeline, color_bg_modeline; int color_fg_highlight, color_bg_highlight; + char **lines, **labels; + int nb_lines; + hash_table_t *hash_table; + + if(!ttyname(STDIN_FILENO)) { + fprintf(stderr, "Selector: The standard input is not a tty.\n"); + exit(1); + } + color_fg_modeline = COLOR_WHITE; color_bg_modeline = COLOR_BLACK; color_fg_highlight = COLOR_BLACK; @@ -681,7 +724,7 @@ int main(int argc, char **argv) { if(strcmp(argv[i], "-o") == 0) { check_opt(argc, argv, i, 1, ""); - strncpy(output_filename, argv[i+1], buffer_size); + strncpy(output_filename, argv[i+1], BUFFER_SIZE); i += 2; } @@ -719,7 +762,7 @@ int main(int argc, char **argv) { else if(strcmp(argv[i], "-f") == 0) { check_opt(argc, argv, i, 1, ""); - strncpy(input_filename, argv[i+1], buffer_size); + strncpy(input_filename, argv[i+1], BUFFER_SIZE); i += 2; } @@ -787,7 +830,7 @@ 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; } } @@ -825,32 +868,34 @@ int main(int argc, char **argv) { exit(error); } - char **lines = (char **) malloc(nb_lines_max * sizeof(char *)); + lines = (char **) malloc(nb_lines_max * sizeof(char *)); - int nb_lines = 0; - int hash_table_size = nb_lines_max * 10; - int *hash_table = 0; + nb_lines = 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 + /* Now remove the null strings */ n = 0; for(k = 0; k < nb_lines; k++) { @@ -869,16 +914,17 @@ int main(int argc, char **argv) { } } - // Build the labels from the strings, take only the part before the - // label_separator and transform control characters to printable - // ones + /* Build the labels from the strings, take only the part before the + label_separator and transform control characters to printable + ones */ + + labels = (char **) malloc(nb_lines * sizeof(char *)); - char **labels = (char **) malloc(nb_lines * sizeof(char *)); for(l = 0; l < nb_lines; l++) { char *s, *t; + int e = 0; const char *u; t = lines[l]; - int e = 0; while(*t && *t != label_separator) { u = unctrl(*t++); e += strlen(u); @@ -893,22 +939,19 @@ int main(int argc, char **argv) { *s = '\0'; } - char pattern[buffer_size]; pattern[0] = '\0'; - int cursor_position; cursor_position = 0; - ////////////////////////////////////////////////////////////////////// - // Here we start to display with curse + /* Here we start to display with curse */ initscr(); cbreak(); noecho(); - // nonl(); + /* nonl(); */ intrflush(stdscr, FALSE); - // So that the arrow keys work + /* So that the arrow keys work */ keypad(stdscr, TRUE); attr_error = A_STANDOUT; @@ -925,7 +968,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); } @@ -940,31 +983,30 @@ int main(int argc, char **argv) { } - int key; - int current_focus_line = 0, displayed_focus_line = 0; + current_focus_line = 0; + displayed_focus_line = 0; update_screen(¤t_focus_line, &displayed_focus_line, 0, nb_lines, labels, cursor_position, pattern); do { + int motion = 0; key = getch(); - int motion = 0; - - if(key >= ' ' && key <= '~') { // Insert character + if(key >= ' ' && key <= '~') { /* Insert character */ insert_char(pattern, &cursor_position, key); } else if(key == KEY_BACKSPACE || - key == '\010' || // ^H - key == '\177') { // ^? + key == '\010' || /* ^H */ + key == '\177') { /* ^? */ backspace_char(pattern, &cursor_position); } else if(key == KEY_DC || - key == '\004') { // ^D + key == '\004') { /* ^D */ delete_char(pattern, &cursor_position); } @@ -985,53 +1027,53 @@ int main(int argc, char **argv) { } else if(key == KEY_DOWN || - key == '\016') { // ^N + key == '\016') { /* ^N */ motion = 1; } else if(key == KEY_UP || - key == '\020') { // ^P + key == '\020') { /* ^P */ motion = -1; } else if(key == KEY_LEFT || - key == '\002') { // ^B + key == '\002') { /* ^B */ if(cursor_position > 0) cursor_position--; else error_feedback(); } else if(key == KEY_RIGHT || - key == '\006') { // ^F + key == '\006') { /* ^F */ if(pattern[cursor_position]) cursor_position++; else error_feedback(); } - else if(key == '\001') { // ^A + else if(key == '\001') { /* ^A */ cursor_position = 0; } - else if(key == '\005') { // ^E + else if(key == '\005') { /* ^E */ cursor_position = strlen(pattern); } - else if(key == '\022') { // ^R + else if(key == '\022') { /* ^R */ use_regexp = !use_regexp; } - else if(key == '\011') { // ^I + else if(key == '\011') { /* ^I */ case_sensitive = !case_sensitive; } - else if(key == '\025') { // ^U + else if(key == '\025') { /* ^U */ kill_before_cursor(pattern, &cursor_position); } - else if(key == '\013') { // ^K + else if(key == '\013') { /* ^K */ kill_after_cursor(pattern, &cursor_position); } - else if(key == '\014') { // ^L - // I suspect that we may sometime mess up the display + else if(key == '\014') { /* ^L */ + /* I suspect that we may sometime mess up the display */ clear(); } @@ -1039,16 +1081,15 @@ int main(int argc, char **argv) { motion, nb_lines, labels, cursor_position, pattern); - } while(key != '\007' && // ^G - key != '\033' && // ^[ (escape) + } while(key != '\007' && /* ^G */ + key != '\033' && /* ^[ (escape) */ key != '\n' && key != KEY_ENTER); echo(); endwin(); - ////////////////////////////////////////////////////////////////////// - // Here we come back to standard display + /* Here we come back to standard display */ if((key == KEY_ENTER || key == '\n')) { @@ -1076,7 +1117,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);