less: more sane way of line numbering. Prepares for
[oweals/busybox.git] / miscutils / less.c
index cd47590ee189d475fdd7b875f06d726e549ff69f..049814319cfc109786fa3b6e638aa5a3e3405b07 100644 (file)
@@ -166,6 +166,14 @@ struct globals {
        USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \
 } while (0)
 
+/* flines[] are lines read from stdin, each in malloc'ed buffer.
+ * Line numbers are stored as uint32_t prepended to each line.
+ * Pointer is adjusted so that flines[i] points directly past
+ * line number. Accesor: */
+#define MEMPTR(p) ((char*)(p) - 4)
+#define LINENO(p) (*(uint32_t*)((p) - 4))
+
+
 /* Reset terminal input to normal */
 static void set_tty_cooked(void)
 {
@@ -252,15 +260,13 @@ static void read_lines(void)
 
  USE_FEATURE_LESS_REGEXP(again0:)
 
-       p = current_line = xmalloc(w);
+       p = current_line = ((char*)xmalloc(w + 4)) + 4;
        max_fline += last_terminated;
        if (!last_terminated) {
                const char *cp = flines[max_fline];
-               if (option_mask32 & FLAG_N)
-                       cp += 8;
-               strcpy(current_line, cp);
+               strcpy(p, cp);
                p += strlen(current_line);
-               free((char*)flines[max_fline]);
+               free(MEMPTR(flines[max_fline]));
                /* linepos is still valid from previous read_lines() */
        } else {
                linepos = 0;
@@ -324,17 +330,12 @@ static void read_lines(void)
  reached_eof:
                last_terminated = terminated;
                flines = xrealloc_vector(flines, 8, max_fline);
-               if (option_mask32 & FLAG_N) {
-                       /* Width of 7 preserves tab spacing in the text */
-                       flines[max_fline] = xasprintf(
-                               (max_lineno <= 9999999) ? "%7u %s" : "%07u %s",
-                               max_lineno % 10000000, current_line);
-                       free(current_line);
-                       if (terminated)
-                               max_lineno++;
-               } else {
-                       flines[max_fline] = xrealloc(current_line, strlen(current_line) + 1);
-               }
+
+               flines[max_fline] = (char*)xrealloc(MEMPTR(current_line), strlen(current_line) + 1 + 4) + 4;
+               LINENO(flines[max_fline]) = max_lineno;
+               if (terminated)
+                       max_lineno++;
+
                if (max_fline >= MAXLINES) {
                        eof_error = 0; /* Pretend we saw EOF */
                        break;
@@ -380,7 +381,7 @@ static void read_lines(void)
 #endif
                }
                max_fline++;
-               current_line = xmalloc(w);
+               current_line = ((char*)xmalloc(w + 4)) + 4;
                p = current_line;
                linepos = 0;
        } /* end of "read lines until we reach cur_fline" loop */
@@ -487,6 +488,30 @@ static const char ctrlconv[] ALIGN1 =
        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x40\x4b\x4c\x4d\x4e\x4f"
        "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f";
 
+static void lineno_str(char *nbuf9, const char *line)
+{
+       nbuf9[0] = '\0';
+       if (option_mask32 & FLAG_N) {
+               const char *fmt;
+               unsigned n;
+
+               if (line == empty_line_marker) {
+                       memset(nbuf9, ' ', 8);
+                       nbuf9[8] = '\0';
+                       return;
+               }
+               /* Width of 7 preserves tab spacing in the text */
+               fmt = "%7u ";
+               n = LINENO(line);
+               if (n > 9999999) {
+                       n %= 10000000;
+                       fmt = "%07u ";
+               }
+               sprintf(nbuf9, fmt, n);
+       }
+}
+
+
 #if ENABLE_FEATURE_LESS_REGEXP
 static void print_found(const char *line)
 {
@@ -496,6 +521,7 @@ static void print_found(const char *line)
        regmatch_t match_structs;
 
        char buf[width];
+       char nbuf9[9];
        const char *str = line;
        char *p = buf;
        size_t n;
@@ -532,7 +558,8 @@ static void print_found(const char *line)
                                match_structs.rm_so, str,
                                match_structs.rm_eo - match_structs.rm_so,
                                                str + match_structs.rm_so);
-               free(growline); growline = new;
+               free(growline);
+               growline = new;
                str += match_structs.rm_eo;
                line += match_structs.rm_eo;
                eflags = REG_NOTBOL;
@@ -544,11 +571,12 @@ static void print_found(const char *line)
                        match_status = 1;
        }
 
+       lineno_str(nbuf9, line);
        if (!growline) {
-               printf(CLEAR_2_EOL"%s\n", str);
+               printf(CLEAR_2_EOL"%s%s\n", nbuf9, str);
                return;
        }
-       printf(CLEAR_2_EOL"%s%s\n", growline, str);
+       printf(CLEAR_2_EOL"%s%s%s\n", nbuf9, growline, str);
        free(growline);
 }
 #else
@@ -558,10 +586,13 @@ void print_found(const char *line);
 static void print_ascii(const char *str)
 {
        char buf[width];
+       char nbuf9[9];
        char *p;
        size_t n;
 
-       printf(CLEAR_2_EOL);
+       lineno_str(nbuf9, str);
+       printf(CLEAR_2_EOL"%s", nbuf9);
+
        while (*str) {
                n = strcspn(str, controls);
                if (n) {
@@ -670,7 +701,7 @@ static void reinitialize(void)
 
        if (flines) {
                for (i = 0; i <= max_fline; i++)
-                       free((void*)(flines[i]));
+                       free(MEMPTR(flines[i]));
                free(flines);
                flines = NULL;
        }