Moved added io-abduco, and typo.
[iomenu.git] / buffer.c
blob567adffa84bedfd1dba2da89a931cec9a7d4493f
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 #include "main.h"
9 /*
10 * Fill the buffer apropriately with the lines and headers.
12 Buffer *
13 fill_buffer(char *separator)
15 /* fill buffer with string */
16 char string[LINE_SIZE];
17 Line *last = malloc(sizeof(Line));
18 Buffer *buffer = malloc(sizeof(Buffer));
19 FILE *fp = stdin;
21 if (!fp)
22 die("Can not open file for reading.");
24 /* empty line in case no line come from stdin */
25 last->content = last->comment = "";
26 buffer->first = buffer->current = buffer->last = last;
28 /* read the file into a doubly linked list of lines */
29 while (fgets(string, LINE_SIZE, fp)) {
30 buffer->total++;
31 last = add_line(buffer, buffer->total, string, separator, last);
34 /* prevent initial current line to be a header and set it up */
35 buffer->current = buffer->first;
36 while (buffer->current->next && buffer->current->header)
37 buffer->current = buffer->current->next;
39 return buffer;
43 void
44 free_line(Line *line)
46 line->content = NULL;
47 free(line->content);
49 line->comment = NULL;
50 free(line->comment);
52 free(line);
57 * Free every struct in the buffer, recursing the doubly linked list, then free
58 * the buffer struct.
60 void
61 free_buffer(Buffer *buffer)
63 while (buffer->first) {
64 free_line(buffer->first);
65 buffer->first = buffer->first->next;
68 free(buffer);
73 * Add a line to the end of the current buffer.
75 * This requires to create a new line with a link to the previous line
76 * and to NULL as the next line.
78 * The previous line's 'next' should be relinked to this new line.
80 * The header's last line have to point to this last line
82 Line *
83 add_line(Buffer *buffer, int number, char *string, char *separator, Line *prev)
85 /* allocate new line */
86 Line *line = malloc(sizeof(Line));
87 line = parse_line(string, separator);
88 line->next = NULL;
89 line->prev = NULL;
90 buffer->last = line;
91 line->number = number;
93 /* interlink with previous line if exists */
94 if (number == 1) {
95 buffer->first = line;
96 } else {
97 prev->next = line;
98 line->prev = prev;
101 return line;
106 * Parse the line content to determine if it is a header and identify the
107 * separator if any.
109 Line *
110 parse_line(char *s, char *separator)
112 Line *line = malloc(sizeof(Line));
113 char *sep = separator ? strstr(s, separator) : NULL;
114 int pos = sep ? (int) (sep - s) : (int) strlen(s) - 1;
116 /* header is when separator is the first character of the line */
117 line->header = (sep == s);
119 /* strip trailing newline */
120 s[strlen(s) - 1] = '\0';
122 /* fill line->content */
123 line->content = malloc((pos + 1) * sizeof(char));
124 strncpy(line->content, s, pos);
126 /* fill line->comment */
127 if (sep) {
128 line->comment = malloc((strlen(s) - pos) * sizeof(char));
129 strcpy(line->comment, s + pos + strlen(separator));
130 } else {
131 line->comment = "";
134 /* strip trailing whitespaces from line->content */
135 for (pos--; pos > 0 && isspace(line->content[pos]); pos--)
136 line->content[pos] = '\0';
138 /* strip leading whitespaces from line->comment */
139 for (pos = 0; isspace(line->comment[pos]); pos++);
140 line->comment += pos;
142 return line;
146 * Set buffer->candidates to an array of lines that match and update
147 * buffer->matching to number of matching candidates.
149 void
150 filter_lines(Buffer *buffer, Opt *opt)
152 Line * line = buffer->first;
153 buffer->matching = 0;
155 while (line) {
156 line->matches = line_match_input(line, buffer->input, opt);
157 buffer->matching += line->matches;
159 line = line->next;
165 * Check if line matches and return TRUE or FALSE
168 line_match_input(Line *line, char *input, Opt *opt)
170 return (opt->complete && !strncmp(input, line->content, strlen(input)))
171 || (!opt->complete && strstr(line->content, input))
172 || line->header
173 ? TRUE : FALSE;
178 * Seek the previous matching line, or NULL if none matches.
180 Line *
181 matching_prev(Line *line)
183 while ((line = line->prev) && (!line->matches || line->header));
184 return line;
189 * Seek the next matching line, or NULL if none matches.
191 Line *
192 matching_next(Line *line)
194 while ((line = line->next) && (!line->matches || line->header));
195 return line;