lwl | Less with links. |
| download: http://git.y1.nz/archives/lwl.tar.gz | |
| README | Files | Log | Refs |
text.c
1 #include <ctype.h> /* isprint */
2 #include <stdlib.h> /* malloc/free */
3
4 #include "config.h"
5 #include "text.h"
6
7 const char *hex_letters = "0123456789ABCDEF";
8
9 FileContents *
10 init_contents()
11 {
12 FileContents *ret = malloc(sizeof(FileContents));
13
14 // TODO use compile-time buffers instead? Only happens once per run..
15 ret->buffer = malloc(MAX_FILE_LENGTH * sizeof(char));
16 ret->buffer[0] = '\0';
17
18 ret->lines = malloc(MAX_NEWLINES * sizeof(int));
19 ret->line_count = 0;
20 ret->lines[ret->line_count++] = 0;
21
22 ret->highlights = malloc(MAX_MARKUPS * sizeof(Markup *));
23 ret->highlight_count = 0;
24
25 ret->links = malloc(MAX_MARKUPS * sizeof(Markup *));
26 ret->link_count = 0;
27
28 return ret;
29 }
30
31 Markup *
32 create_markup(int start, int width, int color)
33 {
34 Markup *ret = malloc(sizeof(Markup));
35 ret->start = start;
36 ret->width = width;
37 ret->color = color;
38 ret->active = 0;
39 ret->data = NULL;
40 return ret;
41 }
42
43 void
44 free_markup(Markup *markup)
45 {
46 free(markup);
47 }
48
49 typedef struct _link {
50 int open_square;
51 int close_square;
52 int open_paren;
53 int close_paren;
54 } Link;
55 #define CURRENT links[link_count-1]
56
57
58 /* returns the new index of the string terminator of contents->buffer */
59 int
60 create_link(FileContents *contents, Link *l) {
61 int start = l->open_square;
62 int width = l->close_square - l->open_square + 1;
63 Markup *link = create_markup(start, width, LINK_COLOR);
64
65 /* copy the link destination into link->data */
66 // TODO only malloc as much as necessary
67 int link_length = l->close_paren - l->open_paren - 1;
68 link->data = malloc((link_length+1)*sizeof(char));
69 for (int i = 0; i < link_length; i++) {
70 link->data[i] = contents->buffer[l->open_paren + 1 + i];
71 link->data[i+1] = '\0';
72 }
73
74 contents->links[contents->link_count++] = link;
75
76 /* keep in the square brackets, write over the parens and link */
77 contents->buffer[l->open_paren] = '\0';
78 return l->open_paren;
79 }
80
81 /* process the file, but only what's independent of linewraps */
82 FileContents *
83 read_contents(FILE *fin)
84 {
85 FileContents *ret = init_contents();
86 char ch = '!', previous_ch = '!';
87 int i = 0, i0;
88
89 Link **links = malloc(1000 * sizeof(Link *));
90 int link_count = 0;
91
92 for (;;) {
93 previous_ch = ch;
94 ch = fgetc(fin);
95 if (ch == EOF) break;
96
97 if (
98 previous_ch == '\\' &&
99 (ch == '[' || ch == ']' || ch == '(' || ch == ')')
100 ) {
101 ret->buffer[i-1] = ch;
102 continue;
103 }
104
105 /* link parsing. */
106 // TODO extract this so it's more modular.
107 if (ch == '[' && previous_ch != '\\') {
108 link_count++;
109 CURRENT = malloc(sizeof(Link));
110 CURRENT->close_square =
111 CURRENT->open_paren =
112 CURRENT->close_paren = -1;
113 CURRENT->open_square = i;
114 }
115 if (link_count != 0 && ch == ']') CURRENT->close_square = i;
116 if (link_count != 0 && ch == '(') CURRENT->open_paren = i;
117 if (
118 link_count != 0 &&
119 ch == ')' &&
120 CURRENT->open_paren == CURRENT->close_square+1 &&
121 CURRENT->open_square < CURRENT->close_square
122 ) {
123 CURRENT->close_paren = i;
124 i = create_link(ret, CURRENT);
125 free(CURRENT);
126 link_count--;
127 continue;
128 }
129
130 /* replace tab chars with appropriate numbers of spaces... */
131 if (ch == '\t') {
132 int x = i - ret->lines[ret->line_count-1];
133 int spaces = 8 - (x%8);
134 for (int k = 0; k < spaces; k++) ret->buffer[i++] = ' ';
135 ret->buffer[i] = '\0';
136 continue;
137 }
138
139 if (ch == '\n')
140 ret->lines[ret->line_count++] = i+1;
141 /* FALL THROUGH */
142
143 // if (isprint(ch) || ch == '\n') {
144 ret->buffer[i++] = ch;
145 ret->buffer[i] = '\0';
146 continue;
147 // }
148
149 // TODO translate utf-8 apostrophes and double quotes and whatnot
150
151 /* for weird characters, just display them in hex + highlight. */
152 /* this way they're unambiguous, searchable, & comprehensible */
153 Markup *highlight = create_markup(i, 3, COLOR_RED);
154 highlight->active = 1; /* show it in inverse */
155 ret->highlights[ret->highlight_count++] = highlight;
156
157 ret->buffer[i++] = '.';
158 ret->buffer[i++] = hex_letters[((unsigned int) ch / 16) % 16];
159 ret->buffer[i++] = hex_letters[(unsigned int) ch % 16];
160 ret->buffer[i] = '\0';
161 }
162
163 /* set the value at line_count for calculating line lengths */
164 ret->lines[ret->line_count] = i;
165
166 return ret;
167 }
168
169 Wrap *
170 wrap_to(FileContents *contents, int width, int height)
171 {
172 Wrap *ret = malloc(sizeof(Wrap));
173
174 // TODO count exact number of lines to allocate..
175 ret->lines = malloc(3 * MAX_NEWLINES * sizeof(int));
176 ret->line_count = 0;
177 ret->width = width;
178 ret->height = height;
179
180 /* first line always starts at 0 */
181 ret->lines[ret->line_count++] = 0;
182
183 char ch, nch, nnch;
184 int i = 0; /* index in buffer */
185 int x = 0; /* horizontal position */
186 for (;;) {
187 ch = contents->buffer[i++];
188 if (ch == '\0') break;
189 nch = contents->buffer[i];
190
191 x++;
192 if ((x == width && nch != '\n') || ch == '\n') {
193 ret->lines[ret->line_count++] = i;
194 x = 0;
195 }
196 }
197
198 /* for calculating lines' lengths */
199 ret->lines[ret->line_count] = i;
200
201 return ret;
202 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.