Handle tab at the begining
[iomenu.git] / buffer.c
blob358ba627b68f36c5c6b2d44f8fb1c3d717c2e5b9
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 /* prevent initial current line to be a header and set it up */
38 buffer->current = buffer->first;
39 while (buffer->current->next && buffer->current->header)
40 buffer->current = buffer->current->next;
42 /* empty line */
43 buffer->empty = malloc(sizeof(Line));
44 buffer->empty->content = buffer->empty->comment = "";
45 buffer->empty->number = buffer->empty->matches = 0;
46 buffer->empty->prev = buffer->empty->next = buffer->first;
48 return buffer;
52 * Add a line to the end of the current buffer.
54 * This requires to create a new line with a link to the previous line
55 * and to NULL as the next line.
57 * The previous line's 'next' should be relinked to this new line.
59 * The header's last line have to point to this last line
61 Line *
62 add_line(Buffer *buffer, int number, char *string, char *separator, Line *prev)
64 /* allocate new line */
65 Line *line = malloc(sizeof(Line));
66 line = parse_line(string, separator);
67 line->next = NULL;
68 line->prev = NULL;
69 buffer->last = line;
70 line->number = number;
72 /* interlink with previous line if exists */
73 if (number == 1) {
74 buffer->first = line;
75 } else {
76 prev->next = line;
77 line->prev = prev;
80 return line;
85 * Parse the line content to determine if it is a header and identify the
86 * separator if any.
88 Line *
89 parse_line(char *s, char *separator)
91 Line *line = malloc(sizeof(Line));
92 char *sep = separator ? strstr(s, separator) : NULL;
93 int pos = sep ? (int) (sep - s) : (int) strlen(s) - 1;
95 /* header is when separator is the first character of the line */
96 line->header = (sep == s);
98 /* strip trailing newline */
99 s[strlen(s) - 1] = '\0';
101 /* fill line->content */
102 line->content = malloc((pos + 1) * sizeof(char));
103 strncpy(line->content, s, pos);
105 /* fill line->comment */
106 if (sep) {
107 line->comment = malloc((strlen(s) - pos) * sizeof(char));
108 strcpy(line->comment, s + pos + strlen(separator));
109 } else {
110 line->comment = "";
113 /* strip trailing whitespaces from line->content */
114 for (pos--; pos > 0 && isspace(line->content[pos]); pos--)
115 line->content[pos] = '\0';
117 /* strip leading whitespaces from line->comment */
118 for (pos = 0; isspace(line->comment[pos]); pos++)
120 line->comment += pos;
122 return line;
126 * Set buffer->candidates to an array of lines that match and update
127 * buffer->matching to number of matching candidates.
129 void
130 filter_lines(Buffer *buffer, Opt *opt)
132 Line * line = buffer->first;
133 buffer->matching = 0;
135 while (line) {
136 line->matches = line_match_input(line, buffer->input, opt);
137 buffer->matching += line->matches;
139 line = line->next;
145 * Check if line matches and return TRUE or FALSE
148 line_match_input(Line *line, char *input, Opt *opt)
150 return (opt->complete && !strncmp(input, line->content, strlen(input)))
151 || strstr(line->content, input)
152 || line->header
153 ? TRUE : FALSE;
158 * Seek the previous matching line, or NULL if none matches.
160 Line *
161 matching_prev(Line *line)
163 while ((line = line->prev) && (!line->matches || line->header))
165 return line;
170 * Seek the next matching line, or NULL if none matches.
172 Line *
173 matching_next(Line *line)
175 while ((line = line->next) && (!line->matches || line->header))
177 return line;