1 Index: editors/Makefile.in
2 ===================================================================
3 --- editors/Makefile.in (revision 10144)
4 +++ editors/Makefile.in (working copy)
6 srcdir=$(top_srcdir)/editors
9 -EDITOR-$(CONFIG_AWK) += awk.o
10 -EDITOR-$(CONFIG_PATCH) += patch.o
11 +EDITOR-$(CONFIG_AWK) += awk.o
12 +EDITOR-$(CONFIG_ED) += ed.o
13 +EDITOR-$(CONFIG_PATCH) += patch.o
14 EDITOR-$(CONFIG_SED) += sed.o
15 EDITOR-$(CONFIG_VI) += vi.o
16 EDITOR_SRC:= $(EDITOR-y)
17 Index: editors/Config.in
18 ===================================================================
19 --- editors/Config.in (revision 10144)
20 +++ editors/Config.in (working copy)
22 Enable math functions of the Awk programming language.
23 NOTE: This will require libm to be present for linking.
34 Index: include/usage.h
35 ===================================================================
36 --- include/usage.h (revision 10151)
37 +++ include/usage.h (working copy)
39 "$ echo \"Erik\\nis\\ncool\"\n" \
42 +#define ed_trivial_usage ""
43 +#define ed_full_usage ""
45 #define env_trivial_usage \
46 "[-iu] [-] [name=value]... [command]"
47 #define env_full_usage \
48 Index: include/applets.h
49 ===================================================================
50 --- include/applets.h (revision 10151)
51 +++ include/applets.h (working copy)
54 APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER)
57 + APPLET(ed, ed_main, _BB_DIR_BIN, _BB_SUID_NEVER)
59 #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
60 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
62 --- /dev/null 2005-04-24 01:00:01.350003056 -0400
63 +++ ed.c 2005-04-24 01:38:51.000000000 -0400
66 + * Copyright (c) 2002 by David I. Bell
67 + * Permission is granted to use, distribute, or modify this source,
68 + * provided that this copyright notice remains intact.
70 + * The "ed" built-in command (much simplified)
81 +#include <sys/param.h>
85 +#define USERSIZE 1024 /* max line length typed in by user */
86 +#define INITBUF_SIZE 1024 /* initial buffer size */
92 +typedef struct LINE LINE;
101 +static LINE *curLine;
104 +static NUM marks[26];
106 +static char *fileName;
107 +static char searchString[USERSIZE];
109 +static char *bufBase;
110 +static char *bufPtr;
114 +static void doCommands(void);
115 +static void subCommand(const char * cmd, NUM num1, NUM num2);
116 +static BOOL getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum);
117 +static BOOL setCurNum(NUM num);
118 +static BOOL initEdit(void);
119 +static void termEdit(void);
120 +static void addLines(NUM num);
121 +static BOOL insertLine(NUM num, const char * data, LEN len);
122 +static BOOL deleteLines(NUM num1, NUM num2);
123 +static BOOL printLines(NUM num1, NUM num2, BOOL expandFlag);
124 +static BOOL writeLines(const char * file, NUM num1, NUM num2);
125 +static BOOL readLines(const char * file, NUM num);
126 +static NUM searchLines(const char * str, NUM num1, NUM num2);
127 +static LINE * findLine(NUM num);
129 +static LEN findString(const LINE * lp, const char * str, LEN len, LEN offset);
131 +int ed_main(int argc, char **argv)
134 + return EXIT_FAILURE;
137 + fileName = strdup(argv[1]);
139 + if (fileName == NULL) {
140 + bb_error_msg("No memory");
142 + return EXIT_SUCCESS;
145 + if (!readLines(fileName, 1)) {
147 + return EXIT_SUCCESS;
159 + return EXIT_SUCCESS;
163 + * Read commands until we are told to stop.
165 +static void doCommands(void)
175 + char buf[USERSIZE];
182 + if (fgets(buf, sizeof(buf), stdin) == NULL)
190 + endbuf = &buf[len - 1];
192 + if (*endbuf != '\n')
194 + bb_error_msg("Command line too long");
198 + len = fgetc(stdin);
200 + while ((len != EOF) && (len != '\n'));
205 + while ((endbuf > buf) && isblank(endbuf[-1]))
212 + while (isblank(*cp))
218 + if ((curNum == 0) && (lastNum > 0))
221 + curLine = lines.next;
224 + if (!getNum(&cp, &have1, &num1))
227 + while (isblank(*cp))
234 + if (!getNum(&cp, &have2, &num2))
256 + addLines(num1 + 1);
260 + deleteLines(num1, num2);
265 + deleteLines(num1, num2);
269 + if (*cp && !isblank(*cp))
271 + bb_error_msg("Bad file command");
275 + while (isblank(*cp))
281 + printf("\"%s\"\n", fileName);
283 + printf("No file name\n");
288 + newname = strdup(cp);
290 + if (newname == NULL)
292 + bb_error_msg("No memory for file name");
299 + fileName = newname;
307 + while (isblank(*cp))
310 + if ((*cp < 'a') || (*cp > 'a') || cp[1])
312 + bb_error_msg("Bad mark name");
316 + marks[*cp - 'a'] = num2;
320 + printLines(num1, num2, TRUE);
324 + printLines(num1, num2, FALSE);
328 + while (isblank(*cp))
333 + bb_error_msg("Bad quit command");
340 + printf("Really quit? ");
344 + fgets(buf, sizeof(buf), stdin);
347 + while (isblank(*cp))
350 + if ((*cp == 'y') || (*cp == 'Y'))
356 + if (*cp && !isblank(*cp))
358 + bb_error_msg("Bad read command");
362 + while (isblank(*cp))
367 + bb_error_msg("No file name");
374 + if (readLines(cp, num1 + 1))
377 + if (fileName == NULL)
378 + fileName = strdup(cp);
383 + subCommand(cp, num1, num2);
387 + if (*cp && !isblank(*cp))
389 + bb_error_msg("Bad write command");
393 + while (isblank(*cp))
406 + bb_error_msg("No file name specified");
410 + writeLines(cp, num1, num2);
417 + printLines(curNum-21, curNum, FALSE);
420 + printLines(curNum-11, curNum+10, FALSE);
423 + printLines(curNum, curNum+21, FALSE);
431 + bb_error_msg("No arguments allowed");
435 + printLines(curNum, curNum, FALSE);
439 + if (setCurNum(curNum - 1))
440 + printLines(curNum, curNum, FALSE);
445 + printf("%d\n", num1);
451 + printLines(num2, num2, FALSE);
455 + if (setCurNum(curNum + 1))
456 + printLines(curNum, curNum, FALSE);
461 + bb_error_msg("Unimplemented command");
469 + * Do the substitute command.
470 + * The current line is set to the last substitution done.
473 +subCommand(const char * cmd, NUM num1, NUM num2)
489 + char buf[USERSIZE];
491 + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
493 + bb_error_msg("Bad line range for substitute");
498 + globalFlag = FALSE;
504 + * Copy the command so we can modify it.
509 + if (isblank(*cp) || (*cp == '\0'))
511 + bb_error_msg("Bad delimiter for substitute");
519 + cp = strchr(cp, delim);
523 + bb_error_msg("Missing 2nd delimiter for substitute");
531 + cp = strchr(cp, delim);
538 + while (*cp) switch (*cp++)
549 + bb_error_msg("Unknown option for substitute");
554 + if (*oldStr == '\0')
556 + if (searchString[0] == '\0')
558 + bb_error_msg("No previous search string");
563 + oldStr = searchString;
566 + if (oldStr != searchString)
567 + strcpy(searchString, oldStr);
569 + lp = findLine(num1);
574 + oldLen = strlen(oldStr);
575 + newLen = strlen(newStr);
576 + deltaLen = newLen - oldLen;
580 + while (num1 <= num2)
582 + offset = findString(lp, oldStr, oldLen, offset);
588 + printLines(num1, num1, FALSE);
599 + needPrint = printFlag;
604 + * If the replacement string is the same size or shorter
605 + * than the old string, then the substitution is easy.
609 + memcpy(&lp->data[offset], newStr, newLen);
613 + memcpy(&lp->data[offset + newLen],
614 + &lp->data[offset + oldLen],
615 + lp->len - offset - oldLen);
617 + lp->len += deltaLen;
627 + printLines(num1, num1, FALSE);
638 + * The new string is larger, so allocate a new line
639 + * structure and use that. Link it in in place of
640 + * the old line structure.
642 + nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen);
646 + bb_error_msg("Cannot get memory for line");
651 + nlp->len = lp->len + deltaLen;
653 + memcpy(nlp->data, lp->data, offset);
655 + memcpy(&nlp->data[offset], newStr, newLen);
657 + memcpy(&nlp->data[offset + newLen],
658 + &lp->data[offset + oldLen],
659 + lp->len - offset - oldLen);
661 + nlp->next = lp->next;
662 + nlp->prev = lp->prev;
663 + nlp->prev->next = nlp;
664 + nlp->next->prev = nlp;
679 + printLines(num1, num1, FALSE);
688 + bb_error_msg("No substitutions found for \"%s\"", oldStr);
693 + * Search a line for the specified string starting at the specified
694 + * offset in the line. Returns the offset of the found string, or -1.
697 +findString( const LINE * lp, const char * str, LEN len, LEN offset)
703 + cp = &lp->data[offset];
704 + left = lp->len - offset;
706 + while (left >= len)
708 + ncp = memchr(cp, *str, left);
713 + left -= (ncp - cp);
720 + if (memcmp(cp, str, len) == 0)
721 + return (cp - lp->data);
732 + * Add lines which are typed in by the user.
733 + * The lines are inserted just before the specified line number.
734 + * The lines are terminated by a line containing a single dot (ugly!),
735 + * or by an end of file.
741 + char buf[USERSIZE + 1];
743 + while (fgets(buf, sizeof(buf), stdin))
745 + if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
753 + if (buf[len - 1] != '\n')
755 + bb_error_msg("Line too long");
759 + len = fgetc(stdin);
761 + while ((len != EOF) && (len != '\n'));
766 + if (!insertLine(num++, buf, len))
773 + * Parse a line number argument if it is present. This is a sum
774 + * or difference of numbers, '.', '$', 'x, or a search string.
775 + * Returns TRUE if successful (whether or not there was a number).
776 + * Returns FALSE if there was a parsing error, with a message output.
777 + * Whether there was a number is returned indirectly, as is the number.
778 + * The character pointer which stopped the scan is also returned.
781 +getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum)
785 + char str[USERSIZE];
798 + while (isblank(*cp))
818 + if ((*cp < 'a') || (*cp > 'z'))
820 + bb_error_msg("Bad mark name");
826 + num = marks[*cp++ - 'a'];
831 + endStr = strchr(str, '/');
836 + cp += (endStr - str);
841 + num = searchLines(str, curNum, lastNum);
853 + *retHaveNum = haveNum;
861 + while (isdigit(*cp))
862 + num = num * 10 + *cp++ - '0';
868 + value += num * sign;
870 + while (isblank(*cp))
887 + *retHaveNum = haveNum;
897 + * Initialize everything for editing.
904 + bufSize = INITBUF_SIZE;
905 + bufBase = malloc(bufSize);
907 + if (bufBase == NULL)
909 + bb_error_msg("No memory for buffer");
917 + lines.next = &lines;
918 + lines.prev = &lines;
925 + searchString[0] = '\0';
927 + for (i = 0; i < 26; i++)
953 + searchString[0] = '\0';
956 + deleteLines(1, lastNum);
965 + * Read lines from a file at the specified line number.
966 + * Returns TRUE if the file was successfully read.
969 +readLines(const char * file, NUM num)
978 + if ((num < 1) || (num > lastNum + 1))
980 + bb_error_msg("Bad line for read");
985 + fd = open(file, 0);
1000 + printf("\"%s\", ", file);
1005 + cp = memchr(bufPtr, '\n', bufUsed);
1009 + len = (cp - bufPtr) + 1;
1011 + if (!insertLine(num, bufPtr, len))
1027 + if (bufPtr != bufBase)
1029 + memcpy(bufBase, bufPtr, bufUsed);
1030 + bufPtr = bufBase + bufUsed;
1033 + if (bufUsed >= bufSize)
1035 + len = (bufSize * 3) / 2;
1036 + cp = realloc(bufBase, len);
1040 + bb_error_msg("No memory for buffer");
1047 + bufPtr = bufBase + bufUsed;
1051 + cc = read(fd, bufPtr, bufSize - bufUsed);
1068 + if (!insertLine(num, bufPtr, bufUsed))
1076 + charCount += bufUsed;
1081 + printf("%d lines%s, %d chars\n", lineCount,
1082 + (bufUsed ? " (incomplete)" : ""), charCount);
1089 + * Write the specified lines out to the specified file.
1090 + * Returns TRUE if successful, or FALSE on an error with a message output.
1093 +writeLines(const char * file, NUM num1, NUM num2)
1100 + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
1102 + bb_error_msg("Bad line range for write");
1110 + fd = creat(file, 0666);
1118 + printf("\"%s\", ", file);
1121 + lp = findLine(num1);
1130 + while (num1++ <= num2)
1132 + if (write(fd, lp->data, lp->len) != lp->len)
1140 + charCount += lp->len;
1145 + if (close(fd) < 0)
1152 + printf("%d lines, %d chars\n", lineCount, charCount);
1159 + * Print lines in a specified range.
1160 + * The last line printed becomes the current line.
1161 + * If expandFlag is TRUE, then the line is printed specially to
1162 + * show magic characters.
1165 +printLines(NUM num1, NUM num2, BOOL expandFlag)
1168 + const unsigned char * cp;
1172 + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
1174 + bb_error_msg("Bad line range for print");
1179 + lp = findLine(num1);
1184 + while (num1 <= num2)
1188 + write(1, lp->data, lp->len);
1189 + setCurNum(num1++);
1196 + * Show control characters and characters with the
1197 + * high bit set specially.
1202 + if ((count > 0) && (cp[count - 1] == '\n'))
1205 + while (count-- > 0)
1211 + fputs("M-", stdout);
1217 + fputc('^', stdout);
1223 + fputc('^', stdout);
1227 + fputc(ch, stdout);
1230 + fputs("$\n", stdout);
1232 + setCurNum(num1++);
1241 + * Insert a new line with the specified text.
1242 + * The line is inserted so as to become the specified line,
1243 + * thus pushing any existing and further lines down one.
1244 + * The inserted line is also set to become the current line.
1245 + * Returns TRUE if successful.
1248 +insertLine(NUM num, const char * data, LEN len)
1253 + if ((num < 1) || (num > lastNum + 1))
1255 + bb_error_msg("Inserting at bad line number");
1260 + newLp = (LINE *) malloc(sizeof(LINE) + len - 1);
1262 + if (newLp == NULL)
1264 + bb_error_msg("Failed to allocate memory for line");
1269 + memcpy(newLp->data, data, len);
1272 + if (num > lastNum)
1276 + lp = findLine(num);
1280 + free((char *) newLp);
1287 + newLp->prev = lp->prev;
1288 + lp->prev->next = newLp;
1294 + return setCurNum(num);
1299 + * Delete lines from the given range.
1302 +deleteLines(NUM num1, NUM num2)
1309 + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
1311 + bb_error_msg("Bad line numbers for delete");
1316 + lp = findLine(num1);
1321 + if ((curNum >= num1) && (curNum <= num2))
1323 + if (num2 < lastNum)
1324 + setCurNum(num2 + 1);
1325 + else if (num1 > 1)
1326 + setCurNum(num1 - 1);
1331 + count = num2 - num1 + 1;
1333 + if (curNum > num2)
1338 + while (count-- > 0)
1358 + * Search for a line which contains the specified string.
1359 + * If the string is NULL, then the previously searched for string
1360 + * is used. The currently searched for string is saved for future use.
1361 + * Returns the line number which matches, or 0 if there was no match
1362 + * with an error printed.
1365 +searchLines(const char * str, NUM num1, NUM num2)
1370 + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
1372 + bb_error_msg("Bad line numbers for search");
1379 + if (searchString[0] == '\0')
1381 + bb_error_msg("No previous search string");
1386 + str = searchString;
1389 + if (str != searchString)
1390 + strcpy(searchString, str);
1392 + len = strlen(str);
1394 + lp = findLine(num1);
1399 + while (num1 <= num2)
1401 + if (findString(lp, str, len, 0) >= 0)
1408 + bb_error_msg("Cannot find string \"%s\"", str);
1415 + * Return a pointer to the specified line number.
1423 + if ((num < 1) || (num > lastNum))
1425 + bb_error_msg("Line number %d does not exist", num);
1433 + curLine = lines.next;
1436 + if (num == curNum)
1442 + if (num < (curNum / 2))
1447 + else if (num > ((curNum + lastNum) / 2))
1453 + while (lnum < num)
1459 + while (lnum > num)
1470 + * Set the current line number.
1471 + * Returns TRUE if successful.
1478 + lp = findLine(num);