/*********************************************************************/
-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';
if(n_opt + n >= argc) {
fprintf(stderr, "Selector: Missing argument for %s, expecting %s.\n",
argv[n_opt], help);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
} else error = 1;
if(error) {
- fprintf(stderr, "Selector: Value `%s' is not a positive integer.\n", string);
- exit(1);
+ fprintf(stderr,
+ "Selector: Value `%s' is not a positive integer.\n",
+ string);
+ exit(EXIT_FAILURE);
}
return result;
}
}
+/*********************************************************************/
+
/* 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. */
+/* 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 = (struct hash_table_t *) malloc(sizeof(struct hash_table_t));
hash_table->size = size;
hash_table->entries = (int *) malloc(hash_table->size * sizeof(int));
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);
}
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) {
if(use_regexp) {
matcher->nb_patterns = -1;
- matcher->regexp_error = regcomp(&matcher->preg, pattern, case_sensitive ? 0 : REG_ICASE);
+ matcher->regexp_error = regcomp(&matcher->preg, pattern,
+ case_sensitive ? 0 : REG_ICASE);
} else {
matcher->regexp_error = 0;
matcher->nb_patterns = 1;
}
}
- matcher->splitted_patterns = (char *) malloc((strlen(pattern) + 1) * sizeof(char));
- matcher->patterns = (char **) malloc(matcher->nb_patterns * sizeof(char *));
+ matcher->splitted_patterns =
+ (char *) malloc((strlen(pattern) + 1) * sizeof(char));
+
+ matcher->patterns =
+ (char **) malloc(matcher->nb_patterns * sizeof(char *));
strcpy(matcher->splitted_patterns, pattern);
/*********************************************************************/
-int previous_visible(int current_line, int nb_lines, char **lines, matcher_t *matcher) {
+int previous_visible(int current_line, int nb_lines, char **lines,
+ matcher_t *matcher) {
int line = current_line - 1;
while(line >= 0 && !match(lines[line], matcher)) line--;
return line;
}
-int next_visible(int current_line, int nb_lines, char **lines, matcher_t *matcher) {
+int next_visible(int current_line, int nb_lines, char **lines,
+ matcher_t *matcher) {
int line = current_line + 1;
while(line < nb_lines && !match(lines[line], matcher)) line++;
/*********************************************************************/
-/* 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 line highlighted is the first one matching the matcher in that
+ order: (1) current_focus_line after motion, if it does not match,
+ then (2) the first with a greater index, if none matches, then (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)
+ displayed_focus_line (it can be -1 if no line at all matches the
+ matcher)
If there is a motion and a line is actually shown highlighted, its
value is written in current_focus_line. */
use_default_colors();
+ /* Add an empty line where we will print the modeline at the end */
+
addstr("\n");
- /* First, we find a visible line. */
+ /* If the regexp is erroneous, print a message saying so */
if(matcher.regexp_error) {
attron(attr_error);
addnstr("Regexp syntax error", console_width);
attroff(attr_error);
- } else if(nb_lines > 0) {
+ }
+
+ /* Else, and we do have lines to select from, find a visible line. */
+
+ else if(nb_lines > 0) {
int new_focus_line;
if(match(lines[*current_focus_line], &matcher)) {
new_focus_line = *current_focus_line;
} else {
- new_focus_line = next_visible(*current_focus_line, nb_lines, lines, &matcher);
+ new_focus_line = next_visible(*current_focus_line, nb_lines, lines,
+ &matcher);
if(new_focus_line < 0) {
- new_focus_line = previous_visible(*current_focus_line, nb_lines, lines, &matcher);
+ new_focus_line = previous_visible(*current_focus_line, nb_lines, lines,
+ &matcher);
}
}
}
}
- /* 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;
+ int first_line = new_focus_line, last_line = new_focus_line;
+ int 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 */
- while(nb_match < console_height-1 && (first_line > 0 || last_line < nb_lines - 1)) {
+ while(nb_match < console_height-1 &&
+ (first_line > 0 || last_line < nb_lines - 1)) {
if(first_line > 0) {
first_line--;
addnstr("No selection", console_width);
attroff(attr_error);
}
- } else {
+ }
+
+ /* Else, print a message saying that there are no lines to select from */
+
+ else {
attron(attr_error);
addnstr("Empty choice", console_width);
attroff(attr_error);
addstr(" ");
}
+ /* Add a few info about the mode we are in (regexp and/or case
+ sensitive) */
+
if(use_regexp || case_sensitive) {
addstr(" [");
if(use_regexp) {
/*********************************************************************/
-void store_line(hash_table_t *hash_table,
- const char *t,
- int nb_lines_max, int *nb_lines, char **lines) {
+void store_line(struct hash_table_t *hash_table,
+ const char *new_line,
+ int *nb_lines, char **lines) {
int dup;
/* Remove the zsh history prefix */
- if(zsh_history && *t == ':') {
- while(*t && *t != ';') t++;
- if(*t == ';') t++;
+ if(zsh_history && *new_line == ':') {
+ while(*new_line && *new_line != ';') new_line++;
+ if(*new_line == ';') new_line++;
}
/* Remove the bash history prefix */
if(bash_history) {
- while(*t == ' ') t++;
- while(*t >= '0' && *t <= '9') t++;
- while(*t == ' ') t++;
+ while(*new_line == ' ') new_line++;
+ while(*new_line >= '0' && *new_line <= '9') new_line++;
+ while(*new_line == ' ') new_line++;
}
/* 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);
+ dup = add_and_get_previous_index(hash_table,
+ new_line, *nb_lines, lines);
} else {
dup = -1;
}
if(dup < 0) {
- lines[*nb_lines] = (char *) malloc((strlen(t) + 1) * sizeof(char));
- strcpy(lines[*nb_lines], t);
+ lines[*nb_lines] = (char *) 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
string but use the pointer to the first occurence of it */
(*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) {
char raw_line[BUFFER_SIZE];
- int start, end, k;
+ int start, end, eol, k;
FILE *file;
file = fopen(input_filename, "r");
if(!file) {
fprintf(stderr, "Selector: Can not open `%s'.\n", input_filename);
- exit(1);
+ exit(EXIT_FAILURE);
}
start = 0;
end = 0;
while(*nb_lines < nb_lines_max && (end > start || !feof(file))) {
- int eol = start;
+ eol = start;
+
+ /* Look for the end of a line in what is already in the buffer */
while(eol < end && raw_line[eol] != '\n') eol++;
+ /* if we did not find the of a line, move what has not been
+ processed and is in the buffer to the beginning of the buffer,
+ fill the buffer with new data from the file, and look for the
+ end of a line */
if(eol == end) {
for(k = 0; k < end - start; k++) {
raw_line[k] = raw_line[k + start];
while(eol < end && raw_line[eol] != '\n') eol++;
}
+ /* The end of the line is the buffer size, which means the line is
+ too long */
+
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, "Selector: Line too long (max is %d characters):\n",
+ 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
+ finish the string */
+
raw_line[eol] = '\0';
store_line(hash_table, raw_line + start,
- nb_lines_max, nb_lines, lines);
+ nb_lines, lines);
start = eol + 1;
}
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;
strcpy(output_filename, "");
i = 1;
- while(!error && !show_help && i < argc && argv[i][0] == '-' && !rest_are_files) {
+
+ while(!error && !show_help &&
+ i < argc &&
+ argv[i][0] == '-' && !rest_are_files) {
if(strcmp(argv[i], "-o") == 0) {
check_opt(argc, argv, i, 1, "<output filename>");
}
else if(strcmp(argv[i], "-c") == 0) {
- check_opt(argc, argv, i, 4, "<fg modeline> <bg modeline> <fg highlight> <bg highlight>");
+ check_opt(argc, argv, i, 4,
+ "<fg modeline> <bg modeline> <fg highlight> <bg highlight>");
color_fg_modeline = string_to_positive_integer(argv[i + 1]);
color_bg_modeline = string_to_positive_integer(argv[i + 2]);
color_fg_highlight = string_to_positive_integer(argv[i + 3]);
out = stderr;
}
- fprintf(out, "Selector version %s-R%s\n", VERSION, REVISION_NUMBER);
+ fprintf(out, "Selector version %s-R%s (%s)\n", VERSION, REVISION_NUMBER, UNAME);
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, "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");
int e = 0;
const char *u;
t = lines[l];
+
while(*t && *t != label_separator) {
u = unctrl(*t++);
e += strlen(u);
}
+
labels[l] = (char *) malloc((e + 1) * sizeof(char));
t = lines[l];
s = labels[l];
initscr();
cbreak();
noecho();
- /* nonl(); */
intrflush(stdscr, FALSE);
/* So that the arrow keys work */
color_bg_highlight < 0 || color_bg_highlight >= COLORS) {
echo();
endwin();
- fprintf(stderr, "Selector: Color numbers have to be between 0 and %d.\n", COLORS - 1);
- exit(1);
+ fprintf(stderr, "Selector: Color numbers have to be between 0 and %d.\n",
+ COLORS - 1);
+ exit(EXIT_FAILURE);
}
init_pair(1, color_fg_modeline, color_bg_modeline);
}
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();
}
}
if(output_to_vt_buffer && t) {
- inject_into_tty_buffer(t);
+ inject_into_tty_buffer(t, add_control_qs);
}
if(output_filename[0]) {
}
fprintf(out, "\n");
} else {
- fprintf(stderr, "Selector: Can not open %s for writing.\n", output_filename);
- exit(1);
+ fprintf(stderr,
+ "Selector: Can not open %s for writing.\n",
+ output_filename);
+ exit(EXIT_FAILURE);
}
fclose(out);
}
free(lines);
free(title);
- exit(0);
+ exit(EXIT_SUCCESS);
}