tls: check size on "MAC-only, no crypt" code path too
[oweals/busybox.git] / editors / ed.c
index cceff0c4003c7ac14bb728868c951c31cd3bc756..c028b78cb8157599f3788e3a55e995b20401c395 100644 (file)
@@ -7,7 +7,23 @@
  * The "ed" built-in command (much simplified)
  */
 
+//config:config ED
+//config:      bool "ed"
+//config:      default y
+//config:      help
+//config:        The original 1970's Unix text editor, from the days of teletypes.
+//config:        Small, simple, evil. Part of SUSv3. If you're not already using
+//config:        this, you don't need it.
+
+//kbuild:lib-$(CONFIG_ED) += ed.o
+
+//applet:IF_ED(APPLET(ed, BB_DIR_BIN, BB_SUID_DROP))
+
+//usage:#define ed_trivial_usage ""
+//usage:#define ed_full_usage ""
+
 #include "libbb.h"
+#include "common_bufsiz.h"
 
 typedef struct LINE {
        struct LINE *next;
@@ -20,8 +36,8 @@ typedef struct LINE {
 #define searchString bb_common_bufsiz1
 
 enum {
-       USERSIZE = sizeof(searchString) > 1024 ? 1024
-                : sizeof(searchString) - 1, /* max line length typed in by user */
+       USERSIZE = COMMON_BUFSIZE > 1024 ? 1024
+                : COMMON_BUFSIZE - 1, /* max line length typed in by user */
        INITBUF_SIZE = 1024, /* initial buffer size */
 };
 
@@ -51,7 +67,8 @@ struct globals {
 #define lines              (G.lines             )
 #define marks              (G.marks             )
 #define INIT_G() do { \
-       PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
+       setup_common_bufsiz(); \
+       SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 } while (0)
 
 
@@ -89,7 +106,7 @@ static char *skip_blank(const char *cp)
 
 
 int ed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int ed_main(int argc, char **argv)
+int ed_main(int argc UNUSED_PARAM, char **argv)
 {
        INIT_G();
 
@@ -99,7 +116,7 @@ int ed_main(int argc, char **argv)
        lines.next = &lines;
        lines.prev = &lines;
 
-       if (argc > 1) {
+       if (argv[1]) {
                fileName = xstrdup(argv[1]);
                if (!readLines(fileName, 1)) {
                        return EXIT_SUCCESS;
@@ -119,7 +136,7 @@ int ed_main(int argc, char **argv)
 static void doCommands(void)
 {
        const char *cp;
-       char *endbuf, *newname, buf[USERSIZE];
+       char *endbuf, buf[USERSIZE];
        int len, num1, num2;
        smallint have1, have2;
 
@@ -129,7 +146,7 @@ static void doCommands(void)
                 * 0  on ctrl-C,
                 * >0 length of input string, including terminating '\n'
                 */
-               len = read_line_input(": ", buf, sizeof(buf), NULL);
+               len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1);
                if (len <= 0)
                        return;
                endbuf = &buf[len - 1];
@@ -168,162 +185,157 @@ static void doCommands(void)
                        num2 = num1;
 
                switch (*cp++) {
-                       case 'a':
-                               addLines(num1 + 1);
-                               break;
+               case 'a':
+                       addLines(num1 + 1);
+                       break;
 
-                       case 'c':
-                               deleteLines(num1, num2);
-                               addLines(num1);
-                               break;
+               case 'c':
+                       deleteLines(num1, num2);
+                       addLines(num1);
+                       break;
 
-                       case 'd':
-                               deleteLines(num1, num2);
-                               break;
+               case 'd':
+                       deleteLines(num1, num2);
+                       break;
 
-                       case 'f':
-                               if (*cp && !isblank(*cp)) {
-                                       bb_error_msg("bad file command");
-                                       break;
-                               }
-                               cp = skip_blank(cp);
-                               if (*cp == '\0') {
-                                       if (fileName)
-                                               printf("\"%s\"\n", fileName);
-                                       else
-                                               printf("No file name\n");
-                                       break;
-                               }
-                               newname = strdup(cp);
-                               if (newname == NULL) {
-                                       bb_error_msg("no memory for file name");
-                                       break;
-                               }
-                               free(fileName);
-                               fileName = newname;
+               case 'f':
+                       if (*cp && !isblank(*cp)) {
+                               bb_error_msg("bad file command");
                                break;
-
-                       case 'i':
-                               addLines(num1);
+                       }
+                       cp = skip_blank(cp);
+                       if (*cp == '\0') {
+                               if (fileName)
+                                       printf("\"%s\"\n", fileName);
+                               else
+                                       puts("No file name");
                                break;
+                       }
+                       free(fileName);
+                       fileName = xstrdup(cp);
+                       break;
 
-                       case 'k':
-                               cp = skip_blank(cp);
-                               if ((*cp < 'a') || (*cp > 'z') || cp[1]) {
-                                       bb_error_msg("bad mark name");
-                                       break;
-                               }
-                               marks[*cp - 'a'] = num2;
-                               break;
+               case 'i':
+                       addLines(num1);
+                       break;
 
-                       case 'l':
-                               printLines(num1, num2, TRUE);
+               case 'k':
+                       cp = skip_blank(cp);
+                       if ((*cp < 'a') || (*cp > 'z') || cp[1]) {
+                               bb_error_msg("bad mark name");
                                break;
+                       }
+                       marks[*cp - 'a'] = num2;
+                       break;
 
-                       case 'p':
-                               printLines(num1, num2, FALSE);
-                               break;
+               case 'l':
+                       printLines(num1, num2, TRUE);
+                       break;
 
-                       case 'q':
-                               cp = skip_blank(cp);
-                               if (have1 || *cp) {
-                                       bb_error_msg("bad quit command");
-                                       break;
-                               }
-                               if (!dirty)
-                                       return;
-                               len = read_line_input("Really quit? ", buf, 16, NULL);
-                               /* read error/EOF - no way to continue */
-                               if (len < 0)
-                                       return;
-                               cp = skip_blank(buf);
-                               if ((*cp | 0x20) == 'y') /* Y or y */
-                                       return;
-                               break;
+               case 'p':
+                       printLines(num1, num2, FALSE);
+                       break;
 
-                       case 'r':
-                               if (*cp && !isblank(*cp)) {
-                                       bb_error_msg("bad read command");
-                                       break;
-                               }
-                               cp = skip_blank(cp);
-                               if (*cp == '\0') {
-                                       bb_error_msg("no file name");
-                                       break;
-                               }
-                               if (!have1)
-                                       num1 = lastNum;
-                               if (readLines(cp, num1 + 1))
-                                       break;
-                               if (fileName == NULL)
-                                       fileName = strdup(cp);
+               case 'q':
+                       cp = skip_blank(cp);
+                       if (have1 || *cp) {
+                               bb_error_msg("bad quit command");
                                break;
+                       }
+                       if (!dirty)
+                               return;
+                       len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1);
+                       /* read error/EOF - no way to continue */
+                       if (len < 0)
+                               return;
+                       cp = skip_blank(buf);
+                       if ((*cp | 0x20) == 'y') /* Y or y */
+                               return;
+                       break;
 
-                       case 's':
-                               subCommand(cp, num1, num2);
+               case 'r':
+                       if (*cp && !isblank(*cp)) {
+                               bb_error_msg("bad read command");
                                break;
-
-                       case 'w':
-                               if (*cp && !isblank(*cp)) {
-                                       bb_error_msg("bad write command");
-                                       break;
-                               }
-                               cp = skip_blank(cp);
-                               if (!have1) {
-                                       num1 = 1;
-                                       num2 = lastNum;
-                               }
-                               if (*cp == '\0')
-                                       cp = fileName;
-                               if (cp == NULL) {
-                                       bb_error_msg("no file name specified");
-                                       break;
-                               }
-                               writeLines(cp, num1, num2);
+                       }
+                       cp = skip_blank(cp);
+                       if (*cp == '\0') {
+                               bb_error_msg("no file name");
                                break;
-
-                       case 'z':
-                               switch (*cp) {
-                               case '-':
-                                       printLines(curNum - 21, curNum, FALSE);
-                                       break;
-                               case '.':
-                                       printLines(curNum - 11, curNum + 10, FALSE);
-                                       break;
-                               default:
-                                       printLines(curNum, curNum + 21, FALSE);
-                                       break;
-                               }
+                       }
+                       if (!have1)
+                               num1 = lastNum;
+                       if (readLines(cp, num1 + 1))
                                break;
+                       if (fileName == NULL)
+                               fileName = xstrdup(cp);
+                       break;
 
-                       case '.':
-                               if (have1) {
-                                       bb_error_msg("no arguments allowed");
-                                       break;
-                               }
-                               printLines(curNum, curNum, FALSE);
+               case 's':
+                       subCommand(cp, num1, num2);
+                       break;
+
+               case 'w':
+                       if (*cp && !isblank(*cp)) {
+                               bb_error_msg("bad write command");
                                break;
+                       }
+                       cp = skip_blank(cp);
+                       if (!have1) {
+                               num1 = 1;
+                               num2 = lastNum;
+                       }
+                       if (*cp == '\0')
+                               cp = fileName;
+                       if (cp == NULL) {
+                               bb_error_msg("no file name specified");
+                               break;
+                       }
+                       writeLines(cp, num1, num2);
+                       break;
 
+               case 'z':
+                       switch (*cp) {
                        case '-':
-                               if (setCurNum(curNum - 1))
-                                       printLines(curNum, curNum, FALSE);
+                               printLines(curNum - 21, curNum, FALSE);
                                break;
-
-                       case '=':
-                               printf("%d\n", num1);
+                       case '.':
+                               printLines(curNum - 11, curNum + 10, FALSE);
                                break;
-                       case '\0':
-                               if (have1) {
-                                       printLines(num2, num2, FALSE);
-                                       break;
-                               }
-                               if (setCurNum(curNum + 1))
-                                       printLines(curNum, curNum, FALSE);
+                       default:
+                               printLines(curNum, curNum + 21, FALSE);
                                break;
+                       }
+                       break;
 
-                       default:
-                               bb_error_msg("unimplemented command");
+               case '.':
+                       if (have1) {
+                               bb_error_msg("no arguments allowed");
+                               break;
+                       }
+                       printLines(curNum, curNum, FALSE);
+                       break;
+
+               case '-':
+                       if (setCurNum(curNum - 1))
+                               printLines(curNum, curNum, FALSE);
+                       break;
+
+               case '=':
+                       printf("%d\n", num1);
+                       break;
+               case '\0':
+                       if (have1) {
+                               printLines(num2, num2, FALSE);
                                break;
+                       }
+                       if (setCurNum(curNum + 1))
+                               printLines(curNum, curNum, FALSE);
+                       break;
+
+               default:
+                       bb_error_msg("unimplemented command");
+                       break;
                }
        }
 }
@@ -456,14 +468,10 @@ static void subCommand(const char *cmd, int num1, int num2)
 
                /*
                 * The new string is larger, so allocate a new line
-                * structure and use that.  Link it in in place of
+                * structure and use that.  Link it in place of
                 * the old line structure.
                 */
-               nlp = malloc(sizeof(LINE) + lp->len + deltaLen);
-               if (nlp == NULL) {
-                       bb_error_msg("cannot get memory for line");
-                       return;
-               }
+               nlp = xmalloc(sizeof(LINE) + lp->len + deltaLen);
 
                nlp->len = lp->len + deltaLen;
 
@@ -550,7 +558,7 @@ static void addLines(int num)
                 * 0  on ctrl-C,
                 * >0 length of input string, including terminating '\n'
                 */
-               len = read_line_input("", buf, sizeof(buf), NULL);
+               len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1);
                if (len <= 0) {
                        /* Previously, ctrl-C was exiting to shell.
                         * Now we exit to ed prompt. Is in important? */
@@ -680,7 +688,7 @@ static int readLines(const char *file, int num)
 
        fd = open(file, 0);
        if (fd < 0) {
-               perror(file);
+               bb_simple_perror_msg(file);
                return FALSE;
        }
 
@@ -691,7 +699,7 @@ static int readLines(const char *file, int num)
        cc = 0;
 
        printf("\"%s\", ", file);
-       fflush(stdout);
+       fflush_all();
 
        do {
                cp = memchr(bufPtr, '\n', bufUsed);
@@ -717,12 +725,7 @@ static int readLines(const char *file, int num)
 
                if (bufUsed >= bufSize) {
                        len = (bufSize * 3) / 2;
-                       cp = realloc(bufBase, len);
-                       if (cp == NULL) {
-                               bb_error_msg("no memory for buffer");
-                               close(fd);
-                               return FALSE;
-                       }
+                       cp = xrealloc(bufBase, len);
                        bufBase = cp;
                        bufPtr = bufBase + bufUsed;
                        bufSize = len;
@@ -731,11 +734,10 @@ static int readLines(const char *file, int num)
                cc = safe_read(fd, bufPtr, bufSize - bufUsed);
                bufUsed += cc;
                bufPtr = bufBase;
-
        } while (cc > 0);
 
        if (cc < 0) {
-               perror(file);
+               bb_simple_perror_msg(file);
                close(fd);
                return FALSE;
        }
@@ -775,12 +777,12 @@ static int writeLines(const char *file, int num1, int num2)
 
        fd = creat(file, 0666);
        if (fd < 0) {
-               perror(file);
+               bb_simple_perror_msg(file);
                return FALSE;
        }
 
        printf("\"%s\", ", file);
-       fflush(stdout);
+       fflush_all();
 
        lp = findLine(num1);
        if (lp == NULL) {
@@ -790,7 +792,7 @@ static int writeLines(const char *file, int num1, int num2)
 
        while (num1++ <= num2) {
                if (full_write(fd, lp->data, lp->len) != lp->len) {
-                       perror(file);
+                       bb_simple_perror_msg(file);
                        close(fd);
                        return FALSE;
                }
@@ -800,7 +802,7 @@ static int writeLines(const char *file, int num1, int num2)
        }
 
        if (close(fd) < 0) {
-               perror(file);
+               bb_simple_perror_msg(file);
                return FALSE;
        }
 
@@ -830,7 +832,7 @@ static int printLines(int num1, int num2, int expandFlag)
 
        while (num1 <= num2) {
                if (!expandFlag) {
-                       write(1, lp->data, lp->len);
+                       write(STDOUT_FILENO, lp->data, lp->len);
                        setCurNum(num1++);
                        lp = lp->next;
                        continue;
@@ -847,20 +849,8 @@ static int printLines(int num1, int num2, int expandFlag)
                        count--;
 
                while (count-- > 0) {
-                       ch = *cp++;
-                       if (ch & 0x80) {
-                               fputs("M-", stdout);
-                               ch &= 0x7f;
-                       }
-                       if (ch < ' ') {
-                               bb_putchar('^');
-                               ch += '@';
-                       }
-                       if (ch == 0x7f) {
-                               bb_putchar('^');
-                               ch = '?';
-                       }
-                       bb_putchar(ch);
+                       ch = (unsigned char) *cp++;
+                       fputc_printable(ch | PRINTABLE_META, stdout);
                }
 
                fputs("$\n", stdout);
@@ -889,11 +879,7 @@ static int insertLine(int num, const char *data, int len)
                return FALSE;
        }
 
-       newLp = malloc(sizeof(LINE) + len - 1);
-       if (newLp == NULL) {
-               bb_error_msg("failed to allocate memory for line");
-               return FALSE;
-       }
+       newLp = xmalloc(sizeof(LINE) + len - 1);
 
        memcpy(newLp->data, data, len);
        newLp->len = len;
@@ -968,7 +954,7 @@ static void deleteLines(int num1, int num2)
  * Returns the line number which matches, or 0 if there was no match
  * with an error printed.
  */
-static int searchLines(const char *str, int num1, int num2)
+static NOINLINE int searchLines(const char *str, int num1, int num2)
 {
        const LINE *lp;
        int len;
@@ -1000,7 +986,7 @@ static int searchLines(const char *str, int num1, int num2)
                lp = lp->next;
        }
 
-       bb_error_msg("cannot find string \"%s\"", str);
+       bb_error_msg("can't find string \"%s\"", str);
        return 0;
 }