diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-20 02:46:48 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-20 02:46:48 +0000 |
commit | 9a7cef930f7e299c0e5d9d1ddeb3f95db6749eb7 (patch) | |
tree | b8f6595e61380091ba42740cf1ad8bb684e55336 /miscutils/less.c | |
parent | b95636c52fbb058a39548bcbc4e86456ebbd7b7b (diff) | |
download | busybox-w32-9a7cef930f7e299c0e5d9d1ddeb3f95db6749eb7.tar.gz busybox-w32-9a7cef930f7e299c0e5d9d1ddeb3f95db6749eb7.tar.bz2 busybox-w32-9a7cef930f7e299c0e5d9d1ddeb3f95db6749eb7.zip |
less: somewhat buggy applet, but nice. Muchly reduced
xstrdup'ing and memory consumption. Made linewrap saner.
regex matching code was awful - still buggy, but not as
leaky as before. Made buffer size configurable. Killed
several static and on-stack buffers. Hopefully eliminated
staircase effect on Ctrl-C (unable to reproduce).
Diffstat (limited to 'miscutils/less.c')
-rw-r--r-- | miscutils/less.c | 413 |
1 files changed, 201 insertions, 212 deletions
diff --git a/miscutils/less.c b/miscutils/less.c index 03ffd78ed..73500671d 100644 --- a/miscutils/less.c +++ b/miscutils/less.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include "busybox.h" | 33 | #include "busybox.h" |
34 | 34 | ||
35 | #ifdef CONFIG_FEATURE_LESS_REGEXP | 35 | #if ENABLE_FEATURE_LESS_REGEXP |
36 | #include "xregex.h" | 36 | #include "xregex.h" |
37 | #endif | 37 | #endif |
38 | 38 | ||
@@ -64,13 +64,12 @@ | |||
64 | /* The escape code to clear the screen */ | 64 | /* The escape code to clear the screen */ |
65 | #define CLEAR "\033[H\033[J" | 65 | #define CLEAR "\033[H\033[J" |
66 | 66 | ||
67 | /* Maximum number of lines in a file */ | 67 | #define MAXLINES CONFIG_FEATURE_LESS_MAXLINES |
68 | #define MAXLINES 10000 | ||
69 | 68 | ||
70 | static int height; | 69 | static int height; |
71 | static int width; | 70 | static int width; |
72 | static char **files; | 71 | static char **files; |
73 | static char filename[256]; | 72 | static char *filename; |
74 | static char **buffer; | 73 | static char **buffer; |
75 | static char **flines; | 74 | static char **flines; |
76 | static int current_file = 1; | 75 | static int current_file = 1; |
@@ -79,24 +78,21 @@ static int num_flines; | |||
79 | static int num_files = 1; | 78 | static int num_files = 1; |
80 | 79 | ||
81 | /* Command line options */ | 80 | /* Command line options */ |
82 | static unsigned flags; | ||
83 | #define FLAG_E 1 | 81 | #define FLAG_E 1 |
84 | #define FLAG_M (1<<1) | 82 | #define FLAG_M (1<<1) |
85 | #define FLAG_m (1<<2) | 83 | #define FLAG_m (1<<2) |
86 | #define FLAG_N (1<<3) | 84 | #define FLAG_N (1<<3) |
87 | #define FLAG_TILDE (1<<4) | 85 | #define FLAG_TILDE (1<<4) |
88 | /* hijack command line options variable for internal state vars */ | 86 | /* hijack command line options variable for internal state vars */ |
89 | #define LESS_STATE_INP_STDIN (1<<5) | 87 | #define LESS_STATE_PAST_EOF (1<<5) |
90 | #define LESS_STATE_PAST_EOF (1<<6) | 88 | #define LESS_STATE_MATCH_BACKWARDS (1<<6) |
91 | #define LESS_STATE_MATCH_BACKWARDS (1<<7) | ||
92 | /* INP_STDIN is used to change behaviour when input comes from stdin */ | ||
93 | 89 | ||
94 | #ifdef CONFIG_FEATURE_LESS_MARKS | 90 | #if ENABLE_FEATURE_LESS_MARKS |
95 | static int mark_lines[15][2]; | 91 | static int mark_lines[15][2]; |
96 | static int num_marks; | 92 | static int num_marks; |
97 | #endif | 93 | #endif |
98 | 94 | ||
99 | #ifdef CONFIG_FEATURE_LESS_REGEXP | 95 | #if ENABLE_FEATURE_LESS_REGEXP |
100 | static int match_found; | 96 | static int match_found; |
101 | static int *match_lines; | 97 | static int *match_lines; |
102 | static int match_pos; | 98 | static int match_pos; |
@@ -143,7 +139,7 @@ static int tless_getch(void) | |||
143 | them accordingly */ | 139 | them accordingly */ |
144 | 140 | ||
145 | if (input == '\033' && getc(inp) == '[') { | 141 | if (input == '\033' && getc(inp) == '[') { |
146 | unsigned int i; | 142 | unsigned i; |
147 | input = getc(inp); | 143 | input = getc(inp); |
148 | set_tty_cooked(); | 144 | set_tty_cooked(); |
149 | 145 | ||
@@ -152,13 +148,12 @@ static int tless_getch(void) | |||
152 | return 20 + i; | 148 | return 20 + i; |
153 | else if ((i = input - REAL_PAGE_UP) < 4) | 149 | else if ((i = input - REAL_PAGE_UP) < 4) |
154 | return 24 + i; | 150 | return 24 + i; |
151 | else | ||
152 | return 0; /* ?? */ | ||
155 | } | 153 | } |
156 | /* The input is a normal ASCII value */ | 154 | /* The input is a normal ASCII value */ |
157 | else { | 155 | set_tty_cooked(); |
158 | set_tty_cooked(); | 156 | return input; |
159 | return input; | ||
160 | } | ||
161 | return 0; | ||
162 | } | 157 | } |
163 | 158 | ||
164 | /* Move the cursor to a position (x,y), where (0,0) is the | 159 | /* Move the cursor to a position (x,y), where (0,0) is the |
@@ -174,51 +169,62 @@ static void clear_line(void) | |||
174 | printf("\033[K"); | 169 | printf("\033[K"); |
175 | } | 170 | } |
176 | 171 | ||
177 | /* This adds line numbers to every line, as the -N flag necessitates */ | ||
178 | static void add_linenumbers(void) | ||
179 | { | ||
180 | int i; | ||
181 | |||
182 | for (i = 0; i <= num_flines; i++) { | ||
183 | char *new = xasprintf("%5d %s", i + 1, flines[i]); | ||
184 | free(flines[i]); | ||
185 | flines[i] = new; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void data_readlines(void) | 172 | static void data_readlines(void) |
190 | { | 173 | { |
191 | int i; | 174 | unsigned i; |
192 | char current_line[256]; | 175 | unsigned n = 1; |
176 | int w = width; | ||
177 | char *last_nl = (char*)1; /* "not NULL" */ | ||
178 | char *current_line; | ||
193 | FILE *fp; | 179 | FILE *fp; |
194 | 180 | ||
195 | fp = (flags & LESS_STATE_INP_STDIN) ? stdin : xfopen(filename, "r"); | 181 | fp = filename ? xfopen(filename, "r") : stdin; |
196 | flines = NULL; | 182 | flines = NULL; |
197 | for (i = 0; (feof(fp)==0) && (i <= MAXLINES); i++) { | 183 | if (option_mask32 & FLAG_N) { |
198 | strcpy(current_line, ""); | 184 | w -= 6; |
199 | fgets(current_line, 256, fp); | 185 | if (w < 1) w = 1; /* paranoia */ |
186 | } | ||
187 | for (i = 0; !feof(fp) && i <= MAXLINES; i++) { | ||
188 | flines = xrealloc(flines, (i+1) * sizeof(char *)); | ||
189 | |||
190 | current_line = xmalloc(w); | ||
191 | again: | ||
192 | current_line[0] = '\0'; | ||
193 | fgets(current_line, w, fp); | ||
200 | if (fp != stdin) | 194 | if (fp != stdin) |
201 | die_if_ferror(fp, filename); | 195 | die_if_ferror(fp, filename); |
202 | flines = xrealloc(flines, (i+1) * sizeof(char *)); | 196 | |
203 | flines[i] = xstrdup(current_line); | 197 | /* Corner case: linewrap with only '\n' wrapping */ |
198 | /* Looks ugly on screen, so we handle it specially */ | ||
199 | if (!last_nl && current_line[0] == '\n') { | ||
200 | last_nl = (char*)1; /* "not NULL" */ | ||
201 | n++; | ||
202 | goto again; | ||
203 | } | ||
204 | last_nl = last_char_is(current_line, '\n'); | ||
205 | if (last_nl) | ||
206 | *last_nl = '\0'; | ||
207 | if (option_mask32 & FLAG_N) { | ||
208 | flines[i] = xasprintf((n <= 99999) ? "%5u %s" : "%05u %s", | ||
209 | n % 100000, current_line); | ||
210 | free(current_line); | ||
211 | if (last_nl) | ||
212 | n++; | ||
213 | } else { | ||
214 | flines[i] = xrealloc(current_line, strlen(current_line)+1); | ||
215 | } | ||
204 | } | 216 | } |
205 | num_flines = i - 2; | 217 | num_flines = i - 2; |
206 | 218 | ||
207 | /* Reset variables for a new file */ | 219 | /* Reset variables for a new file */ |
208 | 220 | ||
209 | line_pos = 0; | 221 | line_pos = 0; |
210 | flags &= ~LESS_STATE_PAST_EOF; | 222 | option_mask32 &= ~LESS_STATE_PAST_EOF; |
211 | 223 | ||
212 | fclose(fp); | 224 | fclose(fp); |
213 | |||
214 | if (inp == NULL) | ||
215 | inp = (flags & LESS_STATE_INP_STDIN) ? xfopen(CURRENT_TTY, "r") : stdin; | ||
216 | |||
217 | if (flags & FLAG_N) | ||
218 | add_linenumbers(); | ||
219 | } | 225 | } |
220 | 226 | ||
221 | #ifdef CONFIG_FEATURE_LESS_FLAGS | 227 | #if ENABLE_FEATURE_LESS_FLAGS |
222 | 228 | ||
223 | /* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes | 229 | /* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes |
224 | * on my build. */ | 230 | * on my build. */ |
@@ -232,19 +238,18 @@ static void m_status_print(void) | |||
232 | { | 238 | { |
233 | int percentage; | 239 | int percentage; |
234 | 240 | ||
235 | if (!(flags & LESS_STATE_PAST_EOF)) { | 241 | if (!(option_mask32 & LESS_STATE_PAST_EOF)) { |
236 | if (!line_pos) { | 242 | if (!line_pos) { |
237 | if (num_files > 1) | 243 | if (num_files > 1) { |
238 | printf("%s%s %s%i%s%i%s%i-%i/%i ", HIGHLIGHT, | 244 | printf("%s%s %s%i%s%i%s%i-%i/%i ", HIGHLIGHT, |
239 | filename, "(file ", current_file, " of ", num_files, ") lines ", | 245 | filename, "(file ", current_file, " of ", num_files, ") lines ", |
240 | line_pos + 1, line_pos + height - 1, num_flines + 1); | 246 | line_pos + 1, line_pos + height - 1, num_flines + 1); |
241 | else { | 247 | } else { |
242 | printf("%s%s lines %i-%i/%i ", HIGHLIGHT, | 248 | printf("%s%s lines %i-%i/%i ", HIGHLIGHT, |
243 | filename, line_pos + 1, line_pos + height - 1, | 249 | filename, line_pos + 1, line_pos + height - 1, |
244 | num_flines + 1); | 250 | num_flines + 1); |
245 | } | 251 | } |
246 | } | 252 | } else { |
247 | else { | ||
248 | printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename, | 253 | printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename, |
249 | line_pos + 1, line_pos + height - 1, num_flines + 1); | 254 | line_pos + 1, line_pos + height - 1, num_flines + 1); |
250 | } | 255 | } |
@@ -253,13 +258,11 @@ static void m_status_print(void) | |||
253 | printf("(END) %s", NORMAL); | 258 | printf("(END) %s", NORMAL); |
254 | if ((num_files > 1) && (current_file != num_files)) | 259 | if ((num_files > 1) && (current_file != num_files)) |
255 | printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL); | 260 | printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL); |
256 | } | 261 | } else { |
257 | else { | ||
258 | percentage = calc_percent(); | 262 | percentage = calc_percent(); |
259 | printf("%i%% %s", percentage, NORMAL); | 263 | printf("%i%% %s", percentage, NORMAL); |
260 | } | 264 | } |
261 | } | 265 | } else { |
262 | else { | ||
263 | printf("%s%s lines %i-%i/%i (END) ", HIGHLIGHT, filename, | 266 | printf("%s%s lines %i-%i/%i (END) ", HIGHLIGHT, filename, |
264 | line_pos + 1, num_flines + 1, num_flines + 1); | 267 | line_pos + 1, num_flines + 1, num_flines + 1); |
265 | if ((num_files > 1) && (current_file != num_files)) | 268 | if ((num_files > 1) && (current_file != num_files)) |
@@ -287,10 +290,10 @@ static void medium_status_print(void) | |||
287 | static void status_print(void) | 290 | static void status_print(void) |
288 | { | 291 | { |
289 | /* Change the status if flags have been set */ | 292 | /* Change the status if flags have been set */ |
290 | #ifdef CONFIG_FEATURE_LESS_FLAGS | 293 | #if ENABLE_FEATURE_LESS_FLAGS |
291 | if (flags & FLAG_M) | 294 | if (option_mask32 & FLAG_M) |
292 | m_status_print(); | 295 | m_status_print(); |
293 | else if (flags & FLAG_m) | 296 | else if (option_mask32 & FLAG_m) |
294 | medium_status_print(); | 297 | medium_status_print(); |
295 | /* No flags set */ | 298 | /* No flags set */ |
296 | else { | 299 | else { |
@@ -300,16 +303,14 @@ static void status_print(void) | |||
300 | if (num_files > 1) | 303 | if (num_files > 1) |
301 | printf("%s%s%i%s%i%s%s", HIGHLIGHT, "(file ", | 304 | printf("%s%s%i%s%i%s%s", HIGHLIGHT, "(file ", |
302 | current_file, " of ", num_files, ")", NORMAL); | 305 | current_file, " of ", num_files, ")", NORMAL); |
303 | } | 306 | } else if (line_pos == num_flines - height + 2) { |
304 | else if (line_pos == num_flines - height + 2) { | ||
305 | printf("%s%s %s", HIGHLIGHT, "(END)", NORMAL); | 307 | printf("%s%s %s", HIGHLIGHT, "(END)", NORMAL); |
306 | if ((num_files > 1) && (current_file != num_files)) | 308 | if ((num_files > 1) && (current_file != num_files)) |
307 | printf("%s%s%s%s", HIGHLIGHT, "- Next: ", files[current_file], NORMAL); | 309 | printf("%s%s%s%s", HIGHLIGHT, "- Next: ", files[current_file], NORMAL); |
308 | } | 310 | } else { |
309 | else { | ||
310 | putchar(':'); | 311 | putchar(':'); |
311 | } | 312 | } |
312 | #ifdef CONFIG_FEATURE_LESS_FLAGS | 313 | #if ENABLE_FEATURE_LESS_FLAGS |
313 | } | 314 | } |
314 | #endif | 315 | #endif |
315 | } | 316 | } |
@@ -322,13 +323,12 @@ static void buffer_print(void) | |||
322 | printf("%s", CLEAR); | 323 | printf("%s", CLEAR); |
323 | if (num_flines >= height - 2) { | 324 | if (num_flines >= height - 2) { |
324 | for (i = 0; i < height - 1; i++) | 325 | for (i = 0; i < height - 1; i++) |
325 | printf("%s", buffer[i]); | 326 | printf("%.*s\n", width, buffer[i]); |
326 | } | 327 | } else { |
327 | else { | ||
328 | for (i = 1; i < (height - 1 - num_flines); i++) | 328 | for (i = 1; i < (height - 1 - num_flines); i++) |
329 | putchar('\n'); | 329 | putchar('\n'); |
330 | for (i = 0; i < height - 1; i++) | 330 | for (i = 0; i < height - 1; i++) |
331 | printf("%s", buffer[i]); | 331 | printf("%.*s\n", width, buffer[i]); |
332 | } | 332 | } |
333 | 333 | ||
334 | status_print(); | 334 | status_print(); |
@@ -341,21 +341,18 @@ static void buffer_init(void) | |||
341 | 341 | ||
342 | if (buffer == NULL) { | 342 | if (buffer == NULL) { |
343 | /* malloc the number of lines needed for the buffer */ | 343 | /* malloc the number of lines needed for the buffer */ |
344 | buffer = xrealloc(buffer, height * sizeof(char *)); | 344 | buffer = xmalloc(height * sizeof(char *)); |
345 | } else { | ||
346 | for (i = 0; i < (height - 1); i++) | ||
347 | free(buffer[i]); | ||
348 | } | 345 | } |
349 | 346 | ||
350 | /* Fill the buffer until the end of the file or the | 347 | /* Fill the buffer until the end of the file or the |
351 | end of the buffer is reached */ | 348 | end of the buffer is reached */ |
352 | for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) { | 349 | for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) { |
353 | buffer[i] = xstrdup(flines[i]); | 350 | buffer[i] = flines[i]; |
354 | } | 351 | } |
355 | 352 | ||
356 | /* If the buffer still isn't full, fill it with blank lines */ | 353 | /* If the buffer still isn't full, fill it with blank lines */ |
357 | for (; i < (height - 1); i++) { | 354 | for (; i < (height - 1); i++) { |
358 | buffer[i] = xstrdup(""); | 355 | buffer[i] = ""; |
359 | } | 356 | } |
360 | } | 357 | } |
361 | 358 | ||
@@ -364,28 +361,25 @@ static void buffer_down(int nlines) | |||
364 | { | 361 | { |
365 | int i; | 362 | int i; |
366 | 363 | ||
367 | if (!(flags & LESS_STATE_PAST_EOF)) { | 364 | if (!(option_mask32 & LESS_STATE_PAST_EOF)) { |
368 | if (line_pos + (height - 3) + nlines < num_flines) { | 365 | if (line_pos + (height - 3) + nlines < num_flines) { |
369 | line_pos += nlines; | 366 | line_pos += nlines; |
370 | for (i = 0; i < (height - 1); i++) { | 367 | for (i = 0; i < (height - 1); i++) { |
371 | free(buffer[i]); | 368 | buffer[i] = flines[line_pos + i]; |
372 | buffer[i] = xstrdup(flines[line_pos + i]); | ||
373 | } | 369 | } |
374 | } | 370 | } else { |
375 | else { | ||
376 | /* As the number of lines requested was too large, we just move | 371 | /* As the number of lines requested was too large, we just move |
377 | to the end of the file */ | 372 | to the end of the file */ |
378 | while (line_pos + (height - 3) + 1 < num_flines) { | 373 | while (line_pos + (height - 3) + 1 < num_flines) { |
379 | line_pos += 1; | 374 | line_pos += 1; |
380 | for (i = 0; i < (height - 1); i++) { | 375 | for (i = 0; i < (height - 1); i++) { |
381 | free(buffer[i]); | 376 | buffer[i] = flines[line_pos + i]; |
382 | buffer[i] = xstrdup(flines[line_pos + i]); | ||
383 | } | 377 | } |
384 | } | 378 | } |
385 | } | 379 | } |
386 | 380 | ||
387 | /* We exit if the -E flag has been set */ | 381 | /* We exit if the -E flag has been set */ |
388 | if ((flags & FLAG_E) && (line_pos + (height - 2) == num_flines)) | 382 | if ((option_mask32 & FLAG_E) && (line_pos + (height - 2) == num_flines)) |
389 | tless_exit(0); | 383 | tless_exit(0); |
390 | } | 384 | } |
391 | } | 385 | } |
@@ -395,22 +389,19 @@ static void buffer_up(int nlines) | |||
395 | int i; | 389 | int i; |
396 | int tilde_line; | 390 | int tilde_line; |
397 | 391 | ||
398 | if (!(flags & LESS_STATE_PAST_EOF)) { | 392 | if (!(option_mask32 & LESS_STATE_PAST_EOF)) { |
399 | if (line_pos - nlines >= 0) { | 393 | if (line_pos - nlines >= 0) { |
400 | line_pos -= nlines; | 394 | line_pos -= nlines; |
401 | for (i = 0; i < (height - 1); i++) { | 395 | for (i = 0; i < (height - 1); i++) { |
402 | free(buffer[i]); | 396 | buffer[i] = flines[line_pos + i]; |
403 | buffer[i] = xstrdup(flines[line_pos + i]); | ||
404 | } | 397 | } |
405 | } | 398 | } else { |
406 | else { | ||
407 | /* As the requested number of lines to move was too large, we | 399 | /* As the requested number of lines to move was too large, we |
408 | move one line up at a time until we can't. */ | 400 | move one line up at a time until we can't. */ |
409 | while (line_pos != 0) { | 401 | while (line_pos != 0) { |
410 | line_pos -= 1; | 402 | line_pos -= 1; |
411 | for (i = 0; i < (height - 1); i++) { | 403 | for (i = 0; i < (height - 1); i++) { |
412 | free(buffer[i]); | 404 | buffer[i] = flines[line_pos + i]; |
413 | buffer[i] = xstrdup(flines[line_pos + i]); | ||
414 | } | 405 | } |
415 | } | 406 | } |
416 | } | 407 | } |
@@ -423,19 +414,17 @@ static void buffer_up(int nlines) | |||
423 | /* Going backwards nlines lines has taken us to a point where | 414 | /* Going backwards nlines lines has taken us to a point where |
424 | nothing is past the EOF, so we revert to normal. */ | 415 | nothing is past the EOF, so we revert to normal. */ |
425 | if (line_pos < num_flines - height + 3) { | 416 | if (line_pos < num_flines - height + 3) { |
426 | flags &= ~LESS_STATE_PAST_EOF; | 417 | option_mask32 &= ~LESS_STATE_PAST_EOF; |
427 | buffer_up(nlines); | 418 | buffer_up(nlines); |
428 | } | 419 | } else { |
429 | else { | ||
430 | /* We only move part of the buffer, as the rest | 420 | /* We only move part of the buffer, as the rest |
431 | is past the EOF */ | 421 | is past the EOF */ |
432 | for (i = 0; i < (height - 1); i++) { | 422 | for (i = 0; i < (height - 1); i++) { |
433 | free(buffer[i]); | 423 | if (i < tilde_line - nlines + 1) { |
434 | if (i < tilde_line - nlines + 1) | 424 | buffer[i] = flines[line_pos + i]; |
435 | buffer[i] = xstrdup(flines[line_pos + i]); | 425 | } else { |
436 | else { | ||
437 | if (line_pos >= num_flines - height + 2) | 426 | if (line_pos >= num_flines - height + 2) |
438 | buffer[i] = xstrdup("~\n"); | 427 | buffer[i] = "~"; |
439 | } | 428 | } |
440 | } | 429 | } |
441 | } | 430 | } |
@@ -445,7 +434,7 @@ static void buffer_up(int nlines) | |||
445 | static void buffer_line(int linenum) | 434 | static void buffer_line(int linenum) |
446 | { | 435 | { |
447 | int i; | 436 | int i; |
448 | flags &= ~LESS_STATE_PAST_EOF; | 437 | option_mask32 &= ~LESS_STATE_PAST_EOF; |
449 | 438 | ||
450 | if (linenum < 0 || linenum > num_flines) { | 439 | if (linenum < 0 || linenum > num_flines) { |
451 | clear_line(); | 440 | clear_line(); |
@@ -453,23 +442,20 @@ static void buffer_line(int linenum) | |||
453 | } | 442 | } |
454 | else if (linenum < (num_flines - height - 2)) { | 443 | else if (linenum < (num_flines - height - 2)) { |
455 | for (i = 0; i < (height - 1); i++) { | 444 | for (i = 0; i < (height - 1); i++) { |
456 | free(buffer[i]); | 445 | buffer[i] = flines[linenum + i]; |
457 | buffer[i] = xstrdup(flines[linenum + i]); | ||
458 | } | 446 | } |
459 | line_pos = linenum; | 447 | line_pos = linenum; |
460 | buffer_print(); | 448 | buffer_print(); |
461 | } | 449 | } else { |
462 | else { | ||
463 | for (i = 0; i < (height - 1); i++) { | 450 | for (i = 0; i < (height - 1); i++) { |
464 | free(buffer[i]); | ||
465 | if (linenum + i < num_flines + 2) | 451 | if (linenum + i < num_flines + 2) |
466 | buffer[i] = xstrdup(flines[linenum + i]); | 452 | buffer[i] = flines[linenum + i]; |
467 | else | 453 | else |
468 | buffer[i] = xstrdup((flags & FLAG_TILDE) ? "\n" : "~\n"); | 454 | buffer[i] = (option_mask32 & FLAG_TILDE) ? "" : "~"; |
469 | } | 455 | } |
470 | line_pos = linenum; | 456 | line_pos = linenum; |
471 | /* Set past_eof so buffer_down and buffer_up act differently */ | 457 | /* Set past_eof so buffer_down and buffer_up act differently */ |
472 | flags |= LESS_STATE_PAST_EOF; | 458 | option_mask32 |= LESS_STATE_PAST_EOF; |
473 | buffer_print(); | 459 | buffer_print(); |
474 | } | 460 | } |
475 | } | 461 | } |
@@ -490,22 +476,13 @@ static void reinitialise(void) | |||
490 | 476 | ||
491 | static void examine_file(void) | 477 | static void examine_file(void) |
492 | { | 478 | { |
493 | int newline_offset; | ||
494 | |||
495 | clear_line(); | 479 | clear_line(); |
496 | printf("Examine: "); | 480 | printf("Examine: "); |
497 | fgets(filename, 256, inp); | 481 | free(filename); |
498 | 482 | filename = xmalloc_getline(inp); | |
499 | /* As fgets adds a newline to the end of an input string, we | 483 | files[num_files] = filename; |
500 | need to remove it */ | ||
501 | newline_offset = strlen(filename) - 1; | ||
502 | filename[newline_offset] = '\0'; | ||
503 | |||
504 | files[num_files] = xstrdup(filename); | ||
505 | current_file = num_files + 1; | 484 | current_file = num_files + 1; |
506 | num_files++; | 485 | num_files++; |
507 | |||
508 | flags &= ~LESS_STATE_INP_STDIN; | ||
509 | reinitialise(); | 486 | reinitialise(); |
510 | } | 487 | } |
511 | 488 | ||
@@ -518,10 +495,10 @@ static void change_file(int direction) | |||
518 | { | 495 | { |
519 | if (current_file != ((direction > 0) ? num_files : 1)) { | 496 | if (current_file != ((direction > 0) ? num_files : 1)) { |
520 | current_file = direction ? current_file + direction : 1; | 497 | current_file = direction ? current_file + direction : 1; |
521 | strcpy(filename, files[current_file - 1]); | 498 | free(filename); |
499 | filename = xstrdup(files[current_file - 1]); | ||
522 | reinitialise(); | 500 | reinitialise(); |
523 | } | 501 | } else { |
524 | else { | ||
525 | clear_line(); | 502 | clear_line(); |
526 | printf("%s%s%s", HIGHLIGHT, (direction > 0) ? "No next file" : "No previous file", NORMAL); | 503 | printf("%s%s%s", HIGHLIGHT, (direction > 0) ? "No next file" : "No previous file", NORMAL); |
527 | } | 504 | } |
@@ -537,8 +514,7 @@ static void remove_current_file(void) | |||
537 | files[i - 2] = files[i - 1]; | 514 | files[i - 2] = files[i - 1]; |
538 | num_files--; | 515 | num_files--; |
539 | buffer_print(); | 516 | buffer_print(); |
540 | } | 517 | } else { |
541 | else { | ||
542 | change_file(1); | 518 | change_file(1); |
543 | for (i = 2; i <= num_files; i++) | 519 | for (i = 2; i <= num_files; i++) |
544 | files[i - 2] = files[i - 1]; | 520 | files[i - 2] = files[i - 1]; |
@@ -564,7 +540,7 @@ static void colon_process(void) | |||
564 | case 'e': | 540 | case 'e': |
565 | examine_file(); | 541 | examine_file(); |
566 | break; | 542 | break; |
567 | #ifdef CONFIG_FEATURE_LESS_FLAGS | 543 | #if ENABLE_FEATURE_LESS_FLAGS |
568 | case 'f': | 544 | case 'f': |
569 | clear_line(); | 545 | clear_line(); |
570 | m_status_print(); | 546 | m_status_print(); |
@@ -587,7 +563,7 @@ static void colon_process(void) | |||
587 | } | 563 | } |
588 | } | 564 | } |
589 | 565 | ||
590 | #ifdef CONFIG_FEATURE_LESS_REGEXP | 566 | #if ENABLE_FEATURE_LESS_REGEXP |
591 | /* The below two regular expression handler functions NEED development. */ | 567 | /* The below two regular expression handler functions NEED development. */ |
592 | 568 | ||
593 | /* Get a regular expression from the user, and then go through the current | 569 | /* Get a regular expression from the user, and then go through the current |
@@ -595,48 +571,50 @@ static void colon_process(void) | |||
595 | 571 | ||
596 | static char *process_regex_on_line(char *line, regex_t *pattern, int action) | 572 | static char *process_regex_on_line(char *line, regex_t *pattern, int action) |
597 | { | 573 | { |
574 | /* UNTESTED. LOOKED BUGGY AND LEAKY AS HELL. */ | ||
575 | /* FIXED. NEED TESTING. */ | ||
576 | /* 'line' should be either returned or free()ed */ | ||
577 | |||
598 | /* This function takes the regex and applies it to the line. | 578 | /* This function takes the regex and applies it to the line. |
599 | Each part of the line that matches has the HIGHLIGHT | 579 | Each part of the line that matches has the HIGHLIGHT |
600 | and NORMAL escape sequences placed around it by | 580 | and NORMAL escape sequences placed around it by |
601 | insert_highlights if action = 1, or has the escape sequences | 581 | insert_highlights if action = 1, or has the escape sequences |
602 | removed if action = 0, and then the line is returned. */ | 582 | removed if action = 0, and then the line is returned. */ |
603 | int match_status; | 583 | int match_status; |
604 | char *line2 = xmalloc((sizeof(char) * (strlen(line) + 1)) + 64); | 584 | char *line2 = line; |
605 | char *growline = ""; | 585 | char *growline = xstrdup(""); |
586 | char *ng; | ||
606 | regmatch_t match_structs; | 587 | regmatch_t match_structs; |
607 | 588 | ||
608 | line2 = xstrdup(line); | ||
609 | |||
610 | match_found = 0; | 589 | match_found = 0; |
611 | match_status = regexec(pattern, line2, 1, &match_structs, 0); | 590 | match_status = regexec(pattern, line2, 1, &match_structs, 0); |
612 | 591 | ||
613 | while (match_status == 0) { | 592 | while (match_status == 0) { |
614 | if (match_found == 0) | 593 | match_found = 1; |
615 | match_found = 1; | ||
616 | |||
617 | if (action) { | 594 | if (action) { |
618 | growline = xasprintf("%s%.*s%s%.*s%s", growline, | 595 | ng = xasprintf("%s%.*s%s%.*s%s", growline, |
619 | match_structs.rm_so, line2, HIGHLIGHT, | 596 | match_structs.rm_so, line2, HIGHLIGHT, |
620 | match_structs.rm_eo - match_structs.rm_so, | 597 | match_structs.rm_eo - match_structs.rm_so, |
621 | line2 + match_structs.rm_so, NORMAL); | 598 | line2 + match_structs.rm_so, NORMAL); |
622 | } | 599 | } else { |
623 | else { | 600 | ng = xasprintf("%s%.*s%.*s", growline, |
624 | growline = xasprintf("%s%.*s%.*s", growline, | ||
625 | match_structs.rm_so - 4, line2, | 601 | match_structs.rm_so - 4, line2, |
626 | match_structs.rm_eo - match_structs.rm_so, | 602 | match_structs.rm_eo - match_structs.rm_so, |
627 | line2 + match_structs.rm_so); | 603 | line2 + match_structs.rm_so); |
628 | } | 604 | } |
629 | 605 | free(growline); growline = ng; | |
630 | line2 += match_structs.rm_eo; | 606 | line2 += match_structs.rm_eo; |
631 | match_status = regexec(pattern, line2, 1, &match_structs, REG_NOTBOL); | 607 | match_status = regexec(pattern, line2, 1, &match_structs, REG_NOTBOL); |
632 | } | 608 | } |
633 | 609 | ||
634 | growline = xasprintf("%s%s", growline, line2); | 610 | if (match_found) { |
635 | 611 | ng = xasprintf("%s%s", growline, line2); | |
636 | return (match_found ? growline : line); | 612 | free(line); |
637 | 613 | } else { | |
614 | ng = line; | ||
615 | } | ||
638 | free(growline); | 616 | free(growline); |
639 | free(line2); | 617 | return ng; |
640 | } | 618 | } |
641 | 619 | ||
642 | static void goto_match(int match) | 620 | static void goto_match(int match) |
@@ -651,35 +629,33 @@ static void goto_match(int match) | |||
651 | 629 | ||
652 | static void regex_process(void) | 630 | static void regex_process(void) |
653 | { | 631 | { |
654 | char uncomp_regex[100]; | 632 | char *uncomp_regex; |
655 | char *current_line; | ||
656 | int i; | 633 | int i; |
657 | int j = 0; | 634 | int j = 0; |
658 | regex_t pattern; | 635 | regex_t pattern; |
636 | |||
659 | /* Get the uncompiled regular expression from the user */ | 637 | /* Get the uncompiled regular expression from the user */ |
660 | clear_line(); | 638 | clear_line(); |
661 | putchar((flags & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/'); | 639 | putchar((option_mask32 & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/'); |
662 | uncomp_regex[0] = 0; | 640 | uncomp_regex = xmalloc_getline(inp); |
663 | fgets(uncomp_regex, sizeof(uncomp_regex), inp); | 641 | if (!uncomp_regex || !uncomp_regex[0]) { |
664 | 642 | free(uncomp_regex); | |
665 | if (strlen(uncomp_regex) == 1) { | ||
666 | if (num_matches) | 643 | if (num_matches) |
667 | goto_match((flags & LESS_STATE_MATCH_BACKWARDS) | 644 | goto_match((option_mask32 & LESS_STATE_MATCH_BACKWARDS) |
668 | ? match_pos - 1 : match_pos + 1); | 645 | ? match_pos - 1 : match_pos + 1); |
669 | else | 646 | else |
670 | buffer_print(); | 647 | buffer_print(); |
671 | return; | 648 | return; |
672 | } | 649 | } |
673 | uncomp_regex[strlen(uncomp_regex) - 1] = '\0'; | ||
674 | 650 | ||
675 | /* Compile the regex and check for errors */ | 651 | /* Compile the regex and check for errors */ |
676 | xregcomp(&pattern, uncomp_regex, 0); | 652 | xregcomp(&pattern, uncomp_regex, 0); |
653 | free(uncomp_regex); | ||
677 | 654 | ||
678 | if (num_matches) { | 655 | if (num_matches) { |
679 | /* Get rid of all the highlights we added previously */ | 656 | /* Get rid of all the highlights we added previously */ |
680 | for (i = 0; i <= num_flines; i++) { | 657 | for (i = 0; i <= num_flines; i++) { |
681 | current_line = process_regex_on_line(flines[i], &old_pattern, 0); | 658 | flines[i] = process_regex_on_line(flines[i], &old_pattern, 0); |
682 | flines[i] = xstrdup(current_line); | ||
683 | } | 659 | } |
684 | } | 660 | } |
685 | old_pattern = pattern; | 661 | old_pattern = pattern; |
@@ -692,8 +668,7 @@ static void regex_process(void) | |||
692 | match_found = 0; | 668 | match_found = 0; |
693 | /* Run the regex on each line of the current file here */ | 669 | /* Run the regex on each line of the current file here */ |
694 | for (i = 0; i <= num_flines; i++) { | 670 | for (i = 0; i <= num_flines; i++) { |
695 | current_line = process_regex_on_line(flines[i], &pattern, 1); | 671 | flines[i] = process_regex_on_line(flines[i], &pattern, 1); |
696 | flines[i] = xstrdup(current_line); | ||
697 | if (match_found) { | 672 | if (match_found) { |
698 | match_lines = xrealloc(match_lines, (j + 1) * sizeof(int)); | 673 | match_lines = xrealloc(match_lines, (j + 1) * sizeof(int)); |
699 | match_lines[j] = i; | 674 | match_lines[j] = i; |
@@ -703,7 +678,7 @@ static void regex_process(void) | |||
703 | 678 | ||
704 | num_matches = j; | 679 | num_matches = j; |
705 | if ((match_lines[0] != -1) && (num_flines > height - 2)) { | 680 | if ((match_lines[0] != -1) && (num_flines > height - 2)) { |
706 | if (flags & LESS_STATE_MATCH_BACKWARDS) { | 681 | if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) { |
707 | for (i = 0; i < num_matches; i++) { | 682 | for (i = 0; i < num_matches; i++) { |
708 | if (match_lines[i] > line_pos) { | 683 | if (match_lines[i] > line_pos) { |
709 | match_pos = i - 1; | 684 | match_pos = i - 1; |
@@ -711,11 +686,9 @@ static void regex_process(void) | |||
711 | break; | 686 | break; |
712 | } | 687 | } |
713 | } | 688 | } |
714 | } | 689 | } else |
715 | else | ||
716 | buffer_line(match_lines[0]); | 690 | buffer_line(match_lines[0]); |
717 | } | 691 | } else |
718 | else | ||
719 | buffer_init(); | 692 | buffer_init(); |
720 | } | 693 | } |
721 | #endif | 694 | #endif |
@@ -724,9 +697,8 @@ static void number_process(int first_digit) | |||
724 | { | 697 | { |
725 | int i = 1; | 698 | int i = 1; |
726 | int num; | 699 | int num; |
727 | char num_input[80]; | 700 | char num_input[sizeof(int)*4]; /* more than enough */ |
728 | char keypress; | 701 | char keypress; |
729 | char *endptr; | ||
730 | 702 | ||
731 | num_input[0] = first_digit; | 703 | num_input[0] = first_digit; |
732 | 704 | ||
@@ -734,8 +706,11 @@ static void number_process(int first_digit) | |||
734 | clear_line(); | 706 | clear_line(); |
735 | printf(":%c", first_digit); | 707 | printf(":%c", first_digit); |
736 | 708 | ||
737 | /* Receive input until a letter is given (max 80 chars)*/ | 709 | /* Receive input until a letter is given */ |
738 | while((i < 80) && (num_input[i] = tless_getch()) && isdigit(num_input[i])) { | 710 | while (i < sizeof(num_input)-1) { |
711 | num_input[i] = tless_getch(); | ||
712 | if (!num_input[i] || !isdigit(num_input[i])) | ||
713 | break; | ||
739 | putchar(num_input[i]); | 714 | putchar(num_input[i]); |
740 | i++; | 715 | i++; |
741 | } | 716 | } |
@@ -743,8 +718,9 @@ static void number_process(int first_digit) | |||
743 | /* Take the final letter out of the digits string */ | 718 | /* Take the final letter out of the digits string */ |
744 | keypress = num_input[i]; | 719 | keypress = num_input[i]; |
745 | num_input[i] = '\0'; | 720 | num_input[i] = '\0'; |
746 | num = strtol(num_input, &endptr, 10); | 721 | num = bb_strtou(num_input, NULL, 10); |
747 | if (endptr==num_input || *endptr!='\0' || num < 1 || num > MAXLINES) { | 722 | /* on format error, num == -1 */ |
723 | if (num < 1 || num > MAXLINES) { | ||
748 | buffer_print(); | 724 | buffer_print(); |
749 | return; | 725 | return; |
750 | } | 726 | } |
@@ -764,16 +740,16 @@ static void number_process(int first_digit) | |||
764 | case 'p': case '%': | 740 | case 'p': case '%': |
765 | buffer_line(((num / 100) * num_flines) - 1); | 741 | buffer_line(((num / 100) * num_flines) - 1); |
766 | break; | 742 | break; |
767 | #ifdef CONFIG_FEATURE_LESS_REGEXP | 743 | #if ENABLE_FEATURE_LESS_REGEXP |
768 | case 'n': | 744 | case 'n': |
769 | goto_match(match_pos + num); | 745 | goto_match(match_pos + num); |
770 | break; | 746 | break; |
771 | case '/': | 747 | case '/': |
772 | flags &= ~LESS_STATE_MATCH_BACKWARDS; | 748 | option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS; |
773 | regex_process(); | 749 | regex_process(); |
774 | break; | 750 | break; |
775 | case '?': | 751 | case '?': |
776 | flags |= LESS_STATE_MATCH_BACKWARDS; | 752 | option_mask32 |= LESS_STATE_MATCH_BACKWARDS; |
777 | regex_process(); | 753 | regex_process(); |
778 | break; | 754 | break; |
779 | #endif | 755 | #endif |
@@ -782,7 +758,7 @@ static void number_process(int first_digit) | |||
782 | } | 758 | } |
783 | } | 759 | } |
784 | 760 | ||
785 | #ifdef CONFIG_FEATURE_LESS_FLAGCS | 761 | #if ENABLE_FEATURE_LESS_FLAGCS |
786 | static void flag_change(void) | 762 | static void flag_change(void) |
787 | { | 763 | { |
788 | int keypress; | 764 | int keypress; |
@@ -793,16 +769,16 @@ static void flag_change(void) | |||
793 | 769 | ||
794 | switch (keypress) { | 770 | switch (keypress) { |
795 | case 'M': | 771 | case 'M': |
796 | flags ^= FLAG_M; | 772 | option_mask32 ^= FLAG_M; |
797 | break; | 773 | break; |
798 | case 'm': | 774 | case 'm': |
799 | flags ^= FLAG_m; | 775 | option_mask32 ^= FLAG_m; |
800 | break; | 776 | break; |
801 | case 'E': | 777 | case 'E': |
802 | flags ^= FLAG_E; | 778 | option_mask32 ^= FLAG_E; |
803 | break; | 779 | break; |
804 | case '~': | 780 | case '~': |
805 | flags ^= FLAG_TILDE; | 781 | option_mask32 ^= FLAG_TILDE; |
806 | break; | 782 | break; |
807 | default: | 783 | default: |
808 | break; | 784 | break; |
@@ -820,19 +796,19 @@ static void show_flag_status(void) | |||
820 | 796 | ||
821 | switch (keypress) { | 797 | switch (keypress) { |
822 | case 'M': | 798 | case 'M': |
823 | flag_val = flags & FLAG_M; | 799 | flag_val = option_mask32 & FLAG_M; |
824 | break; | 800 | break; |
825 | case 'm': | 801 | case 'm': |
826 | flag_val = flags & FLAG_m; | 802 | flag_val = option_mask32 & FLAG_m; |
827 | break; | 803 | break; |
828 | case '~': | 804 | case '~': |
829 | flag_val = flags & FLAG_TILDE; | 805 | flag_val = option_mask32 & FLAG_TILDE; |
830 | break; | 806 | break; |
831 | case 'N': | 807 | case 'N': |
832 | flag_val = flags & FLAG_N; | 808 | flag_val = option_mask32 & FLAG_N; |
833 | break; | 809 | break; |
834 | case 'E': | 810 | case 'E': |
835 | flag_val = flags & FLAG_E; | 811 | flag_val = option_mask32 & FLAG_E; |
836 | break; | 812 | break; |
837 | default: | 813 | default: |
838 | flag_val = 0; | 814 | flag_val = 0; |
@@ -855,26 +831,31 @@ static void full_repaint(void) | |||
855 | 831 | ||
856 | static void save_input_to_file(void) | 832 | static void save_input_to_file(void) |
857 | { | 833 | { |
858 | char current_line[256]; | 834 | char *current_line; |
859 | int i; | 835 | int i; |
860 | FILE *fp; | 836 | FILE *fp; |
861 | 837 | ||
862 | clear_line(); | 838 | clear_line(); |
863 | printf("Log file: "); | 839 | printf("Log file: "); |
864 | fgets(current_line, 256, inp); | 840 | current_line = xmalloc_getline(inp); |
865 | current_line[strlen(current_line) - 1] = '\0'; | 841 | if (strlen(current_line) > 0) { |
866 | if (strlen(current_line) > 1) { | 842 | fp = fopen(current_line, "w"); |
867 | fp = xfopen(current_line, "w"); | 843 | free(current_line); |
844 | if (!fp) { | ||
845 | printf("%s%s%s", HIGHLIGHT, "Error opening log file", NORMAL); | ||
846 | return; | ||
847 | } | ||
868 | for (i = 0; i < num_flines; i++) | 848 | for (i = 0; i < num_flines; i++) |
869 | fprintf(fp, "%s", flines[i]); | 849 | fprintf(fp, "%s\n", flines[i]); |
870 | fclose(fp); | 850 | fclose(fp); |
871 | buffer_print(); | 851 | buffer_print(); |
852 | return; | ||
872 | } | 853 | } |
873 | else | 854 | free(current_line); |
874 | printf("%s%s%s", HIGHLIGHT, "No log file", NORMAL); | 855 | printf("%s%s%s", HIGHLIGHT, "No log file", NORMAL); |
875 | } | 856 | } |
876 | 857 | ||
877 | #ifdef CONFIG_FEATURE_LESS_MARKS | 858 | #if ENABLE_FEATURE_LESS_MARKS |
878 | static void add_mark(void) | 859 | static void add_mark(void) |
879 | { | 860 | { |
880 | int letter; | 861 | int letter; |
@@ -892,8 +873,7 @@ static void add_mark(void) | |||
892 | mark_lines[num_marks][0] = letter; | 873 | mark_lines[num_marks][0] = letter; |
893 | mark_lines[num_marks][1] = line_pos; | 874 | mark_lines[num_marks][1] = line_pos; |
894 | num_marks++; | 875 | num_marks++; |
895 | } | 876 | } else { |
896 | else { | ||
897 | clear_line(); | 877 | clear_line(); |
898 | printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL); | 878 | printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL); |
899 | } | 879 | } |
@@ -917,14 +897,13 @@ static void goto_mark(void) | |||
917 | } | 897 | } |
918 | if ((num_marks == 14) && (letter != mark_lines[14][0])) | 898 | if ((num_marks == 14) && (letter != mark_lines[14][0])) |
919 | printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL); | 899 | printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL); |
920 | } | 900 | } else |
921 | else | ||
922 | printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL); | 901 | printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL); |
923 | } | 902 | } |
924 | #endif | 903 | #endif |
925 | 904 | ||
926 | 905 | ||
927 | #ifdef CONFIG_FEATURE_LESS_BRACKETS | 906 | #if ENABLE_FEATURE_LESS_BRACKETS |
928 | 907 | ||
929 | static char opp_bracket(char bracket) | 908 | static char opp_bracket(char bracket) |
930 | { | 909 | { |
@@ -977,8 +956,7 @@ static void match_left_bracket(char bracket) | |||
977 | printf("%s%s%s", HIGHLIGHT, "No bracket in bottom line", NORMAL); | 956 | printf("%s%s%s", HIGHLIGHT, "No bracket in bottom line", NORMAL); |
978 | printf("%s", flines[line_pos + height]); | 957 | printf("%s", flines[line_pos + height]); |
979 | sleep(4); | 958 | sleep(4); |
980 | } | 959 | } else { |
981 | else { | ||
982 | for (i = line_pos + height - 2; i >= 0; i--) { | 960 | for (i = line_pos + height - 2; i >= 0; i--) { |
983 | if (strchr(flines[i], opp_bracket(bracket)) != NULL) { | 961 | if (strchr(flines[i], opp_bracket(bracket)) != NULL) { |
984 | bracket_line = i; | 962 | bracket_line = i; |
@@ -993,7 +971,7 @@ static void match_left_bracket(char bracket) | |||
993 | } | 971 | } |
994 | } | 972 | } |
995 | 973 | ||
996 | #endif /* CONFIG_FEATURE_LESS_BRACKETS */ | 974 | #endif /* FEATURE_LESS_BRACKETS */ |
997 | 975 | ||
998 | static void keypress_process(int keypress) | 976 | static void keypress_process(int keypress) |
999 | { | 977 | { |
@@ -1031,7 +1009,7 @@ static void keypress_process(int keypress) | |||
1031 | case 'q': case 'Q': | 1009 | case 'q': case 'Q': |
1032 | tless_exit(0); | 1010 | tless_exit(0); |
1033 | break; | 1011 | break; |
1034 | #ifdef CONFIG_FEATURE_LESS_MARKS | 1012 | #if ENABLE_FEATURE_LESS_MARKS |
1035 | case 'm': | 1013 | case 'm': |
1036 | add_mark(); | 1014 | add_mark(); |
1037 | buffer_print(); | 1015 | buffer_print(); |
@@ -1048,21 +1026,20 @@ static void keypress_process(int keypress) | |||
1048 | full_repaint(); | 1026 | full_repaint(); |
1049 | break; | 1027 | break; |
1050 | case 's': | 1028 | case 's': |
1051 | if (flags & LESS_STATE_INP_STDIN) | 1029 | save_input_to_file(); |
1052 | save_input_to_file(); | ||
1053 | break; | 1030 | break; |
1054 | case 'E': | 1031 | case 'E': |
1055 | examine_file(); | 1032 | examine_file(); |
1056 | break; | 1033 | break; |
1057 | #ifdef CONFIG_FEATURE_LESS_FLAGS | 1034 | #if ENABLE_FEATURE_LESS_FLAGS |
1058 | case '=': | 1035 | case '=': |
1059 | clear_line(); | 1036 | clear_line(); |
1060 | m_status_print(); | 1037 | m_status_print(); |
1061 | break; | 1038 | break; |
1062 | #endif | 1039 | #endif |
1063 | #ifdef CONFIG_FEATURE_LESS_REGEXP | 1040 | #if ENABLE_FEATURE_LESS_REGEXP |
1064 | case '/': | 1041 | case '/': |
1065 | flags &= ~LESS_STATE_MATCH_BACKWARDS; | 1042 | option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS; |
1066 | regex_process(); | 1043 | regex_process(); |
1067 | break; | 1044 | break; |
1068 | case 'n': | 1045 | case 'n': |
@@ -1072,11 +1049,11 @@ static void keypress_process(int keypress) | |||
1072 | goto_match(match_pos - 1); | 1049 | goto_match(match_pos - 1); |
1073 | break; | 1050 | break; |
1074 | case '?': | 1051 | case '?': |
1075 | flags |= LESS_STATE_MATCH_BACKWARDS; | 1052 | option_mask32 |= LESS_STATE_MATCH_BACKWARDS; |
1076 | regex_process(); | 1053 | regex_process(); |
1077 | break; | 1054 | break; |
1078 | #endif | 1055 | #endif |
1079 | #ifdef CONFIG_FEATURE_LESS_FLAGCS | 1056 | #if ENABLE_FEATURE_LESS_FLAGCS |
1080 | case '-': | 1057 | case '-': |
1081 | flag_change(); | 1058 | flag_change(); |
1082 | buffer_print(); | 1059 | buffer_print(); |
@@ -1085,7 +1062,7 @@ static void keypress_process(int keypress) | |||
1085 | show_flag_status(); | 1062 | show_flag_status(); |
1086 | break; | 1063 | break; |
1087 | #endif | 1064 | #endif |
1088 | #ifdef CONFIG_FEATURE_LESS_BRACKETS | 1065 | #if ENABLE_FEATURE_LESS_BRACKETS |
1089 | case '{': case '(': case '[': | 1066 | case '{': case '(': case '[': |
1090 | match_right_bracket(keypress); | 1067 | match_right_bracket(keypress); |
1091 | break; | 1068 | break; |
@@ -1104,30 +1081,42 @@ static void keypress_process(int keypress) | |||
1104 | number_process(keypress); | 1081 | number_process(keypress); |
1105 | } | 1082 | } |
1106 | 1083 | ||
1107 | int less_main(int argc, char **argv) { | 1084 | static void sig_catcher(int sig ATTRIBUTE_UNUSED) |
1085 | { | ||
1086 | set_tty_cooked(); | ||
1087 | exit(1); | ||
1088 | } | ||
1108 | 1089 | ||
1090 | int less_main(int argc, char **argv) | ||
1091 | { | ||
1109 | int keypress; | 1092 | int keypress; |
1110 | 1093 | ||
1111 | flags = getopt32(argc, argv, "EMmN~"); | 1094 | getopt32(argc, argv, "EMmN~"); |
1112 | |||
1113 | argc -= optind; | 1095 | argc -= optind; |
1114 | argv += optind; | 1096 | argv += optind; |
1115 | files = argv; | 1097 | files = argv; |
1116 | num_files = argc; | 1098 | num_files = argc; |
1117 | 1099 | ||
1118 | if (!num_files) { | 1100 | if (!num_files) { |
1119 | if (ttyname(STDIN_FILENO) == NULL) | 1101 | if (isatty(STDIN_FILENO)) { |
1120 | flags |= LESS_STATE_INP_STDIN; | 1102 | /* Just "less"? No file and no redirection? */ |
1121 | else { | ||
1122 | bb_error_msg("missing filename"); | 1103 | bb_error_msg("missing filename"); |
1123 | bb_show_usage(); | 1104 | bb_show_usage(); |
1124 | } | 1105 | } |
1125 | } | 1106 | } else |
1107 | filename = xstrdup(files[0]); | ||
1108 | |||
1109 | /* FIXME: another popular pager, most, detects when stdout | ||
1110 | * is not a tty and turns into cat */ | ||
1111 | inp = xfopen(CURRENT_TTY, "r"); | ||
1126 | 1112 | ||
1127 | strcpy(filename, (flags & LESS_STATE_INP_STDIN) ? bb_msg_standard_input : files[0]); | 1113 | get_terminal_width_height(fileno(inp), &width, &height); |
1128 | get_terminal_width_height(0, &width, &height); | ||
1129 | data_readlines(); | 1114 | data_readlines(); |
1115 | |||
1116 | signal(SIGTERM, sig_catcher); | ||
1117 | signal(SIGINT, sig_catcher); | ||
1130 | tcgetattr(fileno(inp), &term_orig); | 1118 | tcgetattr(fileno(inp), &term_orig); |
1119 | |||
1131 | term_vi = term_orig; | 1120 | term_vi = term_orig; |
1132 | term_vi.c_lflag &= (~ICANON & ~ECHO); | 1121 | term_vi.c_lflag &= (~ICANON & ~ECHO); |
1133 | term_vi.c_iflag &= (~IXON & ~ICRNL); | 1122 | term_vi.c_iflag &= (~IXON & ~ICRNL); |