diff options
author | Rob Landley <rob@landley.net> | 2006-05-04 20:56:43 +0000 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2006-05-04 20:56:43 +0000 |
commit | 3b89039c25c8eb15435ed4f87bc8cb31c7941064 (patch) | |
tree | 0793ca73b2cbceca33e678571de77178364c5b6b | |
parent | 846fe0c045eedb2a2e5b3432648f4c1f04353631 (diff) | |
download | busybox-w32-3b89039c25c8eb15435ed4f87bc8cb31c7941064.tar.gz busybox-w32-3b89039c25c8eb15435ed4f87bc8cb31c7941064.tar.bz2 busybox-w32-3b89039c25c8eb15435ed4f87bc8cb31c7941064.zip |
It was sitting there, in the patches directory, for years. It was delete it
or apply it. It's small, simple, evil, part of SUSv3, and we can switch it
off.
-rw-r--r-- | editors/Config.in | 8 | ||||
-rw-r--r-- | editors/Makefile.in | 5 | ||||
-rw-r--r-- | editors/ed.c | 1363 | ||||
-rw-r--r-- | include/applets.h | 7 | ||||
-rw-r--r-- | include/usage.h | 3 | ||||
-rw-r--r-- | patches/ed.patch | 1489 |
6 files changed, 1381 insertions, 1494 deletions
diff --git a/editors/Config.in b/editors/Config.in index a30879c63..14c316c08 100644 --- a/editors/Config.in +++ b/editors/Config.in | |||
@@ -20,6 +20,14 @@ config CONFIG_FEATURE_AWK_MATH | |||
20 | Enable math functions of the Awk programming language. | 20 | Enable math functions of the Awk programming language. |
21 | NOTE: This will require libm to be present for linking. | 21 | NOTE: This will require libm to be present for linking. |
22 | 22 | ||
23 | config CONFIG_ED | ||
24 | bool "ed" | ||
25 | default n | ||
26 | help | ||
27 | The original 1970's Unix text editor, from the days of teletypes. | ||
28 | Small, simple, evil. Part of SUSv3. If you're not already using | ||
29 | this, you don't need it. | ||
30 | |||
23 | config CONFIG_PATCH | 31 | config CONFIG_PATCH |
24 | bool "patch" | 32 | bool "patch" |
25 | default n | 33 | default n |
diff --git a/editors/Makefile.in b/editors/Makefile.in index 805017dcc..9a46e32c2 100644 --- a/editors/Makefile.in +++ b/editors/Makefile.in | |||
@@ -11,8 +11,9 @@ endif | |||
11 | srcdir=$(top_srcdir)/editors | 11 | srcdir=$(top_srcdir)/editors |
12 | 12 | ||
13 | EDITOR-y:= | 13 | EDITOR-y:= |
14 | EDITOR-$(CONFIG_AWK) += awk.o | 14 | EDITOR-$(CONFIG_AWK) += awk.o |
15 | EDITOR-$(CONFIG_PATCH) += patch.o | 15 | EDITOR-$(CONFIG_ED) += ed.o |
16 | EDITOR-$(CONFIG_PATCH) += patch.o | ||
16 | EDITOR-$(CONFIG_SED) += sed.o | 17 | EDITOR-$(CONFIG_SED) += sed.o |
17 | EDITOR-$(CONFIG_VI) += vi.o | 18 | EDITOR-$(CONFIG_VI) += vi.o |
18 | 19 | ||
diff --git a/editors/ed.c b/editors/ed.c new file mode 100644 index 000000000..0414bfc9d --- /dev/null +++ b/editors/ed.c | |||
@@ -0,0 +1,1363 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2002 by David I. Bell | ||
3 | * Permission is granted to use, distribute, or modify this source, | ||
4 | * provided that this copyright notice remains intact. | ||
5 | * | ||
6 | * The "ed" built-in command (much simplified) | ||
7 | */ | ||
8 | |||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <unistd.h> | ||
12 | #include <fcntl.h> | ||
13 | #include <string.h> | ||
14 | #include <memory.h> | ||
15 | #include <time.h> | ||
16 | #include <ctype.h> | ||
17 | #include <sys/param.h> | ||
18 | #include <malloc.h> | ||
19 | #include "busybox.h" | ||
20 | |||
21 | #define USERSIZE 1024 /* max line length typed in by user */ | ||
22 | #define INITBUF_SIZE 1024 /* initial buffer size */ | ||
23 | typedef struct LINE { | ||
24 | struct LINE *next; | ||
25 | struct LINE *prev; | ||
26 | int len; | ||
27 | char data[1]; | ||
28 | } LINE; | ||
29 | |||
30 | static LINE lines, *curLine; | ||
31 | static int curNum, lastNum, marks[26], dirty; | ||
32 | static char *bufBase, *bufPtr, *fileName, searchString[USERSIZE]; | ||
33 | static int bufUsed, bufSize; | ||
34 | |||
35 | static void doCommands(void); | ||
36 | static void subCommand(const char *cmd, int num1, int num2); | ||
37 | static int getNum(const char **retcp, int *retHaveNum, int *retNum); | ||
38 | static int setCurNum(int num); | ||
39 | static int initEdit(void); | ||
40 | static void termEdit(void); | ||
41 | static void addLines(int num); | ||
42 | static int insertLine(int num, const char *data, int len); | ||
43 | static int deleteLines(int num1, int num2); | ||
44 | static int printLines(int num1, int num2, int expandFlag); | ||
45 | static int writeLines(const char *file, int num1, int num2); | ||
46 | static int readLines(const char *file, int num); | ||
47 | static int searchLines(const char *str, int num1, int num2); | ||
48 | static LINE *findLine(int num); | ||
49 | |||
50 | static int findString(const LINE *lp, const char * str, int len, int offset); | ||
51 | |||
52 | int ed_main(int argc, char **argv) | ||
53 | { | ||
54 | if (!initEdit()) | ||
55 | return EXIT_FAILURE; | ||
56 | |||
57 | if (argc > 1) { | ||
58 | fileName = strdup(argv[1]); | ||
59 | |||
60 | if (fileName == NULL) { | ||
61 | bb_error_msg("No memory"); | ||
62 | termEdit(); | ||
63 | return EXIT_SUCCESS; | ||
64 | } | ||
65 | |||
66 | if (!readLines(fileName, 1)) { | ||
67 | termEdit(); | ||
68 | return EXIT_SUCCESS; | ||
69 | } | ||
70 | |||
71 | if (lastNum) | ||
72 | setCurNum(1); | ||
73 | |||
74 | dirty = FALSE; | ||
75 | } | ||
76 | |||
77 | doCommands(); | ||
78 | |||
79 | termEdit(); | ||
80 | return EXIT_SUCCESS; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Read commands until we are told to stop. | ||
85 | */ | ||
86 | static void doCommands(void) | ||
87 | { | ||
88 | const char *cp; | ||
89 | char *endbuf, *newname, buf[USERSIZE]; | ||
90 | int len, num1, num2, have1, have2; | ||
91 | |||
92 | while (TRUE) | ||
93 | { | ||
94 | printf(": "); | ||
95 | fflush(stdout); | ||
96 | |||
97 | if (fgets(buf, sizeof(buf), stdin) == NULL) | ||
98 | return; | ||
99 | |||
100 | len = strlen(buf); | ||
101 | |||
102 | if (len == 0) | ||
103 | return; | ||
104 | |||
105 | endbuf = &buf[len - 1]; | ||
106 | |||
107 | if (*endbuf != '\n') | ||
108 | { | ||
109 | bb_error_msg("Command line too long"); | ||
110 | |||
111 | do | ||
112 | { | ||
113 | len = fgetc(stdin); | ||
114 | } | ||
115 | while ((len != EOF) && (len != '\n')); | ||
116 | |||
117 | continue; | ||
118 | } | ||
119 | |||
120 | while ((endbuf > buf) && isblank(endbuf[-1])) | ||
121 | endbuf--; | ||
122 | |||
123 | *endbuf = '\0'; | ||
124 | |||
125 | cp = buf; | ||
126 | |||
127 | while (isblank(*cp)) | ||
128 | cp++; | ||
129 | |||
130 | have1 = FALSE; | ||
131 | have2 = FALSE; | ||
132 | |||
133 | if ((curNum == 0) && (lastNum > 0)) | ||
134 | { | ||
135 | curNum = 1; | ||
136 | curLine = lines.next; | ||
137 | } | ||
138 | |||
139 | if (!getNum(&cp, &have1, &num1)) | ||
140 | continue; | ||
141 | |||
142 | while (isblank(*cp)) | ||
143 | cp++; | ||
144 | |||
145 | if (*cp == ',') | ||
146 | { | ||
147 | cp++; | ||
148 | |||
149 | if (!getNum(&cp, &have2, &num2)) | ||
150 | continue; | ||
151 | |||
152 | if (!have1) | ||
153 | num1 = 1; | ||
154 | |||
155 | if (!have2) | ||
156 | num2 = lastNum; | ||
157 | |||
158 | have1 = TRUE; | ||
159 | have2 = TRUE; | ||
160 | } | ||
161 | |||
162 | if (!have1) | ||
163 | num1 = curNum; | ||
164 | |||
165 | if (!have2) | ||
166 | num2 = num1; | ||
167 | |||
168 | switch (*cp++) | ||
169 | { | ||
170 | case 'a': | ||
171 | addLines(num1 + 1); | ||
172 | break; | ||
173 | |||
174 | case 'c': | ||
175 | deleteLines(num1, num2); | ||
176 | addLines(num1); | ||
177 | break; | ||
178 | |||
179 | case 'd': | ||
180 | deleteLines(num1, num2); | ||
181 | break; | ||
182 | |||
183 | case 'f': | ||
184 | if (*cp && !isblank(*cp)) | ||
185 | { | ||
186 | bb_error_msg("Bad file command"); | ||
187 | break; | ||
188 | } | ||
189 | |||
190 | while (isblank(*cp)) | ||
191 | cp++; | ||
192 | |||
193 | if (*cp == '\0') | ||
194 | { | ||
195 | if (fileName) | ||
196 | printf("\"%s\"\n", fileName); | ||
197 | else | ||
198 | printf("No file name\n"); | ||
199 | |||
200 | break; | ||
201 | } | ||
202 | |||
203 | newname = strdup(cp); | ||
204 | |||
205 | if (newname == NULL) | ||
206 | { | ||
207 | bb_error_msg("No memory for file name"); | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | if (fileName) | ||
212 | free(fileName); | ||
213 | |||
214 | fileName = newname; | ||
215 | break; | ||
216 | |||
217 | case 'i': | ||
218 | addLines(num1); | ||
219 | break; | ||
220 | |||
221 | case 'k': | ||
222 | while (isblank(*cp)) | ||
223 | cp++; | ||
224 | |||
225 | if ((*cp < 'a') || (*cp > 'a') || cp[1]) | ||
226 | { | ||
227 | bb_error_msg("Bad mark name"); | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | marks[*cp - 'a'] = num2; | ||
232 | break; | ||
233 | |||
234 | case 'l': | ||
235 | printLines(num1, num2, TRUE); | ||
236 | break; | ||
237 | |||
238 | case 'p': | ||
239 | printLines(num1, num2, FALSE); | ||
240 | break; | ||
241 | |||
242 | case 'q': | ||
243 | while (isblank(*cp)) | ||
244 | cp++; | ||
245 | |||
246 | if (have1 || *cp) | ||
247 | { | ||
248 | bb_error_msg("Bad quit command"); | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | if (!dirty) | ||
253 | return; | ||
254 | |||
255 | printf("Really quit? "); | ||
256 | fflush(stdout); | ||
257 | |||
258 | buf[0] = '\0'; | ||
259 | fgets(buf, sizeof(buf), stdin); | ||
260 | cp = buf; | ||
261 | |||
262 | while (isblank(*cp)) | ||
263 | cp++; | ||
264 | |||
265 | if ((*cp == 'y') || (*cp == 'Y')) | ||
266 | return; | ||
267 | |||
268 | break; | ||
269 | |||
270 | case 'r': | ||
271 | if (*cp && !isblank(*cp)) | ||
272 | { | ||
273 | bb_error_msg("Bad read command"); | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | while (isblank(*cp)) | ||
278 | cp++; | ||
279 | |||
280 | if (*cp == '\0') | ||
281 | { | ||
282 | bb_error_msg("No file name"); | ||
283 | break; | ||
284 | } | ||
285 | |||
286 | if (!have1) | ||
287 | num1 = lastNum; | ||
288 | |||
289 | if (readLines(cp, num1 + 1)) | ||
290 | break; | ||
291 | |||
292 | if (fileName == NULL) | ||
293 | fileName = strdup(cp); | ||
294 | |||
295 | break; | ||
296 | |||
297 | case 's': | ||
298 | subCommand(cp, num1, num2); | ||
299 | break; | ||
300 | |||
301 | case 'w': | ||
302 | if (*cp && !isblank(*cp)) | ||
303 | { | ||
304 | bb_error_msg("Bad write command"); | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | while (isblank(*cp)) | ||
309 | cp++; | ||
310 | |||
311 | if (!have1) { | ||
312 | num1 = 1; | ||
313 | num2 = lastNum; | ||
314 | } | ||
315 | |||
316 | if (*cp == '\0') | ||
317 | cp = fileName; | ||
318 | |||
319 | if (cp == NULL) | ||
320 | { | ||
321 | bb_error_msg("No file name specified"); | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | writeLines(cp, num1, num2); | ||
326 | break; | ||
327 | |||
328 | case 'z': | ||
329 | switch (*cp) | ||
330 | { | ||
331 | case '-': | ||
332 | printLines(curNum-21, curNum, FALSE); | ||
333 | break; | ||
334 | case '.': | ||
335 | printLines(curNum-11, curNum+10, FALSE); | ||
336 | break; | ||
337 | default: | ||
338 | printLines(curNum, curNum+21, FALSE); | ||
339 | break; | ||
340 | } | ||
341 | break; | ||
342 | |||
343 | case '.': | ||
344 | if (have1) | ||
345 | { | ||
346 | bb_error_msg("No arguments allowed"); | ||
347 | break; | ||
348 | } | ||
349 | |||
350 | printLines(curNum, curNum, FALSE); | ||
351 | break; | ||
352 | |||
353 | case '-': | ||
354 | if (setCurNum(curNum - 1)) | ||
355 | printLines(curNum, curNum, FALSE); | ||
356 | |||
357 | break; | ||
358 | |||
359 | case '=': | ||
360 | printf("%d\n", num1); | ||
361 | break; | ||
362 | |||
363 | case '\0': | ||
364 | if (have1) | ||
365 | { | ||
366 | printLines(num2, num2, FALSE); | ||
367 | break; | ||
368 | } | ||
369 | |||
370 | if (setCurNum(curNum + 1)) | ||
371 | printLines(curNum, curNum, FALSE); | ||
372 | |||
373 | break; | ||
374 | |||
375 | default: | ||
376 | bb_error_msg("Unimplemented command"); | ||
377 | break; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | |||
382 | |||
383 | /* | ||
384 | * Do the substitute command. | ||
385 | * The current line is set to the last substitution done. | ||
386 | */ | ||
387 | static void subCommand(const char * cmd, int num1, int num2) | ||
388 | { | ||
389 | char *cp, *oldStr, *newStr, buf[USERSIZE]; | ||
390 | int delim, oldLen, newLen, deltaLen, offset; | ||
391 | LINE *lp, *nlp; | ||
392 | int globalFlag, printFlag, didSub, needPrint; | ||
393 | |||
394 | if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
395 | { | ||
396 | bb_error_msg("Bad line range for substitute"); | ||
397 | |||
398 | return; | ||
399 | } | ||
400 | |||
401 | globalFlag = FALSE; | ||
402 | printFlag = FALSE; | ||
403 | didSub = FALSE; | ||
404 | needPrint = FALSE; | ||
405 | |||
406 | /* | ||
407 | * Copy the command so we can modify it. | ||
408 | */ | ||
409 | strcpy(buf, cmd); | ||
410 | cp = buf; | ||
411 | |||
412 | if (isblank(*cp) || (*cp == '\0')) | ||
413 | { | ||
414 | bb_error_msg("Bad delimiter for substitute"); | ||
415 | |||
416 | return; | ||
417 | } | ||
418 | |||
419 | delim = *cp++; | ||
420 | oldStr = cp; | ||
421 | |||
422 | cp = strchr(cp, delim); | ||
423 | |||
424 | if (cp == NULL) | ||
425 | { | ||
426 | bb_error_msg("Missing 2nd delimiter for substitute"); | ||
427 | |||
428 | return; | ||
429 | } | ||
430 | |||
431 | *cp++ = '\0'; | ||
432 | |||
433 | newStr = cp; | ||
434 | cp = strchr(cp, delim); | ||
435 | |||
436 | if (cp) | ||
437 | *cp++ = '\0'; | ||
438 | else | ||
439 | cp = ""; | ||
440 | |||
441 | while (*cp) switch (*cp++) | ||
442 | { | ||
443 | case 'g': | ||
444 | globalFlag = TRUE; | ||
445 | break; | ||
446 | |||
447 | case 'p': | ||
448 | printFlag = TRUE; | ||
449 | break; | ||
450 | |||
451 | default: | ||
452 | bb_error_msg("Unknown option for substitute"); | ||
453 | |||
454 | return; | ||
455 | } | ||
456 | |||
457 | if (*oldStr == '\0') | ||
458 | { | ||
459 | if (searchString[0] == '\0') | ||
460 | { | ||
461 | bb_error_msg("No previous search string"); | ||
462 | |||
463 | return; | ||
464 | } | ||
465 | |||
466 | oldStr = searchString; | ||
467 | } | ||
468 | |||
469 | if (oldStr != searchString) | ||
470 | strcpy(searchString, oldStr); | ||
471 | |||
472 | lp = findLine(num1); | ||
473 | |||
474 | if (lp == NULL) | ||
475 | return; | ||
476 | |||
477 | oldLen = strlen(oldStr); | ||
478 | newLen = strlen(newStr); | ||
479 | deltaLen = newLen - oldLen; | ||
480 | offset = 0; | ||
481 | nlp = NULL; | ||
482 | |||
483 | while (num1 <= num2) | ||
484 | { | ||
485 | offset = findString(lp, oldStr, oldLen, offset); | ||
486 | |||
487 | if (offset < 0) | ||
488 | { | ||
489 | if (needPrint) | ||
490 | { | ||
491 | printLines(num1, num1, FALSE); | ||
492 | needPrint = FALSE; | ||
493 | } | ||
494 | |||
495 | offset = 0; | ||
496 | lp = lp->next; | ||
497 | num1++; | ||
498 | |||
499 | continue; | ||
500 | } | ||
501 | |||
502 | needPrint = printFlag; | ||
503 | didSub = TRUE; | ||
504 | dirty = TRUE; | ||
505 | |||
506 | /* | ||
507 | * If the replacement string is the same size or shorter | ||
508 | * than the old string, then the substitution is easy. | ||
509 | */ | ||
510 | if (deltaLen <= 0) | ||
511 | { | ||
512 | memcpy(&lp->data[offset], newStr, newLen); | ||
513 | |||
514 | if (deltaLen) | ||
515 | { | ||
516 | memcpy(&lp->data[offset + newLen], | ||
517 | &lp->data[offset + oldLen], | ||
518 | lp->len - offset - oldLen); | ||
519 | |||
520 | lp->len += deltaLen; | ||
521 | } | ||
522 | |||
523 | offset += newLen; | ||
524 | |||
525 | if (globalFlag) | ||
526 | continue; | ||
527 | |||
528 | if (needPrint) | ||
529 | { | ||
530 | printLines(num1, num1, FALSE); | ||
531 | needPrint = FALSE; | ||
532 | } | ||
533 | |||
534 | lp = lp->next; | ||
535 | num1++; | ||
536 | |||
537 | continue; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * The new string is larger, so allocate a new line | ||
542 | * structure and use that. Link it in in place of | ||
543 | * the old line structure. | ||
544 | */ | ||
545 | nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen); | ||
546 | |||
547 | if (nlp == NULL) | ||
548 | { | ||
549 | bb_error_msg("Cannot get memory for line"); | ||
550 | |||
551 | return; | ||
552 | } | ||
553 | |||
554 | nlp->len = lp->len + deltaLen; | ||
555 | |||
556 | memcpy(nlp->data, lp->data, offset); | ||
557 | |||
558 | memcpy(&nlp->data[offset], newStr, newLen); | ||
559 | |||
560 | memcpy(&nlp->data[offset + newLen], | ||
561 | &lp->data[offset + oldLen], | ||
562 | lp->len - offset - oldLen); | ||
563 | |||
564 | nlp->next = lp->next; | ||
565 | nlp->prev = lp->prev; | ||
566 | nlp->prev->next = nlp; | ||
567 | nlp->next->prev = nlp; | ||
568 | |||
569 | if (curLine == lp) | ||
570 | curLine = nlp; | ||
571 | |||
572 | free(lp); | ||
573 | lp = nlp; | ||
574 | |||
575 | offset += newLen; | ||
576 | |||
577 | if (globalFlag) | ||
578 | continue; | ||
579 | |||
580 | if (needPrint) | ||
581 | { | ||
582 | printLines(num1, num1, FALSE); | ||
583 | needPrint = FALSE; | ||
584 | } | ||
585 | |||
586 | lp = lp->next; | ||
587 | num1++; | ||
588 | } | ||
589 | |||
590 | if (!didSub) | ||
591 | bb_error_msg("No substitutions found for \"%s\"", oldStr); | ||
592 | } | ||
593 | |||
594 | |||
595 | /* | ||
596 | * Search a line for the specified string starting at the specified | ||
597 | * offset in the line. Returns the offset of the found string, or -1. | ||
598 | */ | ||
599 | static int findString( const LINE * lp, const char * str, int len, int offset) | ||
600 | { | ||
601 | int left; | ||
602 | const char *cp, *ncp; | ||
603 | |||
604 | cp = &lp->data[offset]; | ||
605 | left = lp->len - offset; | ||
606 | |||
607 | while (left >= len) | ||
608 | { | ||
609 | ncp = memchr(cp, *str, left); | ||
610 | |||
611 | if (ncp == NULL) | ||
612 | return -1; | ||
613 | |||
614 | left -= (ncp - cp); | ||
615 | |||
616 | if (left < len) | ||
617 | return -1; | ||
618 | |||
619 | cp = ncp; | ||
620 | |||
621 | if (memcmp(cp, str, len) == 0) | ||
622 | return (cp - lp->data); | ||
623 | |||
624 | cp++; | ||
625 | left--; | ||
626 | } | ||
627 | |||
628 | return -1; | ||
629 | } | ||
630 | |||
631 | |||
632 | /* | ||
633 | * Add lines which are typed in by the user. | ||
634 | * The lines are inserted just before the specified line number. | ||
635 | * The lines are terminated by a line containing a single dot (ugly!), | ||
636 | * or by an end of file. | ||
637 | */ | ||
638 | static void addLines(int num) | ||
639 | { | ||
640 | int len; | ||
641 | char buf[USERSIZE + 1]; | ||
642 | |||
643 | while (fgets(buf, sizeof(buf), stdin)) | ||
644 | { | ||
645 | if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0')) | ||
646 | return; | ||
647 | |||
648 | len = strlen(buf); | ||
649 | |||
650 | if (len == 0) | ||
651 | return; | ||
652 | |||
653 | if (buf[len - 1] != '\n') | ||
654 | { | ||
655 | bb_error_msg("Line too long"); | ||
656 | |||
657 | do | ||
658 | { | ||
659 | len = fgetc(stdin); | ||
660 | } | ||
661 | while ((len != EOF) && (len != '\n')); | ||
662 | |||
663 | return; | ||
664 | } | ||
665 | |||
666 | if (!insertLine(num++, buf, len)) | ||
667 | return; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | |||
672 | /* | ||
673 | * Parse a line number argument if it is present. This is a sum | ||
674 | * or difference of numbers, '.', '$', 'x, or a search string. | ||
675 | * Returns TRUE if successful (whether or not there was a number). | ||
676 | * Returns FALSE if there was a parsing error, with a message output. | ||
677 | * Whether there was a number is returned indirectly, as is the number. | ||
678 | * The character pointer which stopped the scan is also returned. | ||
679 | */ | ||
680 | static int getNum(const char **retcp, int *retHaveNum, int *retNum) | ||
681 | { | ||
682 | const char *cp; | ||
683 | char *endStr, str[USERSIZE]; | ||
684 | int haveNum, value, num, sign; | ||
685 | |||
686 | cp = *retcp; | ||
687 | haveNum = FALSE; | ||
688 | value = 0; | ||
689 | sign = 1; | ||
690 | |||
691 | while (TRUE) | ||
692 | { | ||
693 | while (isblank(*cp)) | ||
694 | cp++; | ||
695 | |||
696 | switch (*cp) | ||
697 | { | ||
698 | case '.': | ||
699 | haveNum = TRUE; | ||
700 | num = curNum; | ||
701 | cp++; | ||
702 | break; | ||
703 | |||
704 | case '$': | ||
705 | haveNum = TRUE; | ||
706 | num = lastNum; | ||
707 | cp++; | ||
708 | break; | ||
709 | |||
710 | case '\'': | ||
711 | cp++; | ||
712 | |||
713 | if ((*cp < 'a') || (*cp > 'z')) | ||
714 | { | ||
715 | bb_error_msg("Bad mark name"); | ||
716 | |||
717 | return FALSE; | ||
718 | } | ||
719 | |||
720 | haveNum = TRUE; | ||
721 | num = marks[*cp++ - 'a']; | ||
722 | break; | ||
723 | |||
724 | case '/': | ||
725 | strcpy(str, ++cp); | ||
726 | endStr = strchr(str, '/'); | ||
727 | |||
728 | if (endStr) | ||
729 | { | ||
730 | *endStr++ = '\0'; | ||
731 | cp += (endStr - str); | ||
732 | } | ||
733 | else | ||
734 | cp = ""; | ||
735 | |||
736 | num = searchLines(str, curNum, lastNum); | ||
737 | |||
738 | if (num == 0) | ||
739 | return FALSE; | ||
740 | |||
741 | haveNum = TRUE; | ||
742 | break; | ||
743 | |||
744 | default: | ||
745 | if (!isdigit(*cp)) | ||
746 | { | ||
747 | *retcp = cp; | ||
748 | *retHaveNum = haveNum; | ||
749 | *retNum = value; | ||
750 | |||
751 | return TRUE; | ||
752 | } | ||
753 | |||
754 | num = 0; | ||
755 | |||
756 | while (isdigit(*cp)) | ||
757 | num = num * 10 + *cp++ - '0'; | ||
758 | |||
759 | haveNum = TRUE; | ||
760 | break; | ||
761 | } | ||
762 | |||
763 | value += num * sign; | ||
764 | |||
765 | while (isblank(*cp)) | ||
766 | cp++; | ||
767 | |||
768 | switch (*cp) | ||
769 | { | ||
770 | case '-': | ||
771 | sign = -1; | ||
772 | cp++; | ||
773 | break; | ||
774 | |||
775 | case '+': | ||
776 | sign = 1; | ||
777 | cp++; | ||
778 | break; | ||
779 | |||
780 | default: | ||
781 | *retcp = cp; | ||
782 | *retHaveNum = haveNum; | ||
783 | *retNum = value; | ||
784 | |||
785 | return TRUE; | ||
786 | } | ||
787 | } | ||
788 | } | ||
789 | |||
790 | |||
791 | /* | ||
792 | * Initialize everything for editing. | ||
793 | */ | ||
794 | static int initEdit(void) | ||
795 | { | ||
796 | int i; | ||
797 | |||
798 | bufSize = INITBUF_SIZE; | ||
799 | bufBase = malloc(bufSize); | ||
800 | |||
801 | if (bufBase == NULL) | ||
802 | { | ||
803 | bb_error_msg("No memory for buffer"); | ||
804 | |||
805 | return FALSE; | ||
806 | } | ||
807 | |||
808 | bufPtr = bufBase; | ||
809 | bufUsed = 0; | ||
810 | |||
811 | lines.next = &lines; | ||
812 | lines.prev = &lines; | ||
813 | |||
814 | curLine = NULL; | ||
815 | curNum = 0; | ||
816 | lastNum = 0; | ||
817 | dirty = FALSE; | ||
818 | fileName = NULL; | ||
819 | searchString[0] = '\0'; | ||
820 | |||
821 | for (i = 0; i < 26; i++) | ||
822 | marks[i] = 0; | ||
823 | |||
824 | return TRUE; | ||
825 | } | ||
826 | |||
827 | |||
828 | /* | ||
829 | * Finish editing. | ||
830 | */ | ||
831 | static void termEdit(void) | ||
832 | { | ||
833 | if (bufBase) | ||
834 | free(bufBase); | ||
835 | |||
836 | bufBase = NULL; | ||
837 | bufPtr = NULL; | ||
838 | bufSize = 0; | ||
839 | bufUsed = 0; | ||
840 | |||
841 | if (fileName) | ||
842 | free(fileName); | ||
843 | |||
844 | fileName = NULL; | ||
845 | |||
846 | searchString[0] = '\0'; | ||
847 | |||
848 | if (lastNum) | ||
849 | deleteLines(1, lastNum); | ||
850 | |||
851 | lastNum = 0; | ||
852 | curNum = 0; | ||
853 | curLine = NULL; | ||
854 | } | ||
855 | |||
856 | |||
857 | /* | ||
858 | * Read lines from a file at the specified line number. | ||
859 | * Returns TRUE if the file was successfully read. | ||
860 | */ | ||
861 | static int readLines(const char * file, int num) | ||
862 | { | ||
863 | int fd, cc; | ||
864 | int len, lineCount, charCount; | ||
865 | char *cp; | ||
866 | |||
867 | if ((num < 1) || (num > lastNum + 1)) | ||
868 | { | ||
869 | bb_error_msg("Bad line for read"); | ||
870 | |||
871 | return FALSE; | ||
872 | } | ||
873 | |||
874 | fd = open(file, 0); | ||
875 | |||
876 | if (fd < 0) | ||
877 | { | ||
878 | perror(file); | ||
879 | |||
880 | return FALSE; | ||
881 | } | ||
882 | |||
883 | bufPtr = bufBase; | ||
884 | bufUsed = 0; | ||
885 | lineCount = 0; | ||
886 | charCount = 0; | ||
887 | cc = 0; | ||
888 | |||
889 | printf("\"%s\", ", file); | ||
890 | fflush(stdout); | ||
891 | |||
892 | do | ||
893 | { | ||
894 | cp = memchr(bufPtr, '\n', bufUsed); | ||
895 | |||
896 | if (cp) | ||
897 | { | ||
898 | len = (cp - bufPtr) + 1; | ||
899 | |||
900 | if (!insertLine(num, bufPtr, len)) | ||
901 | { | ||
902 | close(fd); | ||
903 | |||
904 | return FALSE; | ||
905 | } | ||
906 | |||
907 | bufPtr += len; | ||
908 | bufUsed -= len; | ||
909 | charCount += len; | ||
910 | lineCount++; | ||
911 | num++; | ||
912 | |||
913 | continue; | ||
914 | } | ||
915 | |||
916 | if (bufPtr != bufBase) | ||
917 | { | ||
918 | memcpy(bufBase, bufPtr, bufUsed); | ||
919 | bufPtr = bufBase + bufUsed; | ||
920 | } | ||
921 | |||
922 | if (bufUsed >= bufSize) | ||
923 | { | ||
924 | len = (bufSize * 3) / 2; | ||
925 | cp = realloc(bufBase, len); | ||
926 | |||
927 | if (cp == NULL) | ||
928 | { | ||
929 | bb_error_msg("No memory for buffer"); | ||
930 | close(fd); | ||
931 | |||
932 | return FALSE; | ||
933 | } | ||
934 | |||
935 | bufBase = cp; | ||
936 | bufPtr = bufBase + bufUsed; | ||
937 | bufSize = len; | ||
938 | } | ||
939 | |||
940 | cc = read(fd, bufPtr, bufSize - bufUsed); | ||
941 | bufUsed += cc; | ||
942 | bufPtr = bufBase; | ||
943 | |||
944 | } | ||
945 | while (cc > 0); | ||
946 | |||
947 | if (cc < 0) | ||
948 | { | ||
949 | perror(file); | ||
950 | close(fd); | ||
951 | |||
952 | return FALSE; | ||
953 | } | ||
954 | |||
955 | if (bufUsed) | ||
956 | { | ||
957 | if (!insertLine(num, bufPtr, bufUsed)) | ||
958 | { | ||
959 | close(fd); | ||
960 | |||
961 | return -1; | ||
962 | } | ||
963 | |||
964 | lineCount++; | ||
965 | charCount += bufUsed; | ||
966 | } | ||
967 | |||
968 | close(fd); | ||
969 | |||
970 | printf("%d lines%s, %d chars\n", lineCount, | ||
971 | (bufUsed ? " (incomplete)" : ""), charCount); | ||
972 | |||
973 | return TRUE; | ||
974 | } | ||
975 | |||
976 | |||
977 | /* | ||
978 | * Write the specified lines out to the specified file. | ||
979 | * Returns TRUE if successful, or FALSE on an error with a message output. | ||
980 | */ | ||
981 | static int writeLines(const char * file, int num1, int num2) | ||
982 | { | ||
983 | LINE *lp; | ||
984 | int fd, lineCount, charCount; | ||
985 | |||
986 | if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
987 | { | ||
988 | bb_error_msg("Bad line range for write"); | ||
989 | |||
990 | return FALSE; | ||
991 | } | ||
992 | |||
993 | lineCount = 0; | ||
994 | charCount = 0; | ||
995 | |||
996 | fd = creat(file, 0666); | ||
997 | |||
998 | if (fd < 0) { | ||
999 | perror(file); | ||
1000 | |||
1001 | return FALSE; | ||
1002 | } | ||
1003 | |||
1004 | printf("\"%s\", ", file); | ||
1005 | fflush(stdout); | ||
1006 | |||
1007 | lp = findLine(num1); | ||
1008 | |||
1009 | if (lp == NULL) | ||
1010 | { | ||
1011 | close(fd); | ||
1012 | |||
1013 | return FALSE; | ||
1014 | } | ||
1015 | |||
1016 | while (num1++ <= num2) | ||
1017 | { | ||
1018 | if (write(fd, lp->data, lp->len) != lp->len) | ||
1019 | { | ||
1020 | perror(file); | ||
1021 | close(fd); | ||
1022 | |||
1023 | return FALSE; | ||
1024 | } | ||
1025 | |||
1026 | charCount += lp->len; | ||
1027 | lineCount++; | ||
1028 | lp = lp->next; | ||
1029 | } | ||
1030 | |||
1031 | if (close(fd) < 0) | ||
1032 | { | ||
1033 | perror(file); | ||
1034 | |||
1035 | return FALSE; | ||
1036 | } | ||
1037 | |||
1038 | printf("%d lines, %d chars\n", lineCount, charCount); | ||
1039 | |||
1040 | return TRUE; | ||
1041 | } | ||
1042 | |||
1043 | |||
1044 | /* | ||
1045 | * Print lines in a specified range. | ||
1046 | * The last line printed becomes the current line. | ||
1047 | * If expandFlag is TRUE, then the line is printed specially to | ||
1048 | * show magic characters. | ||
1049 | */ | ||
1050 | static int printLines(int num1, int num2, int expandFlag) | ||
1051 | { | ||
1052 | const LINE *lp; | ||
1053 | const char *cp; | ||
1054 | int ch, count; | ||
1055 | |||
1056 | if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1057 | { | ||
1058 | bb_error_msg("Bad line range for print"); | ||
1059 | |||
1060 | return FALSE; | ||
1061 | } | ||
1062 | |||
1063 | lp = findLine(num1); | ||
1064 | |||
1065 | if (lp == NULL) | ||
1066 | return FALSE; | ||
1067 | |||
1068 | while (num1 <= num2) | ||
1069 | { | ||
1070 | if (!expandFlag) | ||
1071 | { | ||
1072 | write(1, lp->data, lp->len); | ||
1073 | setCurNum(num1++); | ||
1074 | lp = lp->next; | ||
1075 | |||
1076 | continue; | ||
1077 | } | ||
1078 | |||
1079 | /* | ||
1080 | * Show control characters and characters with the | ||
1081 | * high bit set specially. | ||
1082 | */ | ||
1083 | cp = lp->data; | ||
1084 | count = lp->len; | ||
1085 | |||
1086 | if ((count > 0) && (cp[count - 1] == '\n')) | ||
1087 | count--; | ||
1088 | |||
1089 | while (count-- > 0) | ||
1090 | { | ||
1091 | ch = *cp++; | ||
1092 | |||
1093 | if (ch & 0x80) | ||
1094 | { | ||
1095 | fputs("M-", stdout); | ||
1096 | ch &= 0x7f; | ||
1097 | } | ||
1098 | |||
1099 | if (ch < ' ') | ||
1100 | { | ||
1101 | fputc('^', stdout); | ||
1102 | ch += '@'; | ||
1103 | } | ||
1104 | |||
1105 | if (ch == 0x7f) | ||
1106 | { | ||
1107 | fputc('^', stdout); | ||
1108 | ch = '?'; | ||
1109 | } | ||
1110 | |||
1111 | fputc(ch, stdout); | ||
1112 | } | ||
1113 | |||
1114 | fputs("$\n", stdout); | ||
1115 | |||
1116 | setCurNum(num1++); | ||
1117 | lp = lp->next; | ||
1118 | } | ||
1119 | |||
1120 | return TRUE; | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | /* | ||
1125 | * Insert a new line with the specified text. | ||
1126 | * The line is inserted so as to become the specified line, | ||
1127 | * thus pushing any existing and further lines down one. | ||
1128 | * The inserted line is also set to become the current line. | ||
1129 | * Returns TRUE if successful. | ||
1130 | */ | ||
1131 | static int insertLine(int num, const char * data, int len) | ||
1132 | { | ||
1133 | LINE *newLp, *lp; | ||
1134 | |||
1135 | if ((num < 1) || (num > lastNum + 1)) | ||
1136 | { | ||
1137 | bb_error_msg("Inserting at bad line number"); | ||
1138 | |||
1139 | return FALSE; | ||
1140 | } | ||
1141 | |||
1142 | newLp = (LINE *) malloc(sizeof(LINE) + len - 1); | ||
1143 | |||
1144 | if (newLp == NULL) | ||
1145 | { | ||
1146 | bb_error_msg("Failed to allocate memory for line"); | ||
1147 | |||
1148 | return FALSE; | ||
1149 | } | ||
1150 | |||
1151 | memcpy(newLp->data, data, len); | ||
1152 | newLp->len = len; | ||
1153 | |||
1154 | if (num > lastNum) | ||
1155 | lp = &lines; | ||
1156 | else | ||
1157 | { | ||
1158 | lp = findLine(num); | ||
1159 | |||
1160 | if (lp == NULL) | ||
1161 | { | ||
1162 | free((char *) newLp); | ||
1163 | |||
1164 | return FALSE; | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | newLp->next = lp; | ||
1169 | newLp->prev = lp->prev; | ||
1170 | lp->prev->next = newLp; | ||
1171 | lp->prev = newLp; | ||
1172 | |||
1173 | lastNum++; | ||
1174 | dirty = TRUE; | ||
1175 | |||
1176 | return setCurNum(num); | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | /* | ||
1181 | * Delete lines from the given range. | ||
1182 | */ | ||
1183 | static int deleteLines(int num1, int num2) | ||
1184 | { | ||
1185 | LINE *lp, *nlp, *plp; | ||
1186 | int count; | ||
1187 | |||
1188 | if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1189 | { | ||
1190 | bb_error_msg("Bad line numbers for delete"); | ||
1191 | |||
1192 | return FALSE; | ||
1193 | } | ||
1194 | |||
1195 | lp = findLine(num1); | ||
1196 | |||
1197 | if (lp == NULL) | ||
1198 | return FALSE; | ||
1199 | |||
1200 | if ((curNum >= num1) && (curNum <= num2)) | ||
1201 | { | ||
1202 | if (num2 < lastNum) | ||
1203 | setCurNum(num2 + 1); | ||
1204 | else if (num1 > 1) | ||
1205 | setCurNum(num1 - 1); | ||
1206 | else | ||
1207 | curNum = 0; | ||
1208 | } | ||
1209 | |||
1210 | count = num2 - num1 + 1; | ||
1211 | |||
1212 | if (curNum > num2) | ||
1213 | curNum -= count; | ||
1214 | |||
1215 | lastNum -= count; | ||
1216 | |||
1217 | while (count-- > 0) | ||
1218 | { | ||
1219 | nlp = lp->next; | ||
1220 | plp = lp->prev; | ||
1221 | plp->next = nlp; | ||
1222 | nlp->prev = plp; | ||
1223 | lp->next = NULL; | ||
1224 | lp->prev = NULL; | ||
1225 | lp->len = 0; | ||
1226 | free(lp); | ||
1227 | lp = nlp; | ||
1228 | } | ||
1229 | |||
1230 | dirty = TRUE; | ||
1231 | |||
1232 | return TRUE; | ||
1233 | } | ||
1234 | |||
1235 | |||
1236 | /* | ||
1237 | * Search for a line which contains the specified string. | ||
1238 | * If the string is NULL, then the previously searched for string | ||
1239 | * is used. The currently searched for string is saved for future use. | ||
1240 | * Returns the line number which matches, or 0 if there was no match | ||
1241 | * with an error printed. | ||
1242 | */ | ||
1243 | static int searchLines(const char *str, int num1, int num2) | ||
1244 | { | ||
1245 | const LINE *lp; | ||
1246 | int len; | ||
1247 | |||
1248 | if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1249 | { | ||
1250 | bb_error_msg("Bad line numbers for search"); | ||
1251 | |||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | if (*str == '\0') | ||
1256 | { | ||
1257 | if (searchString[0] == '\0') | ||
1258 | { | ||
1259 | bb_error_msg("No previous search string"); | ||
1260 | |||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | str = searchString; | ||
1265 | } | ||
1266 | |||
1267 | if (str != searchString) | ||
1268 | strcpy(searchString, str); | ||
1269 | |||
1270 | len = strlen(str); | ||
1271 | |||
1272 | lp = findLine(num1); | ||
1273 | |||
1274 | if (lp == NULL) | ||
1275 | return 0; | ||
1276 | |||
1277 | while (num1 <= num2) | ||
1278 | { | ||
1279 | if (findString(lp, str, len, 0) >= 0) | ||
1280 | return num1; | ||
1281 | |||
1282 | num1++; | ||
1283 | lp = lp->next; | ||
1284 | } | ||
1285 | |||
1286 | bb_error_msg("Cannot find string \"%s\"", str); | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | |||
1291 | |||
1292 | /* | ||
1293 | * Return a pointer to the specified line number. | ||
1294 | */ | ||
1295 | static LINE *findLine(int num) | ||
1296 | { | ||
1297 | LINE *lp; | ||
1298 | int lnum; | ||
1299 | |||
1300 | if ((num < 1) || (num > lastNum)) | ||
1301 | { | ||
1302 | bb_error_msg("Line number %d does not exist", num); | ||
1303 | |||
1304 | return NULL; | ||
1305 | } | ||
1306 | |||
1307 | if (curNum <= 0) | ||
1308 | { | ||
1309 | curNum = 1; | ||
1310 | curLine = lines.next; | ||
1311 | } | ||
1312 | |||
1313 | if (num == curNum) | ||
1314 | return curLine; | ||
1315 | |||
1316 | lp = curLine; | ||
1317 | lnum = curNum; | ||
1318 | |||
1319 | if (num < (curNum / 2)) | ||
1320 | { | ||
1321 | lp = lines.next; | ||
1322 | lnum = 1; | ||
1323 | } | ||
1324 | else if (num > ((curNum + lastNum) / 2)) | ||
1325 | { | ||
1326 | lp = lines.prev; | ||
1327 | lnum = lastNum; | ||
1328 | } | ||
1329 | |||
1330 | while (lnum < num) | ||
1331 | { | ||
1332 | lp = lp->next; | ||
1333 | lnum++; | ||
1334 | } | ||
1335 | |||
1336 | while (lnum > num) | ||
1337 | { | ||
1338 | lp = lp->prev; | ||
1339 | lnum--; | ||
1340 | } | ||
1341 | |||
1342 | return lp; | ||
1343 | } | ||
1344 | |||
1345 | |||
1346 | /* | ||
1347 | * Set the current line number. | ||
1348 | * Returns TRUE if successful. | ||
1349 | */ | ||
1350 | static int setCurNum(int num) | ||
1351 | { | ||
1352 | LINE *lp; | ||
1353 | |||
1354 | lp = findLine(num); | ||
1355 | |||
1356 | if (lp == NULL) | ||
1357 | return FALSE; | ||
1358 | |||
1359 | curNum = num; | ||
1360 | curLine = lp; | ||
1361 | |||
1362 | return TRUE; | ||
1363 | } | ||
diff --git a/include/applets.h b/include/applets.h index 06bd9e7f5..b83e8ed79 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -95,10 +95,11 @@ USE_DPKG(APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | |||
95 | USE_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dpkg_deb)) | 95 | USE_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dpkg_deb)) |
96 | USE_DU(APPLET(du, du_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 96 | USE_DU(APPLET(du, du_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
97 | USE_DUMPKMAP(APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 97 | USE_DUMPKMAP(APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
98 | USE_DUMPLEASES(APPLET(dumpleases, dumpleases_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 98 | //USE_DUMPLEASES(APPLET(dumpleases, dumpleases_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
99 | USE_E2FSCK(APPLET(e2fsck, e2fsck_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 99 | USE_E2FSCK(APPLET(e2fsck, e2fsck_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
100 | USE_E2LABEL(APPLET_NOUSAGE(e2label, tune2fs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 100 | USE_E2LABEL(APPLET_NOUSAGE(e2label, tune2fs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
101 | USE_ECHO(APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 101 | USE_ECHO(APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
102 | USE_ED(APPLET(ed, ed_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | ||
102 | USE_FEATURE_GREP_EGREP_ALIAS(APPLET_NOUSAGE(egrep, grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 103 | USE_FEATURE_GREP_EGREP_ALIAS(APPLET_NOUSAGE(egrep, grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
103 | USE_EJECT(APPLET(eject, eject_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 104 | USE_EJECT(APPLET(eject, eject_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
104 | USE_ENV(APPLET(env, env_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 105 | USE_ENV(APPLET(env, env_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
@@ -273,8 +274,8 @@ USE_TRACEROUTE(APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN, _BB_SUID_MAY | |||
273 | USE_TRUE(APPLET(true, true_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 274 | USE_TRUE(APPLET(true, true_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
274 | USE_TTY(APPLET(tty, tty_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 275 | USE_TTY(APPLET(tty, tty_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
275 | USE_TUNE2FS(APPLET(tune2fs, tune2fs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 276 | USE_TUNE2FS(APPLET(tune2fs, tune2fs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
276 | USE_UDHCPC(APPLET(udhcpc, udhcpc_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 277 | //USE_UDHCPC(APPLET(udhcpc, udhcpc_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
277 | USE_UDHCPD(APPLET(udhcpd, udhcpd_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | 278 | //USE_UDHCPD(APPLET(udhcpd, udhcpd_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) |
278 | USE_UMOUNT(APPLET(umount, umount_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 279 | USE_UMOUNT(APPLET(umount, umount_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
279 | USE_UNAME(APPLET(uname, uname_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 280 | USE_UNAME(APPLET(uname, uname_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
280 | USE_UNCOMPRESS(APPLET(uncompress, uncompress_main, _BB_DIR_BIN, _BB_SUID_NEVER)) | 281 | USE_UNCOMPRESS(APPLET(uncompress, uncompress_main, _BB_DIR_BIN, _BB_SUID_NEVER)) |
diff --git a/include/usage.h b/include/usage.h index 65a7874fa..d09c1108e 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -626,6 +626,9 @@ USE_FEATURE_DATE_ISOFMT( \ | |||
626 | "Options:\n" \ | 626 | "Options:\n" \ |
627 | "\t-t\tclose tray" | 627 | "\t-t\tclose tray" |
628 | 628 | ||
629 | #define ed_trivial_usage "" | ||
630 | #define ed_full_usage "" | ||
631 | |||
629 | #define env_trivial_usage \ | 632 | #define env_trivial_usage \ |
630 | "[-iu] [-] [name=value]... [command]" | 633 | "[-iu] [-] [name=value]... [command]" |
631 | #define env_full_usage \ | 634 | #define env_full_usage \ |
diff --git a/patches/ed.patch b/patches/ed.patch deleted file mode 100644 index 6d51830a5..000000000 --- a/patches/ed.patch +++ /dev/null | |||
@@ -1,1489 +0,0 @@ | |||
1 | Index: editors/Makefile.in | ||
2 | =================================================================== | ||
3 | --- editors/Makefile.in (revision 10144) | ||
4 | +++ editors/Makefile.in (working copy) | ||
5 | @@ -24,8 +24,9 @@ | ||
6 | srcdir=$(top_srcdir)/editors | ||
7 | |||
8 | EDITOR-y:= | ||
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) | ||
21 | @@ -20,6 +20,12 @@ | ||
22 | Enable math functions of the Awk programming language. | ||
23 | NOTE: This will require libm to be present for linking. | ||
24 | |||
25 | +config CONFIG_ED | ||
26 | + bool "ed" | ||
27 | + default n | ||
28 | + help | ||
29 | + ed | ||
30 | + | ||
31 | config CONFIG_PATCH | ||
32 | bool "patch" | ||
33 | default n | ||
34 | Index: include/usage.h | ||
35 | =================================================================== | ||
36 | --- include/usage.h (revision 10151) | ||
37 | +++ include/usage.h (working copy) | ||
38 | @@ -556,6 +561,9 @@ | ||
39 | "$ echo \"Erik\\nis\\ncool\"\n" \ | ||
40 | "Erik\\nis\\ncool\n") | ||
41 | |||
42 | +#define ed_trivial_usage "" | ||
43 | +#define ed_full_usage "" | ||
44 | + | ||
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) | ||
52 | @@ -179,6 +179,9 @@ | ||
53 | #ifdef CONFIG_ECHO | ||
54 | APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
55 | #endif | ||
56 | +#ifdef CONFIG_ED | ||
57 | + APPLET(ed, ed_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
58 | +#endif | ||
59 | #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS) | ||
60 | APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
61 | #endif | ||
62 | --- /dev/null 2005-04-24 01:00:01.350003056 -0400 | ||
63 | +++ ed.c 2005-04-24 01:38:51.000000000 -0400 | ||
64 | @@ -0,0 +1,1425 @@ | ||
65 | +/* | ||
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. | ||
69 | + * | ||
70 | + * The "ed" built-in command (much simplified) | ||
71 | + */ | ||
72 | + | ||
73 | +#include <stdio.h> | ||
74 | +#include <stdlib.h> | ||
75 | +#include <unistd.h> | ||
76 | +#include <fcntl.h> | ||
77 | +#include <string.h> | ||
78 | +#include <memory.h> | ||
79 | +#include <time.h> | ||
80 | +#include <ctype.h> | ||
81 | +#include <sys/param.h> | ||
82 | +#include <malloc.h> | ||
83 | +#include "busybox.h" | ||
84 | + | ||
85 | +#define USERSIZE 1024 /* max line length typed in by user */ | ||
86 | +#define INITBUF_SIZE 1024 /* initial buffer size */ | ||
87 | + | ||
88 | +typedef int BOOL; | ||
89 | +typedef int NUM; | ||
90 | +typedef int LEN; | ||
91 | + | ||
92 | +typedef struct LINE LINE; | ||
93 | +struct LINE { | ||
94 | + LINE *next; | ||
95 | + LINE *prev; | ||
96 | + LEN len; | ||
97 | + char data[1]; | ||
98 | +}; | ||
99 | + | ||
100 | +static LINE lines; | ||
101 | +static LINE *curLine; | ||
102 | +static NUM curNum; | ||
103 | +static NUM lastNum; | ||
104 | +static NUM marks[26]; | ||
105 | +static BOOL dirty; | ||
106 | +static char *fileName; | ||
107 | +static char searchString[USERSIZE]; | ||
108 | + | ||
109 | +static char *bufBase; | ||
110 | +static char *bufPtr; | ||
111 | +static LEN bufUsed; | ||
112 | +static LEN bufSize; | ||
113 | + | ||
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); | ||
128 | + | ||
129 | +static LEN findString(const LINE * lp, const char * str, LEN len, LEN offset); | ||
130 | + | ||
131 | +int ed_main(int argc, char **argv) | ||
132 | +{ | ||
133 | + if (!initEdit()) | ||
134 | + return EXIT_FAILURE; | ||
135 | + | ||
136 | + if (argc > 1) { | ||
137 | + fileName = strdup(argv[1]); | ||
138 | + | ||
139 | + if (fileName == NULL) { | ||
140 | + bb_error_msg("No memory"); | ||
141 | + termEdit(); | ||
142 | + return EXIT_SUCCESS; | ||
143 | + } | ||
144 | + | ||
145 | + if (!readLines(fileName, 1)) { | ||
146 | + termEdit(); | ||
147 | + return EXIT_SUCCESS; | ||
148 | + } | ||
149 | + | ||
150 | + if (lastNum) | ||
151 | + setCurNum(1); | ||
152 | + | ||
153 | + dirty = FALSE; | ||
154 | + } | ||
155 | + | ||
156 | + doCommands(); | ||
157 | + | ||
158 | + termEdit(); | ||
159 | + return EXIT_SUCCESS; | ||
160 | +} | ||
161 | + | ||
162 | +/* | ||
163 | + * Read commands until we are told to stop. | ||
164 | + */ | ||
165 | +static void doCommands(void) | ||
166 | +{ | ||
167 | + const char * cp; | ||
168 | + char * endbuf; | ||
169 | + char * newname; | ||
170 | + int len; | ||
171 | + NUM num1; | ||
172 | + NUM num2; | ||
173 | + BOOL have1; | ||
174 | + BOOL have2; | ||
175 | + char buf[USERSIZE]; | ||
176 | + | ||
177 | + while (TRUE) | ||
178 | + { | ||
179 | + printf(": "); | ||
180 | + fflush(stdout); | ||
181 | + | ||
182 | + if (fgets(buf, sizeof(buf), stdin) == NULL) | ||
183 | + return; | ||
184 | + | ||
185 | + len = strlen(buf); | ||
186 | + | ||
187 | + if (len == 0) | ||
188 | + return; | ||
189 | + | ||
190 | + endbuf = &buf[len - 1]; | ||
191 | + | ||
192 | + if (*endbuf != '\n') | ||
193 | + { | ||
194 | + bb_error_msg("Command line too long"); | ||
195 | + | ||
196 | + do | ||
197 | + { | ||
198 | + len = fgetc(stdin); | ||
199 | + } | ||
200 | + while ((len != EOF) && (len != '\n')); | ||
201 | + | ||
202 | + continue; | ||
203 | + } | ||
204 | + | ||
205 | + while ((endbuf > buf) && isblank(endbuf[-1])) | ||
206 | + endbuf--; | ||
207 | + | ||
208 | + *endbuf = '\0'; | ||
209 | + | ||
210 | + cp = buf; | ||
211 | + | ||
212 | + while (isblank(*cp)) | ||
213 | + cp++; | ||
214 | + | ||
215 | + have1 = FALSE; | ||
216 | + have2 = FALSE; | ||
217 | + | ||
218 | + if ((curNum == 0) && (lastNum > 0)) | ||
219 | + { | ||
220 | + curNum = 1; | ||
221 | + curLine = lines.next; | ||
222 | + } | ||
223 | + | ||
224 | + if (!getNum(&cp, &have1, &num1)) | ||
225 | + continue; | ||
226 | + | ||
227 | + while (isblank(*cp)) | ||
228 | + cp++; | ||
229 | + | ||
230 | + if (*cp == ',') | ||
231 | + { | ||
232 | + cp++; | ||
233 | + | ||
234 | + if (!getNum(&cp, &have2, &num2)) | ||
235 | + continue; | ||
236 | + | ||
237 | + if (!have1) | ||
238 | + num1 = 1; | ||
239 | + | ||
240 | + if (!have2) | ||
241 | + num2 = lastNum; | ||
242 | + | ||
243 | + have1 = TRUE; | ||
244 | + have2 = TRUE; | ||
245 | + } | ||
246 | + | ||
247 | + if (!have1) | ||
248 | + num1 = curNum; | ||
249 | + | ||
250 | + if (!have2) | ||
251 | + num2 = num1; | ||
252 | + | ||
253 | + switch (*cp++) | ||
254 | + { | ||
255 | + case 'a': | ||
256 | + addLines(num1 + 1); | ||
257 | + break; | ||
258 | + | ||
259 | + case 'c': | ||
260 | + deleteLines(num1, num2); | ||
261 | + addLines(num1); | ||
262 | + break; | ||
263 | + | ||
264 | + case 'd': | ||
265 | + deleteLines(num1, num2); | ||
266 | + break; | ||
267 | + | ||
268 | + case 'f': | ||
269 | + if (*cp && !isblank(*cp)) | ||
270 | + { | ||
271 | + bb_error_msg("Bad file command"); | ||
272 | + break; | ||
273 | + } | ||
274 | + | ||
275 | + while (isblank(*cp)) | ||
276 | + cp++; | ||
277 | + | ||
278 | + if (*cp == '\0') | ||
279 | + { | ||
280 | + if (fileName) | ||
281 | + printf("\"%s\"\n", fileName); | ||
282 | + else | ||
283 | + printf("No file name\n"); | ||
284 | + | ||
285 | + break; | ||
286 | + } | ||
287 | + | ||
288 | + newname = strdup(cp); | ||
289 | + | ||
290 | + if (newname == NULL) | ||
291 | + { | ||
292 | + bb_error_msg("No memory for file name"); | ||
293 | + break; | ||
294 | + } | ||
295 | + | ||
296 | + if (fileName) | ||
297 | + free(fileName); | ||
298 | + | ||
299 | + fileName = newname; | ||
300 | + break; | ||
301 | + | ||
302 | + case 'i': | ||
303 | + addLines(num1); | ||
304 | + break; | ||
305 | + | ||
306 | + case 'k': | ||
307 | + while (isblank(*cp)) | ||
308 | + cp++; | ||
309 | + | ||
310 | + if ((*cp < 'a') || (*cp > 'a') || cp[1]) | ||
311 | + { | ||
312 | + bb_error_msg("Bad mark name"); | ||
313 | + break; | ||
314 | + } | ||
315 | + | ||
316 | + marks[*cp - 'a'] = num2; | ||
317 | + break; | ||
318 | + | ||
319 | + case 'l': | ||
320 | + printLines(num1, num2, TRUE); | ||
321 | + break; | ||
322 | + | ||
323 | + case 'p': | ||
324 | + printLines(num1, num2, FALSE); | ||
325 | + break; | ||
326 | + | ||
327 | + case 'q': | ||
328 | + while (isblank(*cp)) | ||
329 | + cp++; | ||
330 | + | ||
331 | + if (have1 || *cp) | ||
332 | + { | ||
333 | + bb_error_msg("Bad quit command"); | ||
334 | + break; | ||
335 | + } | ||
336 | + | ||
337 | + if (!dirty) | ||
338 | + return; | ||
339 | + | ||
340 | + printf("Really quit? "); | ||
341 | + fflush(stdout); | ||
342 | + | ||
343 | + buf[0] = '\0'; | ||
344 | + fgets(buf, sizeof(buf), stdin); | ||
345 | + cp = buf; | ||
346 | + | ||
347 | + while (isblank(*cp)) | ||
348 | + cp++; | ||
349 | + | ||
350 | + if ((*cp == 'y') || (*cp == 'Y')) | ||
351 | + return; | ||
352 | + | ||
353 | + break; | ||
354 | + | ||
355 | + case 'r': | ||
356 | + if (*cp && !isblank(*cp)) | ||
357 | + { | ||
358 | + bb_error_msg("Bad read command"); | ||
359 | + break; | ||
360 | + } | ||
361 | + | ||
362 | + while (isblank(*cp)) | ||
363 | + cp++; | ||
364 | + | ||
365 | + if (*cp == '\0') | ||
366 | + { | ||
367 | + bb_error_msg("No file name"); | ||
368 | + break; | ||
369 | + } | ||
370 | + | ||
371 | + if (!have1) | ||
372 | + num1 = lastNum; | ||
373 | + | ||
374 | + if (readLines(cp, num1 + 1)) | ||
375 | + break; | ||
376 | + | ||
377 | + if (fileName == NULL) | ||
378 | + fileName = strdup(cp); | ||
379 | + | ||
380 | + break; | ||
381 | + | ||
382 | + case 's': | ||
383 | + subCommand(cp, num1, num2); | ||
384 | + break; | ||
385 | + | ||
386 | + case 'w': | ||
387 | + if (*cp && !isblank(*cp)) | ||
388 | + { | ||
389 | + bb_error_msg("Bad write command"); | ||
390 | + break; | ||
391 | + } | ||
392 | + | ||
393 | + while (isblank(*cp)) | ||
394 | + cp++; | ||
395 | + | ||
396 | + if (!have1) { | ||
397 | + num1 = 1; | ||
398 | + num2 = lastNum; | ||
399 | + } | ||
400 | + | ||
401 | + if (*cp == '\0') | ||
402 | + cp = fileName; | ||
403 | + | ||
404 | + if (cp == NULL) | ||
405 | + { | ||
406 | + bb_error_msg("No file name specified"); | ||
407 | + break; | ||
408 | + } | ||
409 | + | ||
410 | + writeLines(cp, num1, num2); | ||
411 | + break; | ||
412 | + | ||
413 | + case 'z': | ||
414 | + switch (*cp) | ||
415 | + { | ||
416 | + case '-': | ||
417 | + printLines(curNum-21, curNum, FALSE); | ||
418 | + break; | ||
419 | + case '.': | ||
420 | + printLines(curNum-11, curNum+10, FALSE); | ||
421 | + break; | ||
422 | + default: | ||
423 | + printLines(curNum, curNum+21, FALSE); | ||
424 | + break; | ||
425 | + } | ||
426 | + break; | ||
427 | + | ||
428 | + case '.': | ||
429 | + if (have1) | ||
430 | + { | ||
431 | + bb_error_msg("No arguments allowed"); | ||
432 | + break; | ||
433 | + } | ||
434 | + | ||
435 | + printLines(curNum, curNum, FALSE); | ||
436 | + break; | ||
437 | + | ||
438 | + case '-': | ||
439 | + if (setCurNum(curNum - 1)) | ||
440 | + printLines(curNum, curNum, FALSE); | ||
441 | + | ||
442 | + break; | ||
443 | + | ||
444 | + case '=': | ||
445 | + printf("%d\n", num1); | ||
446 | + break; | ||
447 | + | ||
448 | + case '\0': | ||
449 | + if (have1) | ||
450 | + { | ||
451 | + printLines(num2, num2, FALSE); | ||
452 | + break; | ||
453 | + } | ||
454 | + | ||
455 | + if (setCurNum(curNum + 1)) | ||
456 | + printLines(curNum, curNum, FALSE); | ||
457 | + | ||
458 | + break; | ||
459 | + | ||
460 | + default: | ||
461 | + bb_error_msg("Unimplemented command"); | ||
462 | + break; | ||
463 | + } | ||
464 | + } | ||
465 | +} | ||
466 | + | ||
467 | + | ||
468 | +/* | ||
469 | + * Do the substitute command. | ||
470 | + * The current line is set to the last substitution done. | ||
471 | + */ | ||
472 | +static void | ||
473 | +subCommand(const char * cmd, NUM num1, NUM num2) | ||
474 | +{ | ||
475 | + int delim; | ||
476 | + char * cp; | ||
477 | + char * oldStr; | ||
478 | + char * newStr; | ||
479 | + LEN oldLen; | ||
480 | + LEN newLen; | ||
481 | + LEN deltaLen; | ||
482 | + LEN offset; | ||
483 | + LINE * lp; | ||
484 | + LINE * nlp; | ||
485 | + BOOL globalFlag; | ||
486 | + BOOL printFlag; | ||
487 | + BOOL didSub; | ||
488 | + BOOL needPrint; | ||
489 | + char buf[USERSIZE]; | ||
490 | + | ||
491 | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
492 | + { | ||
493 | + bb_error_msg("Bad line range for substitute"); | ||
494 | + | ||
495 | + return; | ||
496 | + } | ||
497 | + | ||
498 | + globalFlag = FALSE; | ||
499 | + printFlag = FALSE; | ||
500 | + didSub = FALSE; | ||
501 | + needPrint = FALSE; | ||
502 | + | ||
503 | + /* | ||
504 | + * Copy the command so we can modify it. | ||
505 | + */ | ||
506 | + strcpy(buf, cmd); | ||
507 | + cp = buf; | ||
508 | + | ||
509 | + if (isblank(*cp) || (*cp == '\0')) | ||
510 | + { | ||
511 | + bb_error_msg("Bad delimiter for substitute"); | ||
512 | + | ||
513 | + return; | ||
514 | + } | ||
515 | + | ||
516 | + delim = *cp++; | ||
517 | + oldStr = cp; | ||
518 | + | ||
519 | + cp = strchr(cp, delim); | ||
520 | + | ||
521 | + if (cp == NULL) | ||
522 | + { | ||
523 | + bb_error_msg("Missing 2nd delimiter for substitute"); | ||
524 | + | ||
525 | + return; | ||
526 | + } | ||
527 | + | ||
528 | + *cp++ = '\0'; | ||
529 | + | ||
530 | + newStr = cp; | ||
531 | + cp = strchr(cp, delim); | ||
532 | + | ||
533 | + if (cp) | ||
534 | + *cp++ = '\0'; | ||
535 | + else | ||
536 | + cp = ""; | ||
537 | + | ||
538 | + while (*cp) switch (*cp++) | ||
539 | + { | ||
540 | + case 'g': | ||
541 | + globalFlag = TRUE; | ||
542 | + break; | ||
543 | + | ||
544 | + case 'p': | ||
545 | + printFlag = TRUE; | ||
546 | + break; | ||
547 | + | ||
548 | + default: | ||
549 | + bb_error_msg("Unknown option for substitute"); | ||
550 | + | ||
551 | + return; | ||
552 | + } | ||
553 | + | ||
554 | + if (*oldStr == '\0') | ||
555 | + { | ||
556 | + if (searchString[0] == '\0') | ||
557 | + { | ||
558 | + bb_error_msg("No previous search string"); | ||
559 | + | ||
560 | + return; | ||
561 | + } | ||
562 | + | ||
563 | + oldStr = searchString; | ||
564 | + } | ||
565 | + | ||
566 | + if (oldStr != searchString) | ||
567 | + strcpy(searchString, oldStr); | ||
568 | + | ||
569 | + lp = findLine(num1); | ||
570 | + | ||
571 | + if (lp == NULL) | ||
572 | + return; | ||
573 | + | ||
574 | + oldLen = strlen(oldStr); | ||
575 | + newLen = strlen(newStr); | ||
576 | + deltaLen = newLen - oldLen; | ||
577 | + offset = 0; | ||
578 | + nlp = NULL; | ||
579 | + | ||
580 | + while (num1 <= num2) | ||
581 | + { | ||
582 | + offset = findString(lp, oldStr, oldLen, offset); | ||
583 | + | ||
584 | + if (offset < 0) | ||
585 | + { | ||
586 | + if (needPrint) | ||
587 | + { | ||
588 | + printLines(num1, num1, FALSE); | ||
589 | + needPrint = FALSE; | ||
590 | + } | ||
591 | + | ||
592 | + offset = 0; | ||
593 | + lp = lp->next; | ||
594 | + num1++; | ||
595 | + | ||
596 | + continue; | ||
597 | + } | ||
598 | + | ||
599 | + needPrint = printFlag; | ||
600 | + didSub = TRUE; | ||
601 | + dirty = TRUE; | ||
602 | + | ||
603 | + /* | ||
604 | + * If the replacement string is the same size or shorter | ||
605 | + * than the old string, then the substitution is easy. | ||
606 | + */ | ||
607 | + if (deltaLen <= 0) | ||
608 | + { | ||
609 | + memcpy(&lp->data[offset], newStr, newLen); | ||
610 | + | ||
611 | + if (deltaLen) | ||
612 | + { | ||
613 | + memcpy(&lp->data[offset + newLen], | ||
614 | + &lp->data[offset + oldLen], | ||
615 | + lp->len - offset - oldLen); | ||
616 | + | ||
617 | + lp->len += deltaLen; | ||
618 | + } | ||
619 | + | ||
620 | + offset += newLen; | ||
621 | + | ||
622 | + if (globalFlag) | ||
623 | + continue; | ||
624 | + | ||
625 | + if (needPrint) | ||
626 | + { | ||
627 | + printLines(num1, num1, FALSE); | ||
628 | + needPrint = FALSE; | ||
629 | + } | ||
630 | + | ||
631 | + lp = lp->next; | ||
632 | + num1++; | ||
633 | + | ||
634 | + continue; | ||
635 | + } | ||
636 | + | ||
637 | + /* | ||
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. | ||
641 | + */ | ||
642 | + nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen); | ||
643 | + | ||
644 | + if (nlp == NULL) | ||
645 | + { | ||
646 | + bb_error_msg("Cannot get memory for line"); | ||
647 | + | ||
648 | + return; | ||
649 | + } | ||
650 | + | ||
651 | + nlp->len = lp->len + deltaLen; | ||
652 | + | ||
653 | + memcpy(nlp->data, lp->data, offset); | ||
654 | + | ||
655 | + memcpy(&nlp->data[offset], newStr, newLen); | ||
656 | + | ||
657 | + memcpy(&nlp->data[offset + newLen], | ||
658 | + &lp->data[offset + oldLen], | ||
659 | + lp->len - offset - oldLen); | ||
660 | + | ||
661 | + nlp->next = lp->next; | ||
662 | + nlp->prev = lp->prev; | ||
663 | + nlp->prev->next = nlp; | ||
664 | + nlp->next->prev = nlp; | ||
665 | + | ||
666 | + if (curLine == lp) | ||
667 | + curLine = nlp; | ||
668 | + | ||
669 | + free(lp); | ||
670 | + lp = nlp; | ||
671 | + | ||
672 | + offset += newLen; | ||
673 | + | ||
674 | + if (globalFlag) | ||
675 | + continue; | ||
676 | + | ||
677 | + if (needPrint) | ||
678 | + { | ||
679 | + printLines(num1, num1, FALSE); | ||
680 | + needPrint = FALSE; | ||
681 | + } | ||
682 | + | ||
683 | + lp = lp->next; | ||
684 | + num1++; | ||
685 | + } | ||
686 | + | ||
687 | + if (!didSub) | ||
688 | + bb_error_msg("No substitutions found for \"%s\"", oldStr); | ||
689 | +} | ||
690 | + | ||
691 | + | ||
692 | +/* | ||
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. | ||
695 | + */ | ||
696 | +static LEN | ||
697 | +findString( const LINE * lp, const char * str, LEN len, LEN offset) | ||
698 | +{ | ||
699 | + LEN left; | ||
700 | + const char * cp; | ||
701 | + const char * ncp; | ||
702 | + | ||
703 | + cp = &lp->data[offset]; | ||
704 | + left = lp->len - offset; | ||
705 | + | ||
706 | + while (left >= len) | ||
707 | + { | ||
708 | + ncp = memchr(cp, *str, left); | ||
709 | + | ||
710 | + if (ncp == NULL) | ||
711 | + return -1; | ||
712 | + | ||
713 | + left -= (ncp - cp); | ||
714 | + | ||
715 | + if (left < len) | ||
716 | + return -1; | ||
717 | + | ||
718 | + cp = ncp; | ||
719 | + | ||
720 | + if (memcmp(cp, str, len) == 0) | ||
721 | + return (cp - lp->data); | ||
722 | + | ||
723 | + cp++; | ||
724 | + left--; | ||
725 | + } | ||
726 | + | ||
727 | + return -1; | ||
728 | +} | ||
729 | + | ||
730 | + | ||
731 | +/* | ||
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. | ||
736 | + */ | ||
737 | +static void | ||
738 | +addLines(NUM num) | ||
739 | +{ | ||
740 | + int len; | ||
741 | + char buf[USERSIZE + 1]; | ||
742 | + | ||
743 | + while (fgets(buf, sizeof(buf), stdin)) | ||
744 | + { | ||
745 | + if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0')) | ||
746 | + return; | ||
747 | + | ||
748 | + len = strlen(buf); | ||
749 | + | ||
750 | + if (len == 0) | ||
751 | + return; | ||
752 | + | ||
753 | + if (buf[len - 1] != '\n') | ||
754 | + { | ||
755 | + bb_error_msg("Line too long"); | ||
756 | + | ||
757 | + do | ||
758 | + { | ||
759 | + len = fgetc(stdin); | ||
760 | + } | ||
761 | + while ((len != EOF) && (len != '\n')); | ||
762 | + | ||
763 | + return; | ||
764 | + } | ||
765 | + | ||
766 | + if (!insertLine(num++, buf, len)) | ||
767 | + return; | ||
768 | + } | ||
769 | +} | ||
770 | + | ||
771 | + | ||
772 | +/* | ||
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. | ||
779 | + */ | ||
780 | +static BOOL | ||
781 | +getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum) | ||
782 | +{ | ||
783 | + const char * cp; | ||
784 | + char * endStr; | ||
785 | + char str[USERSIZE]; | ||
786 | + BOOL haveNum; | ||
787 | + NUM value; | ||
788 | + NUM num; | ||
789 | + NUM sign; | ||
790 | + | ||
791 | + cp = *retcp; | ||
792 | + haveNum = FALSE; | ||
793 | + value = 0; | ||
794 | + sign = 1; | ||
795 | + | ||
796 | + while (TRUE) | ||
797 | + { | ||
798 | + while (isblank(*cp)) | ||
799 | + cp++; | ||
800 | + | ||
801 | + switch (*cp) | ||
802 | + { | ||
803 | + case '.': | ||
804 | + haveNum = TRUE; | ||
805 | + num = curNum; | ||
806 | + cp++; | ||
807 | + break; | ||
808 | + | ||
809 | + case '$': | ||
810 | + haveNum = TRUE; | ||
811 | + num = lastNum; | ||
812 | + cp++; | ||
813 | + break; | ||
814 | + | ||
815 | + case '\'': | ||
816 | + cp++; | ||
817 | + | ||
818 | + if ((*cp < 'a') || (*cp > 'z')) | ||
819 | + { | ||
820 | + bb_error_msg("Bad mark name"); | ||
821 | + | ||
822 | + return FALSE; | ||
823 | + } | ||
824 | + | ||
825 | + haveNum = TRUE; | ||
826 | + num = marks[*cp++ - 'a']; | ||
827 | + break; | ||
828 | + | ||
829 | + case '/': | ||
830 | + strcpy(str, ++cp); | ||
831 | + endStr = strchr(str, '/'); | ||
832 | + | ||
833 | + if (endStr) | ||
834 | + { | ||
835 | + *endStr++ = '\0'; | ||
836 | + cp += (endStr - str); | ||
837 | + } | ||
838 | + else | ||
839 | + cp = ""; | ||
840 | + | ||
841 | + num = searchLines(str, curNum, lastNum); | ||
842 | + | ||
843 | + if (num == 0) | ||
844 | + return FALSE; | ||
845 | + | ||
846 | + haveNum = TRUE; | ||
847 | + break; | ||
848 | + | ||
849 | + default: | ||
850 | + if (!isdigit(*cp)) | ||
851 | + { | ||
852 | + *retcp = cp; | ||
853 | + *retHaveNum = haveNum; | ||
854 | + *retNum = value; | ||
855 | + | ||
856 | + return TRUE; | ||
857 | + } | ||
858 | + | ||
859 | + num = 0; | ||
860 | + | ||
861 | + while (isdigit(*cp)) | ||
862 | + num = num * 10 + *cp++ - '0'; | ||
863 | + | ||
864 | + haveNum = TRUE; | ||
865 | + break; | ||
866 | + } | ||
867 | + | ||
868 | + value += num * sign; | ||
869 | + | ||
870 | + while (isblank(*cp)) | ||
871 | + cp++; | ||
872 | + | ||
873 | + switch (*cp) | ||
874 | + { | ||
875 | + case '-': | ||
876 | + sign = -1; | ||
877 | + cp++; | ||
878 | + break; | ||
879 | + | ||
880 | + case '+': | ||
881 | + sign = 1; | ||
882 | + cp++; | ||
883 | + break; | ||
884 | + | ||
885 | + default: | ||
886 | + *retcp = cp; | ||
887 | + *retHaveNum = haveNum; | ||
888 | + *retNum = value; | ||
889 | + | ||
890 | + return TRUE; | ||
891 | + } | ||
892 | + } | ||
893 | +} | ||
894 | + | ||
895 | + | ||
896 | +/* | ||
897 | + * Initialize everything for editing. | ||
898 | + */ | ||
899 | +static BOOL | ||
900 | +initEdit(void) | ||
901 | +{ | ||
902 | + int i; | ||
903 | + | ||
904 | + bufSize = INITBUF_SIZE; | ||
905 | + bufBase = malloc(bufSize); | ||
906 | + | ||
907 | + if (bufBase == NULL) | ||
908 | + { | ||
909 | + bb_error_msg("No memory for buffer"); | ||
910 | + | ||
911 | + return FALSE; | ||
912 | + } | ||
913 | + | ||
914 | + bufPtr = bufBase; | ||
915 | + bufUsed = 0; | ||
916 | + | ||
917 | + lines.next = &lines; | ||
918 | + lines.prev = &lines; | ||
919 | + | ||
920 | + curLine = NULL; | ||
921 | + curNum = 0; | ||
922 | + lastNum = 0; | ||
923 | + dirty = FALSE; | ||
924 | + fileName = NULL; | ||
925 | + searchString[0] = '\0'; | ||
926 | + | ||
927 | + for (i = 0; i < 26; i++) | ||
928 | + marks[i] = 0; | ||
929 | + | ||
930 | + return TRUE; | ||
931 | +} | ||
932 | + | ||
933 | + | ||
934 | +/* | ||
935 | + * Finish editing. | ||
936 | + */ | ||
937 | +static void | ||
938 | +termEdit(void) | ||
939 | +{ | ||
940 | + if (bufBase) | ||
941 | + free(bufBase); | ||
942 | + | ||
943 | + bufBase = NULL; | ||
944 | + bufPtr = NULL; | ||
945 | + bufSize = 0; | ||
946 | + bufUsed = 0; | ||
947 | + | ||
948 | + if (fileName) | ||
949 | + free(fileName); | ||
950 | + | ||
951 | + fileName = NULL; | ||
952 | + | ||
953 | + searchString[0] = '\0'; | ||
954 | + | ||
955 | + if (lastNum) | ||
956 | + deleteLines(1, lastNum); | ||
957 | + | ||
958 | + lastNum = 0; | ||
959 | + curNum = 0; | ||
960 | + curLine = NULL; | ||
961 | +} | ||
962 | + | ||
963 | + | ||
964 | +/* | ||
965 | + * Read lines from a file at the specified line number. | ||
966 | + * Returns TRUE if the file was successfully read. | ||
967 | + */ | ||
968 | +static BOOL | ||
969 | +readLines(const char * file, NUM num) | ||
970 | +{ | ||
971 | + int fd; | ||
972 | + int cc; | ||
973 | + LEN len; | ||
974 | + LEN lineCount; | ||
975 | + LEN charCount; | ||
976 | + char * cp; | ||
977 | + | ||
978 | + if ((num < 1) || (num > lastNum + 1)) | ||
979 | + { | ||
980 | + bb_error_msg("Bad line for read"); | ||
981 | + | ||
982 | + return FALSE; | ||
983 | + } | ||
984 | + | ||
985 | + fd = open(file, 0); | ||
986 | + | ||
987 | + if (fd < 0) | ||
988 | + { | ||
989 | + perror(file); | ||
990 | + | ||
991 | + return FALSE; | ||
992 | + } | ||
993 | + | ||
994 | + bufPtr = bufBase; | ||
995 | + bufUsed = 0; | ||
996 | + lineCount = 0; | ||
997 | + charCount = 0; | ||
998 | + cc = 0; | ||
999 | + | ||
1000 | + printf("\"%s\", ", file); | ||
1001 | + fflush(stdout); | ||
1002 | + | ||
1003 | + do | ||
1004 | + { | ||
1005 | + cp = memchr(bufPtr, '\n', bufUsed); | ||
1006 | + | ||
1007 | + if (cp) | ||
1008 | + { | ||
1009 | + len = (cp - bufPtr) + 1; | ||
1010 | + | ||
1011 | + if (!insertLine(num, bufPtr, len)) | ||
1012 | + { | ||
1013 | + close(fd); | ||
1014 | + | ||
1015 | + return FALSE; | ||
1016 | + } | ||
1017 | + | ||
1018 | + bufPtr += len; | ||
1019 | + bufUsed -= len; | ||
1020 | + charCount += len; | ||
1021 | + lineCount++; | ||
1022 | + num++; | ||
1023 | + | ||
1024 | + continue; | ||
1025 | + } | ||
1026 | + | ||
1027 | + if (bufPtr != bufBase) | ||
1028 | + { | ||
1029 | + memcpy(bufBase, bufPtr, bufUsed); | ||
1030 | + bufPtr = bufBase + bufUsed; | ||
1031 | + } | ||
1032 | + | ||
1033 | + if (bufUsed >= bufSize) | ||
1034 | + { | ||
1035 | + len = (bufSize * 3) / 2; | ||
1036 | + cp = realloc(bufBase, len); | ||
1037 | + | ||
1038 | + if (cp == NULL) | ||
1039 | + { | ||
1040 | + bb_error_msg("No memory for buffer"); | ||
1041 | + close(fd); | ||
1042 | + | ||
1043 | + return FALSE; | ||
1044 | + } | ||
1045 | + | ||
1046 | + bufBase = cp; | ||
1047 | + bufPtr = bufBase + bufUsed; | ||
1048 | + bufSize = len; | ||
1049 | + } | ||
1050 | + | ||
1051 | + cc = read(fd, bufPtr, bufSize - bufUsed); | ||
1052 | + bufUsed += cc; | ||
1053 | + bufPtr = bufBase; | ||
1054 | + | ||
1055 | + } | ||
1056 | + while (cc > 0); | ||
1057 | + | ||
1058 | + if (cc < 0) | ||
1059 | + { | ||
1060 | + perror(file); | ||
1061 | + close(fd); | ||
1062 | + | ||
1063 | + return FALSE; | ||
1064 | + } | ||
1065 | + | ||
1066 | + if (bufUsed) | ||
1067 | + { | ||
1068 | + if (!insertLine(num, bufPtr, bufUsed)) | ||
1069 | + { | ||
1070 | + close(fd); | ||
1071 | + | ||
1072 | + return -1; | ||
1073 | + } | ||
1074 | + | ||
1075 | + lineCount++; | ||
1076 | + charCount += bufUsed; | ||
1077 | + } | ||
1078 | + | ||
1079 | + close(fd); | ||
1080 | + | ||
1081 | + printf("%d lines%s, %d chars\n", lineCount, | ||
1082 | + (bufUsed ? " (incomplete)" : ""), charCount); | ||
1083 | + | ||
1084 | + return TRUE; | ||
1085 | +} | ||
1086 | + | ||
1087 | + | ||
1088 | +/* | ||
1089 | + * Write the specified lines out to the specified file. | ||
1090 | + * Returns TRUE if successful, or FALSE on an error with a message output. | ||
1091 | + */ | ||
1092 | +static BOOL | ||
1093 | +writeLines(const char * file, NUM num1, NUM num2) | ||
1094 | +{ | ||
1095 | + int fd; | ||
1096 | + LINE * lp; | ||
1097 | + LEN lineCount; | ||
1098 | + LEN charCount; | ||
1099 | + | ||
1100 | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1101 | + { | ||
1102 | + bb_error_msg("Bad line range for write"); | ||
1103 | + | ||
1104 | + return FALSE; | ||
1105 | + } | ||
1106 | + | ||
1107 | + lineCount = 0; | ||
1108 | + charCount = 0; | ||
1109 | + | ||
1110 | + fd = creat(file, 0666); | ||
1111 | + | ||
1112 | + if (fd < 0) { | ||
1113 | + perror(file); | ||
1114 | + | ||
1115 | + return FALSE; | ||
1116 | + } | ||
1117 | + | ||
1118 | + printf("\"%s\", ", file); | ||
1119 | + fflush(stdout); | ||
1120 | + | ||
1121 | + lp = findLine(num1); | ||
1122 | + | ||
1123 | + if (lp == NULL) | ||
1124 | + { | ||
1125 | + close(fd); | ||
1126 | + | ||
1127 | + return FALSE; | ||
1128 | + } | ||
1129 | + | ||
1130 | + while (num1++ <= num2) | ||
1131 | + { | ||
1132 | + if (write(fd, lp->data, lp->len) != lp->len) | ||
1133 | + { | ||
1134 | + perror(file); | ||
1135 | + close(fd); | ||
1136 | + | ||
1137 | + return FALSE; | ||
1138 | + } | ||
1139 | + | ||
1140 | + charCount += lp->len; | ||
1141 | + lineCount++; | ||
1142 | + lp = lp->next; | ||
1143 | + } | ||
1144 | + | ||
1145 | + if (close(fd) < 0) | ||
1146 | + { | ||
1147 | + perror(file); | ||
1148 | + | ||
1149 | + return FALSE; | ||
1150 | + } | ||
1151 | + | ||
1152 | + printf("%d lines, %d chars\n", lineCount, charCount); | ||
1153 | + | ||
1154 | + return TRUE; | ||
1155 | +} | ||
1156 | + | ||
1157 | + | ||
1158 | +/* | ||
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. | ||
1163 | + */ | ||
1164 | +static BOOL | ||
1165 | +printLines(NUM num1, NUM num2, BOOL expandFlag) | ||
1166 | +{ | ||
1167 | + const LINE * lp; | ||
1168 | + const unsigned char * cp; | ||
1169 | + int ch; | ||
1170 | + LEN count; | ||
1171 | + | ||
1172 | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1173 | + { | ||
1174 | + bb_error_msg("Bad line range for print"); | ||
1175 | + | ||
1176 | + return FALSE; | ||
1177 | + } | ||
1178 | + | ||
1179 | + lp = findLine(num1); | ||
1180 | + | ||
1181 | + if (lp == NULL) | ||
1182 | + return FALSE; | ||
1183 | + | ||
1184 | + while (num1 <= num2) | ||
1185 | + { | ||
1186 | + if (!expandFlag) | ||
1187 | + { | ||
1188 | + write(1, lp->data, lp->len); | ||
1189 | + setCurNum(num1++); | ||
1190 | + lp = lp->next; | ||
1191 | + | ||
1192 | + continue; | ||
1193 | + } | ||
1194 | + | ||
1195 | + /* | ||
1196 | + * Show control characters and characters with the | ||
1197 | + * high bit set specially. | ||
1198 | + */ | ||
1199 | + cp = lp->data; | ||
1200 | + count = lp->len; | ||
1201 | + | ||
1202 | + if ((count > 0) && (cp[count - 1] == '\n')) | ||
1203 | + count--; | ||
1204 | + | ||
1205 | + while (count-- > 0) | ||
1206 | + { | ||
1207 | + ch = *cp++; | ||
1208 | + | ||
1209 | + if (ch & 0x80) | ||
1210 | + { | ||
1211 | + fputs("M-", stdout); | ||
1212 | + ch &= 0x7f; | ||
1213 | + } | ||
1214 | + | ||
1215 | + if (ch < ' ') | ||
1216 | + { | ||
1217 | + fputc('^', stdout); | ||
1218 | + ch += '@'; | ||
1219 | + } | ||
1220 | + | ||
1221 | + if (ch == 0x7f) | ||
1222 | + { | ||
1223 | + fputc('^', stdout); | ||
1224 | + ch = '?'; | ||
1225 | + } | ||
1226 | + | ||
1227 | + fputc(ch, stdout); | ||
1228 | + } | ||
1229 | + | ||
1230 | + fputs("$\n", stdout); | ||
1231 | + | ||
1232 | + setCurNum(num1++); | ||
1233 | + lp = lp->next; | ||
1234 | + } | ||
1235 | + | ||
1236 | + return TRUE; | ||
1237 | +} | ||
1238 | + | ||
1239 | + | ||
1240 | +/* | ||
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. | ||
1246 | + */ | ||
1247 | +static BOOL | ||
1248 | +insertLine(NUM num, const char * data, LEN len) | ||
1249 | +{ | ||
1250 | + LINE * newLp; | ||
1251 | + LINE * lp; | ||
1252 | + | ||
1253 | + if ((num < 1) || (num > lastNum + 1)) | ||
1254 | + { | ||
1255 | + bb_error_msg("Inserting at bad line number"); | ||
1256 | + | ||
1257 | + return FALSE; | ||
1258 | + } | ||
1259 | + | ||
1260 | + newLp = (LINE *) malloc(sizeof(LINE) + len - 1); | ||
1261 | + | ||
1262 | + if (newLp == NULL) | ||
1263 | + { | ||
1264 | + bb_error_msg("Failed to allocate memory for line"); | ||
1265 | + | ||
1266 | + return FALSE; | ||
1267 | + } | ||
1268 | + | ||
1269 | + memcpy(newLp->data, data, len); | ||
1270 | + newLp->len = len; | ||
1271 | + | ||
1272 | + if (num > lastNum) | ||
1273 | + lp = &lines; | ||
1274 | + else | ||
1275 | + { | ||
1276 | + lp = findLine(num); | ||
1277 | + | ||
1278 | + if (lp == NULL) | ||
1279 | + { | ||
1280 | + free((char *) newLp); | ||
1281 | + | ||
1282 | + return FALSE; | ||
1283 | + } | ||
1284 | + } | ||
1285 | + | ||
1286 | + newLp->next = lp; | ||
1287 | + newLp->prev = lp->prev; | ||
1288 | + lp->prev->next = newLp; | ||
1289 | + lp->prev = newLp; | ||
1290 | + | ||
1291 | + lastNum++; | ||
1292 | + dirty = TRUE; | ||
1293 | + | ||
1294 | + return setCurNum(num); | ||
1295 | +} | ||
1296 | + | ||
1297 | + | ||
1298 | +/* | ||
1299 | + * Delete lines from the given range. | ||
1300 | + */ | ||
1301 | +static BOOL | ||
1302 | +deleteLines(NUM num1, NUM num2) | ||
1303 | +{ | ||
1304 | + LINE * lp; | ||
1305 | + LINE * nlp; | ||
1306 | + LINE * plp; | ||
1307 | + NUM count; | ||
1308 | + | ||
1309 | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1310 | + { | ||
1311 | + bb_error_msg("Bad line numbers for delete"); | ||
1312 | + | ||
1313 | + return FALSE; | ||
1314 | + } | ||
1315 | + | ||
1316 | + lp = findLine(num1); | ||
1317 | + | ||
1318 | + if (lp == NULL) | ||
1319 | + return FALSE; | ||
1320 | + | ||
1321 | + if ((curNum >= num1) && (curNum <= num2)) | ||
1322 | + { | ||
1323 | + if (num2 < lastNum) | ||
1324 | + setCurNum(num2 + 1); | ||
1325 | + else if (num1 > 1) | ||
1326 | + setCurNum(num1 - 1); | ||
1327 | + else | ||
1328 | + curNum = 0; | ||
1329 | + } | ||
1330 | + | ||
1331 | + count = num2 - num1 + 1; | ||
1332 | + | ||
1333 | + if (curNum > num2) | ||
1334 | + curNum -= count; | ||
1335 | + | ||
1336 | + lastNum -= count; | ||
1337 | + | ||
1338 | + while (count-- > 0) | ||
1339 | + { | ||
1340 | + nlp = lp->next; | ||
1341 | + plp = lp->prev; | ||
1342 | + plp->next = nlp; | ||
1343 | + nlp->prev = plp; | ||
1344 | + lp->next = NULL; | ||
1345 | + lp->prev = NULL; | ||
1346 | + lp->len = 0; | ||
1347 | + free(lp); | ||
1348 | + lp = nlp; | ||
1349 | + } | ||
1350 | + | ||
1351 | + dirty = TRUE; | ||
1352 | + | ||
1353 | + return TRUE; | ||
1354 | +} | ||
1355 | + | ||
1356 | + | ||
1357 | +/* | ||
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. | ||
1363 | + */ | ||
1364 | +static NUM | ||
1365 | +searchLines(const char * str, NUM num1, NUM num2) | ||
1366 | +{ | ||
1367 | + const LINE * lp; | ||
1368 | + int len; | ||
1369 | + | ||
1370 | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) | ||
1371 | + { | ||
1372 | + bb_error_msg("Bad line numbers for search"); | ||
1373 | + | ||
1374 | + return 0; | ||
1375 | + } | ||
1376 | + | ||
1377 | + if (*str == '\0') | ||
1378 | + { | ||
1379 | + if (searchString[0] == '\0') | ||
1380 | + { | ||
1381 | + bb_error_msg("No previous search string"); | ||
1382 | + | ||
1383 | + return 0; | ||
1384 | + } | ||
1385 | + | ||
1386 | + str = searchString; | ||
1387 | + } | ||
1388 | + | ||
1389 | + if (str != searchString) | ||
1390 | + strcpy(searchString, str); | ||
1391 | + | ||
1392 | + len = strlen(str); | ||
1393 | + | ||
1394 | + lp = findLine(num1); | ||
1395 | + | ||
1396 | + if (lp == NULL) | ||
1397 | + return 0; | ||
1398 | + | ||
1399 | + while (num1 <= num2) | ||
1400 | + { | ||
1401 | + if (findString(lp, str, len, 0) >= 0) | ||
1402 | + return num1; | ||
1403 | + | ||
1404 | + num1++; | ||
1405 | + lp = lp->next; | ||
1406 | + } | ||
1407 | + | ||
1408 | + bb_error_msg("Cannot find string \"%s\"", str); | ||
1409 | + | ||
1410 | + return 0; | ||
1411 | +} | ||
1412 | + | ||
1413 | + | ||
1414 | +/* | ||
1415 | + * Return a pointer to the specified line number. | ||
1416 | + */ | ||
1417 | +static LINE * | ||
1418 | +findLine(NUM num) | ||
1419 | +{ | ||
1420 | + LINE * lp; | ||
1421 | + NUM lnum; | ||
1422 | + | ||
1423 | + if ((num < 1) || (num > lastNum)) | ||
1424 | + { | ||
1425 | + bb_error_msg("Line number %d does not exist", num); | ||
1426 | + | ||
1427 | + return NULL; | ||
1428 | + } | ||
1429 | + | ||
1430 | + if (curNum <= 0) | ||
1431 | + { | ||
1432 | + curNum = 1; | ||
1433 | + curLine = lines.next; | ||
1434 | + } | ||
1435 | + | ||
1436 | + if (num == curNum) | ||
1437 | + return curLine; | ||
1438 | + | ||
1439 | + lp = curLine; | ||
1440 | + lnum = curNum; | ||
1441 | + | ||
1442 | + if (num < (curNum / 2)) | ||
1443 | + { | ||
1444 | + lp = lines.next; | ||
1445 | + lnum = 1; | ||
1446 | + } | ||
1447 | + else if (num > ((curNum + lastNum) / 2)) | ||
1448 | + { | ||
1449 | + lp = lines.prev; | ||
1450 | + lnum = lastNum; | ||
1451 | + } | ||
1452 | + | ||
1453 | + while (lnum < num) | ||
1454 | + { | ||
1455 | + lp = lp->next; | ||
1456 | + lnum++; | ||
1457 | + } | ||
1458 | + | ||
1459 | + while (lnum > num) | ||
1460 | + { | ||
1461 | + lp = lp->prev; | ||
1462 | + lnum--; | ||
1463 | + } | ||
1464 | + | ||
1465 | + return lp; | ||
1466 | +} | ||
1467 | + | ||
1468 | + | ||
1469 | +/* | ||
1470 | + * Set the current line number. | ||
1471 | + * Returns TRUE if successful. | ||
1472 | + */ | ||
1473 | +static BOOL | ||
1474 | +setCurNum(NUM num) | ||
1475 | +{ | ||
1476 | + LINE * lp; | ||
1477 | + | ||
1478 | + lp = findLine(num); | ||
1479 | + | ||
1480 | + if (lp == NULL) | ||
1481 | + return FALSE; | ||
1482 | + | ||
1483 | + curNum = num; | ||
1484 | + curLine = lp; | ||
1485 | + | ||
1486 | + return TRUE; | ||
1487 | +} | ||
1488 | + | ||
1489 | +/* END CODE */ | ||