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 | |
| 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')
| -rw-r--r-- | miscutils/Config.in | 5 | ||||
| -rw-r--r-- | miscutils/less.c | 413 |
2 files changed, 206 insertions, 212 deletions
diff --git a/miscutils/Config.in b/miscutils/Config.in index 90e2b6fb1..01d1fa0a5 100644 --- a/miscutils/Config.in +++ b/miscutils/Config.in | |||
| @@ -133,6 +133,11 @@ config LESS | |||
| 133 | 'less' is a pager, meaning that it displays text files. It possesses | 133 | 'less' is a pager, meaning that it displays text files. It possesses |
| 134 | a wide array of features, and is an improvement over 'more'. | 134 | a wide array of features, and is an improvement over 'more'. |
| 135 | 135 | ||
| 136 | config FEATURE_LESS_MAXLINES | ||
| 137 | int "Max number of input lines less will try to eat" | ||
| 138 | default 9999999 | ||
| 139 | depends on LESS | ||
| 140 | |||
| 136 | config FEATURE_LESS_BRACKETS | 141 | config FEATURE_LESS_BRACKETS |
| 137 | bool "Enable bracket searching" | 142 | bool "Enable bracket searching" |
| 138 | default y | 143 | default y |
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); |
