Fixed segfault when only header match
[iomenu.git] / buffer.c
blobbf9caf42e77f9851c255bcc225573e0f425438a8
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 #include "main.h"
7 #include "util.h"
8 #include "buffer.h"
12 * Fill the buffer apropriately with the lines and headers.
14 Buffer *
15 fill_buffer(char *separator)
17 /* fill buffer with string */
18 char string[LINE_SIZE];
19 Line *last = malloc(sizeof(Line));
20 Buffer *buffer = malloc(sizeof(Buffer));
21 FILE *fp = stdin;
23 if (!fp) {
24 die("Can not open file for reading.");
27 /* empty line in case no line come from stdin */
28 last->content = last->comment = "";
29 buffer->first = buffer->current = buffer->last = last;
31 /* read the file into a doubly linked list of lines */
32 while (fgets(string, LINE_SIZE, fp)) {
33 buffer->total++;
34 last = add_line(buffer, buffer->total, string, separator, last);
37 /* set the buffer stats */
38 buffer->current = buffer->first;
40 /* empty line */
41 buffer->empty = malloc(sizeof(Line));
42 buffer->empty->content = buffer->empty->comment = "";
43 buffer->empty->number = buffer->empty->matches = 0;
44 buffer->empty->prev = buffer->empty->next = buffer->first;
46 return buffer;
50 * Add a line to the end of the current buffer.
52 * This requires to create a new line with a link to the previous line
53 * and to NULL as the next line.
55 * The previous line's 'next' should be relinked to this new line.
57 * The header's last line have to point to this last line
59 Line *
60 add_line(Buffer *buffer, int number, char *string, char *separator, Line *prev)
62 /* allocate new line */
63 Line *line = malloc(sizeof(Line));
64 line = parse_line(string, separator);
65 line->next = NULL;
66 line->prev = NULL;
67 buffer->last = line;
68 line->number = number;
70 /* interlink with previous line if exists */
71 if (number == 1) {
72 buffer->first = line;
73 } else {
74 prev->next = line;
75 line->prev = prev;
78 return line;
83 * Parse the line content to determine if it is a header and identify the
84 * separator if any.
86 Line *
87 parse_line(char *s, char *separator)
89 Line *line = malloc(sizeof(Line));
90 char *sep = separator ? strstr(s, separator) : NULL;
91 int pos = sep ? (int) (sep - s) : (int) strlen(s) - 1;
93 /* header is when separator is the first character of the line */
94 line->header = (sep == s);
96 /* strip trailing newline */
97 s[strlen(s) - 1] = '\0';
99 /* fill line->content */
100 line->content = malloc((pos + 1) * sizeof(char));
101 strncpy(line->content, s, pos);
103 /* fill line->comment */
104 if (sep) {
105 line->comment = malloc((strlen(s) - pos) * sizeof(char));
106 strcpy(line->comment, s + pos + strlen(separator));
107 } else {
108 line->comment = "";
111 /* strip trailing whitespaces from line->content */
112 for (pos--; pos > 0 && isspace(line->content[pos]); pos--)
113 line->content[pos] = '\0';
115 /* strip leading whitespaces from line->comment */
116 for (pos = 0; isspace(line->comment[pos]); pos++)
118 line->comment += pos;
120 return line;
124 * Set buffer->candidates to an array of lines that match and update
125 * buffer->matching to number of matching candidates.
127 void
128 filter_lines(Buffer *buffer, Opt *opt)
130 Line * line = buffer->first;
131 buffer->matching = 0;
133 while (line) {
134 line->matches = line_match_input(line, buffer->input, opt);
135 buffer->matching += line->matches;
137 line = line->next;
143 * Check if line matches and return TRUE or FALSE
146 line_match_input(Line *line, char *input, Opt *opt)
148 return (opt->complete && !strncmp(input, line->content, strlen(input)))
149 || strstr(line->content, input)
150 || line->header
151 ? TRUE : FALSE;
156 * Seek the previous matching line, or NULL if none matches.
158 Line *
159 matching_prev(Line *line)
161 while ((line = line->prev) && (!line->matches || line->header))
163 return line;
168 * Seek the next matching line, or NULL if none matches.
170 Line *
171 matching_next(Line *line)
173 while ((line = line->next) && (!line->matches || line->header))
175 return line;