Added io-mblaze and removed io-ii.1
[iomenu.git] / buffer.c
blob4994760757fbcc2065337e43d341aec42b4dc962
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 s[LINE_SIZE];
17 Buffer *buffer = malloc(sizeof(Buffer));
18 FILE *fp = stdin;
19 int l;
21 if (!fp)
22 die("Can not open file for reading.");
24 buffer->input[0] = '\0';
25 buffer->total = buffer->matching = 1;
27 /* empty line in case no line come from stdin */
28 buffer->first = buffer->current = malloc(sizeof(Line));
29 buffer->first->content = buffer->first->comment = "";
30 buffer->first->next = buffer->first->prev = NULL;
31 buffer->last = NULL;
33 /* read the file into a doubly linked list of lines */
34 for (l = 1; fgets(s, LINE_SIZE, fp); buffer->total++, l++) {
35 buffer->last = add_line(buffer, l, s, separator, buffer->last);
37 l = buffer->last->header ? 0 : l;
40 /* prevent initial current line to be a header */
41 buffer->current = buffer->first;
42 while (buffer->current->next && buffer->current->header)
43 buffer->current = buffer->current->next;
45 return buffer;
50 * Add a line to the end of the current buffer.
52 Line *
53 add_line(Buffer *buffer, int number, char *s, char *separator, Line *prev)
55 /* allocate new line */
56 buffer->last = new_line(s, separator);
57 buffer->last->number = number;
58 buffer->last->matches = 1; /* matches by default */
59 buffer->matching++;
61 /* interlink with previous line if exists */
62 if (prev) {
63 prev->next = buffer->last;
64 buffer->last->prev = prev;
65 } else {
66 buffer->first = buffer->last;
69 return buffer->last;
74 * Parse the line content to determine if it is a header and identify the
75 * separator if any.
77 Line *
78 new_line(char *s, char *separator)
80 Line *line = malloc(sizeof(Line));
81 char *sep = separator ? strstr(s, separator) : NULL;
82 int pos = sep ? (int) (sep - s) : (int) strlen(s) - 1;
84 /* header is when separator is the first character of the line */
85 line->header = (sep == s);
87 /* strip trailing newline */
88 s[strlen(s) - 1] = '\0';
90 /* fill line->content */
91 line->content = malloc((pos + 1) * sizeof(char));
92 strncpy(line->content, s, pos);
94 /* fill line->comment */
95 line->comment = malloc((strlen(s) - pos) * sizeof(char));
96 if (sep) {
97 strcpy(line->comment, s + pos + strlen(separator));
100 /* strip trailing whitespaces from line->content */
101 for (pos--; pos > 0 && isspace(line->content[pos]); pos--)
102 line->content[pos] = '\0';
104 /* strip leading whitespaces from line->comment */
105 for (pos = 0; isspace(line->comment[pos]); pos++);
106 line->comment += pos;
108 return line;
113 * Free the buffer, also recursing the doubly linked list.
115 void
116 free_buffer(Buffer *buffer)
118 Line *next = NULL;
120 while (buffer->first) {
121 next = buffer->first->next;
123 free(buffer->first);
125 buffer->first = next;
128 free(buffer);
133 * Set the line->matching state according to the return value of match_line,
134 * and buffer->matching to number of matching candidates.
136 * The incremental parameter sets whether check already matching or
137 * non-matching lines only. This is for performance concerns.
139 void
140 filter_lines(Buffer *buffer, int inc)
142 Line *line = buffer->first;
143 char **tokv = NULL;
144 char *s, buf[sizeof buffer->input];
145 size_t n = 0, tokc = 0;
147 /* tokenize input from space characters, this comes from dmenu */
148 strcpy(buf, buffer->input);
149 for (s = strtok(buf, " "); s; s = strtok(NULL, " ")) {
150 if (++tokc > n && !(tokv = realloc(tokv, ++n * sizeof(*tokv))))
151 die("cannot realloc memory for tokv\n");
153 tokv[tokc - 1] = s;
156 /* match lines */
157 buffer->matching = 0;
158 while (line) {
159 if (buffer->input[0] && !strcmp(buffer->input, line->content)) {
160 line->matches = 1;
161 buffer->current = line;
162 } else if ((inc && line->matches) || (!inc && !line->matches)) {
163 line->matches = match_line(line, tokv, tokc);
164 buffer->matching += line->header ? 0 : line->matches;
167 line = line->next;
173 * Return whecher the line matches every string from tokv.
176 match_line(Line *line, char **tokv, size_t tokc)
178 size_t i, match = 1, offset = 0;
180 if (line->header)
181 return 1;
183 for (i = 0; i < tokc && match; i++)
184 match = !!strstr(line->content + offset, tokv[i]);
186 return match;
191 * Seek the previous matching line, or NULL if none matches.
193 Line *
194 matching_prev(Line *line)
196 while ((line = line->prev) && (!line->matches || line->header));
197 return line;
202 * Seek the next matching line, or NULL if none matches.
204 Line *
205 matching_next(Line *line)
207 while ((line = line->next) && (!line->matches || line->header));
208 return line;