Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/editors/ed.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 20099 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 /* vi: set sw=4 ts=4: */
2 /*
3 * Copyright (c) 2002 by David I. Bell
4 * Permission is granted to use, distribute, or modify this source,
5 * provided that this copyright notice remains intact.
6 *
7 * The "ed" built-in command (much simplified)
8 */
9
10 #include "busybox.h"
11
12 #define USERSIZE 1024 /* max line length typed in by user */
13 #define INITBUF_SIZE 1024 /* initial buffer size */
14 typedef struct LINE {
15 struct LINE *next;
16 struct LINE *prev;
17 int len;
18 char data[1];
19 } LINE;
20
21 static LINE lines, *curLine;
22 static int curNum, lastNum, marks[26], dirty;
23 static char *bufBase, *bufPtr, *fileName, searchString[USERSIZE];
24 static int bufUsed, bufSize;
25
26 static void doCommands(void);
27 static void subCommand(const char *cmd, int num1, int num2);
28 static int getNum(const char **retcp, int *retHaveNum, int *retNum);
29 static int setCurNum(int num);
30 static int initEdit(void);
31 static void termEdit(void);
32 static void addLines(int num);
33 static int insertLine(int num, const char *data, int len);
34 static int deleteLines(int num1, int num2);
35 static int printLines(int num1, int num2, int expandFlag);
36 static int writeLines(const char *file, int num1, int num2);
37 static int readLines(const char *file, int num);
38 static int searchLines(const char *str, int num1, int num2);
39 static LINE *findLine(int num);
40
41 static int findString(const LINE *lp, const char * str, int len, int offset);
42
43 int ed_main(int argc, char **argv)
44 {
45 if (!initEdit())
46 return EXIT_FAILURE;
47
48 if (argc > 1) {
49 fileName = strdup(argv[1]);
50
51 if (fileName == NULL) {
52 bb_error_msg("no memory");
53 termEdit();
54 return EXIT_SUCCESS;
55 }
56
57 if (!readLines(fileName, 1)) {
58 termEdit();
59 return EXIT_SUCCESS;
60 }
61
62 if (lastNum)
63 setCurNum(1);
64
65 dirty = FALSE;
66 }
67
68 doCommands();
69
70 termEdit();
71 return EXIT_SUCCESS;
72 }
73
74 /*
75 * Read commands until we are told to stop.
76 */
77 static void doCommands(void)
78 {
79 const char *cp;
80 char *endbuf, *newname, buf[USERSIZE];
81 int len, num1, num2, have1, have2;
82
83 while (TRUE) {
84 printf(": ");
85 fflush(stdout);
86
87 if (fgets(buf, sizeof(buf), stdin) == NULL)
88 return;
89
90 len = strlen(buf);
91
92 if (len == 0)
93 return;
94
95 endbuf = &buf[len - 1];
96
97 if (*endbuf != '\n') {
98 bb_error_msg("command line too long");
99
100 do {
101 len = fgetc(stdin);
102 } while ((len != EOF) && (len != '\n'));
103
104 continue;
105 }
106
107 while ((endbuf > buf) && isblank(endbuf[-1]))
108 endbuf--;
109
110 *endbuf = '\0';
111
112 cp = buf;
113
114 while (isblank(*cp))
115 cp++;
116
117 have1 = FALSE;
118 have2 = FALSE;
119
120 if ((curNum == 0) && (lastNum > 0)) {
121 curNum = 1;
122 curLine = lines.next;
123 }
124
125 if (!getNum(&cp, &have1, &num1))
126 continue;
127
128 while (isblank(*cp))
129 cp++;
130
131 if (*cp == ',') {
132 cp++;
133
134 if (!getNum(&cp, &have2, &num2))
135 continue;
136
137 if (!have1)
138 num1 = 1;
139
140 if (!have2)
141 num2 = lastNum;
142
143 have1 = TRUE;
144 have2 = TRUE;
145 }
146
147 if (!have1)
148 num1 = curNum;
149
150 if (!have2)
151 num2 = num1;
152
153 switch (*cp++) {
154 case 'a':
155 addLines(num1 + 1);
156 break;
157
158 case 'c':
159 deleteLines(num1, num2);
160 addLines(num1);
161 break;
162
163 case 'd':
164 deleteLines(num1, num2);
165 break;
166
167 case 'f':
168 if (*cp && !isblank(*cp)) {
169 bb_error_msg("bad file command");
170 break;
171 }
172
173 while (isblank(*cp))
174 cp++;
175
176 if (*cp == '\0') {
177 if (fileName)
178 printf("\"%s\"\n", fileName);
179 else
180 printf("No file name\n");
181 break;
182 }
183
184 newname = strdup(cp);
185
186 if (newname == NULL) {
187 bb_error_msg("no memory for file name");
188 break;
189 }
190
191 if (fileName)
192 free(fileName);
193
194 fileName = newname;
195 break;
196
197 case 'i':
198 addLines(num1);
199 break;
200
201 case 'k':
202 while (isblank(*cp))
203 cp++;
204
205 if ((*cp < 'a') || (*cp > 'a') || cp[1]) {
206 bb_error_msg("bad mark name");
207 break;
208 }
209
210 marks[*cp - 'a'] = num2;
211 break;
212
213 case 'l':
214 printLines(num1, num2, TRUE);
215 break;
216
217 case 'p':
218 printLines(num1, num2, FALSE);
219 break;
220
221 case 'q':
222 while (isblank(*cp))
223 cp++;
224
225 if (have1 || *cp) {
226 bb_error_msg("bad quit command");
227 break;
228 }
229
230 if (!dirty)
231 return;
232
233 printf("Really quit? ");
234 fflush(stdout);
235
236 buf[0] = '\0';
237 fgets(buf, sizeof(buf), stdin);
238 cp = buf;
239
240 while (isblank(*cp))
241 cp++;
242
243 if ((*cp == 'y') || (*cp == 'Y'))
244 return;
245
246 break;
247
248 case 'r':
249 if (*cp && !isblank(*cp)) {
250 bb_error_msg("bad read command");
251 break;
252 }
253
254 while (isblank(*cp))
255 cp++;
256
257 if (*cp == '\0') {
258 bb_error_msg("no file name");
259 break;
260 }
261
262 if (!have1)
263 num1 = lastNum;
264
265 if (readLines(cp, num1 + 1))
266 break;
267
268 if (fileName == NULL)
269 fileName = strdup(cp);
270
271 break;
272
273 case 's':
274 subCommand(cp, num1, num2);
275 break;
276
277 case 'w':
278 if (*cp && !isblank(*cp)) {
279 bb_error_msg("bad write command");
280 break;
281 }
282
283 while (isblank(*cp))
284 cp++;
285
286 if (!have1) {
287 num1 = 1;
288 num2 = lastNum;
289 }
290
291 if (*cp == '\0')
292 cp = fileName;
293
294 if (cp == NULL) {
295 bb_error_msg("no file name specified");
296 break;
297 }
298
299 writeLines(cp, num1, num2);
300 break;
301
302 case 'z':
303 switch (*cp) {
304 case '-':
305 printLines(curNum-21, curNum, FALSE);
306 break;
307 case '.':
308 printLines(curNum-11, curNum+10, FALSE);
309 break;
310 default:
311 printLines(curNum, curNum+21, FALSE);
312 break;
313 }
314 break;
315
316 case '.':
317 if (have1) {
318 bb_error_msg("no arguments allowed");
319 break;
320 }
321
322 printLines(curNum, curNum, FALSE);
323 break;
324
325 case '-':
326 if (setCurNum(curNum - 1))
327 printLines(curNum, curNum, FALSE);
328
329 break;
330
331 case '=':
332 printf("%d\n", num1);
333 break;
334
335 case '\0':
336 if (have1) {
337 printLines(num2, num2, FALSE);
338 break;
339 }
340
341 if (setCurNum(curNum + 1))
342 printLines(curNum, curNum, FALSE);
343
344 break;
345
346 default:
347 bb_error_msg("unimplemented command");
348 break;
349 }
350 }
351 }
352
353
354 /*
355 * Do the substitute command.
356 * The current line is set to the last substitution done.
357 */
358 static void subCommand(const char * cmd, int num1, int num2)
359 {
360 char *cp, *oldStr, *newStr, buf[USERSIZE];
361 int delim, oldLen, newLen, deltaLen, offset;
362 LINE *lp, *nlp;
363 int globalFlag, printFlag, didSub, needPrint;
364
365 if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
366 bb_error_msg("bad line range for substitute");
367 return;
368 }
369
370 globalFlag = FALSE;
371 printFlag = FALSE;
372 didSub = FALSE;
373 needPrint = FALSE;
374
375 /*
376 * Copy the command so we can modify it.
377 */
378 strcpy(buf, cmd);
379 cp = buf;
380
381 if (isblank(*cp) || (*cp == '\0')) {
382 bb_error_msg("bad delimiter for substitute");
383 return;
384 }
385
386 delim = *cp++;
387 oldStr = cp;
388
389 cp = strchr(cp, delim);
390
391 if (cp == NULL) {
392 bb_error_msg("missing 2nd delimiter for substitute");
393 return;
394 }
395
396 *cp++ = '\0';
397
398 newStr = cp;
399 cp = strchr(cp, delim);
400
401 if (cp)
402 *cp++ = '\0';
403 else
404 cp = "";
405
406 while (*cp) switch (*cp++) {
407 case 'g':
408 globalFlag = TRUE;
409 break;
410
411 case 'p':
412 printFlag = TRUE;
413 break;
414
415 default:
416 bb_error_msg("unknown option for substitute");
417 return;
418 }
419
420 if (*oldStr == '\0') {
421 if (searchString[0] == '\0') {
422 bb_error_msg("no previous search string");
423 return;
424 }
425
426 oldStr = searchString;
427 }
428
429 if (oldStr != searchString)
430 strcpy(searchString, oldStr);
431
432 lp = findLine(num1);
433
434 if (lp == NULL)
435 return;
436
437 oldLen = strlen(oldStr);
438 newLen = strlen(newStr);
439 deltaLen = newLen - oldLen;
440 offset = 0;
441 nlp = NULL;
442
443 while (num1 <= num2) {
444 offset = findString(lp, oldStr, oldLen, offset);
445
446 if (offset < 0) {
447 if (needPrint) {
448 printLines(num1, num1, FALSE);
449 needPrint = FALSE;
450 }
451
452 offset = 0;
453 lp = lp->next;
454 num1++;
455
456 continue;
457 }
458
459 needPrint = printFlag;
460 didSub = TRUE;
461 dirty = TRUE;
462
463 /*
464 * If the replacement string is the same size or shorter
465 * than the old string, then the substitution is easy.
466 */
467 if (deltaLen <= 0) {
468 memcpy(&lp->data[offset], newStr, newLen);
469
470 if (deltaLen) {
471 memcpy(&lp->data[offset + newLen],
472 &lp->data[offset + oldLen],
473 lp->len - offset - oldLen);
474
475 lp->len += deltaLen;
476 }
477
478 offset += newLen;
479
480 if (globalFlag)
481 continue;
482
483 if (needPrint) {
484 printLines(num1, num1, FALSE);
485 needPrint = FALSE;
486 }
487
488 lp = lp->next;
489 num1++;
490
491 continue;
492 }
493
494 /*
495 * The new string is larger, so allocate a new line
496 * structure and use that. Link it in in place of
497 * the old line structure.
498 */
499 nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen);
500
501 if (nlp == NULL) {
502 bb_error_msg("cannot get memory for line");
503 return;
504 }
505
506 nlp->len = lp->len + deltaLen;
507
508 memcpy(nlp->data, lp->data, offset);
509
510 memcpy(&nlp->data[offset], newStr, newLen);
511
512 memcpy(&nlp->data[offset + newLen],
513 &lp->data[offset + oldLen],
514 lp->len - offset - oldLen);
515
516 nlp->next = lp->next;
517 nlp->prev = lp->prev;
518 nlp->prev->next = nlp;
519 nlp->next->prev = nlp;
520
521 if (curLine == lp)
522 curLine = nlp;
523
524 free(lp);
525 lp = nlp;
526
527 offset += newLen;
528
529 if (globalFlag)
530 continue;
531
532 if (needPrint) {
533 printLines(num1, num1, FALSE);
534 needPrint = FALSE;
535 }
536
537 lp = lp->next;
538 num1++;
539 }
540
541 if (!didSub)
542 bb_error_msg("no substitutions found for \"%s\"", oldStr);
543 }
544
545
546 /*
547 * Search a line for the specified string starting at the specified
548 * offset in the line. Returns the offset of the found string, or -1.
549 */
550 static int findString( const LINE * lp, const char * str, int len, int offset)
551 {
552 int left;
553 const char *cp, *ncp;
554
555 cp = &lp->data[offset];
556 left = lp->len - offset;
557
558 while (left >= len) {
559 ncp = memchr(cp, *str, left);
560
561 if (ncp == NULL)
562 return -1;
563
564 left -= (ncp - cp);
565
566 if (left < len)
567 return -1;
568
569 cp = ncp;
570
571 if (memcmp(cp, str, len) == 0)
572 return (cp - lp->data);
573
574 cp++;
575 left--;
576 }
577
578 return -1;
579 }
580
581
582 /*
583 * Add lines which are typed in by the user.
584 * The lines are inserted just before the specified line number.
585 * The lines are terminated by a line containing a single dot (ugly!),
586 * or by an end of file.
587 */
588 static void addLines(int num)
589 {
590 int len;
591 char buf[USERSIZE + 1];
592
593 while (fgets(buf, sizeof(buf), stdin)) {
594 if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
595 return;
596
597 len = strlen(buf);
598
599 if (len == 0)
600 return;
601
602 if (buf[len - 1] != '\n') {
603 bb_error_msg("line too long");
604 do {
605 len = fgetc(stdin);
606 } while ((len != EOF) && (len != '\n'));
607 return;
608 }
609
610 if (!insertLine(num++, buf, len))
611 return;
612 }
613 }
614
615
616 /*
617 * Parse a line number argument if it is present. This is a sum
618 * or difference of numbers, '.', '$', 'x, or a search string.
619 * Returns TRUE if successful (whether or not there was a number).
620 * Returns FALSE if there was a parsing error, with a message output.
621 * Whether there was a number is returned indirectly, as is the number.
622 * The character pointer which stopped the scan is also returned.
623 */
624 static int getNum(const char **retcp, int *retHaveNum, int *retNum)
625 {
626 const char *cp;
627 char *endStr, str[USERSIZE];
628 int haveNum, value, num, sign;
629
630 cp = *retcp;
631 haveNum = FALSE;
632 value = 0;
633 sign = 1;
634
635 while (TRUE) {
636 while (isblank(*cp))
637 cp++;
638
639 switch (*cp) {
640 case '.':
641 haveNum = TRUE;
642 num = curNum;
643 cp++;
644 break;
645
646 case '$':
647 haveNum = TRUE;
648 num = lastNum;
649 cp++;
650 break;
651
652 case '\'':
653 cp++;
654
655 if ((*cp < 'a') || (*cp > 'z')) {
656 bb_error_msg("bad mark name");
657 return FALSE;
658 }
659
660 haveNum = TRUE;
661 num = marks[*cp++ - 'a'];
662 break;
663
664 case '/':
665 strcpy(str, ++cp);
666 endStr = strchr(str, '/');
667
668 if (endStr) {
669 *endStr++ = '\0';
670 cp += (endStr - str);
671 }
672 else
673 cp = "";
674
675 num = searchLines(str, curNum, lastNum);
676
677 if (num == 0)
678 return FALSE;
679
680 haveNum = TRUE;
681 break;
682
683 default:
684 if (!isdigit(*cp)) {
685 *retcp = cp;
686 *retHaveNum = haveNum;
687 *retNum = value;
688 return TRUE;
689 }
690
691 num = 0;
692
693 while (isdigit(*cp))
694 num = num * 10 + *cp++ - '0';
695
696 haveNum = TRUE;
697 break;
698 }
699
700 value += num * sign;
701
702 while (isblank(*cp))
703 cp++;
704
705 switch (*cp) {
706 case '-':
707 sign = -1;
708 cp++;
709 break;
710
711 case '+':
712 sign = 1;
713 cp++;
714 break;
715
716 default:
717 *retcp = cp;
718 *retHaveNum = haveNum;
719 *retNum = value;
720 return TRUE;
721 }
722 }
723 }
724
725
726 /*
727 * Initialize everything for editing.
728 */
729 static int initEdit(void)
730 {
731 int i;
732
733 bufSize = INITBUF_SIZE;
734 bufBase = malloc(bufSize);
735
736 if (bufBase == NULL) {
737 bb_error_msg("no memory for buffer");
738 return FALSE;
739 }
740
741 bufPtr = bufBase;
742 bufUsed = 0;
743
744 lines.next = &lines;
745 lines.prev = &lines;
746
747 curLine = NULL;
748 curNum = 0;
749 lastNum = 0;
750 dirty = FALSE;
751 fileName = NULL;
752 searchString[0] = '\0';
753
754 for (i = 0; i < 26; i++)
755 marks[i] = 0;
756
757 return TRUE;
758 }
759
760
761 /*
762 * Finish editing.
763 */
764 static void termEdit(void)
765 {
766 if (bufBase)
767 free(bufBase);
768
769 bufBase = NULL;
770 bufPtr = NULL;
771 bufSize = 0;
772 bufUsed = 0;
773
774 if (fileName)
775 free(fileName);
776
777 fileName = NULL;
778
779 searchString[0] = '\0';
780
781 if (lastNum)
782 deleteLines(1, lastNum);
783
784 lastNum = 0;
785 curNum = 0;
786 curLine = NULL;
787 }
788
789
790 /*
791 * Read lines from a file at the specified line number.
792 * Returns TRUE if the file was successfully read.
793 */
794 static int readLines(const char * file, int num)
795 {
796 int fd, cc;
797 int len, lineCount, charCount;
798 char *cp;
799
800 if ((num < 1) || (num > lastNum + 1)) {
801 bb_error_msg("bad line for read");
802 return FALSE;
803 }
804
805 fd = open(file, 0);
806
807 if (fd < 0) {
808 perror(file);
809 return FALSE;
810 }
811
812 bufPtr = bufBase;
813 bufUsed = 0;
814 lineCount = 0;
815 charCount = 0;
816 cc = 0;
817
818 printf("\"%s\", ", file);
819 fflush(stdout);
820
821 do {
822 cp = memchr(bufPtr, '\n', bufUsed);
823
824 if (cp) {
825 len = (cp - bufPtr) + 1;
826
827 if (!insertLine(num, bufPtr, len)) {
828 close(fd);
829 return FALSE;
830 }
831
832 bufPtr += len;
833 bufUsed -= len;
834 charCount += len;
835 lineCount++;
836 num++;
837
838 continue;
839 }
840
841 if (bufPtr != bufBase) {
842 memcpy(bufBase, bufPtr, bufUsed);
843 bufPtr = bufBase + bufUsed;
844 }
845
846 if (bufUsed >= bufSize) {
847 len = (bufSize * 3) / 2;
848 cp = realloc(bufBase, len);
849
850 if (cp == NULL) {
851 bb_error_msg("no memory for buffer");
852 close(fd);
853 return FALSE;
854 }
855
856 bufBase = cp;
857 bufPtr = bufBase + bufUsed;
858 bufSize = len;
859 }
860
861 cc = read(fd, bufPtr, bufSize - bufUsed);
862 bufUsed += cc;
863 bufPtr = bufBase;
864
865 } while (cc > 0);
866
867 if (cc < 0) {
868 perror(file);
869 close(fd);
870 return FALSE;
871 }
872
873 if (bufUsed) {
874 if (!insertLine(num, bufPtr, bufUsed)) {
875 close(fd);
876 return -1;
877 }
878
879 lineCount++;
880 charCount += bufUsed;
881 }
882
883 close(fd);
884
885 printf("%d lines%s, %d chars\n", lineCount,
886 (bufUsed ? " (incomplete)" : ""), charCount);
887
888 return TRUE;
889 }
890
891
892 /*
893 * Write the specified lines out to the specified file.
894 * Returns TRUE if successful, or FALSE on an error with a message output.
895 */
896 static int writeLines(const char * file, int num1, int num2)
897 {
898 LINE *lp;
899 int fd, lineCount, charCount;
900
901 if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
902 bb_error_msg("bad line range for write");
903 return FALSE;
904 }
905
906 lineCount = 0;
907 charCount = 0;
908
909 fd = creat(file, 0666);
910
911 if (fd < 0) {
912 perror(file);
913 return FALSE;
914 }
915
916 printf("\"%s\", ", file);
917 fflush(stdout);
918
919 lp = findLine(num1);
920
921 if (lp == NULL) {
922 close(fd);
923 return FALSE;
924 }
925
926 while (num1++ <= num2) {
927 if (write(fd, lp->data, lp->len) != lp->len) {
928 perror(file);
929 close(fd);
930 return FALSE;
931 }
932
933 charCount += lp->len;
934 lineCount++;
935 lp = lp->next;
936 }
937
938 if (close(fd) < 0) {
939 perror(file);
940 return FALSE;
941 }
942
943 printf("%d lines, %d chars\n", lineCount, charCount);
944 return TRUE;
945 }
946
947
948 /*
949 * Print lines in a specified range.
950 * The last line printed becomes the current line.
951 * If expandFlag is TRUE, then the line is printed specially to
952 * show magic characters.
953 */
954 static int printLines(int num1, int num2, int expandFlag)
955 {
956 const LINE *lp;
957 const char *cp;
958 int ch, count;
959
960 if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
961 bb_error_msg("bad line range for print");
962 return FALSE;
963 }
964
965 lp = findLine(num1);
966
967 if (lp == NULL)
968 return FALSE;
969
970 while (num1 <= num2) {
971 if (!expandFlag) {
972 write(1, lp->data, lp->len);
973 setCurNum(num1++);
974 lp = lp->next;
975
976 continue;
977 }
978
979 /*
980 * Show control characters and characters with the
981 * high bit set specially.
982 */
983 cp = lp->data;
984 count = lp->len;
985
986 if ((count > 0) && (cp[count - 1] == '\n'))
987 count--;
988
989 while (count-- > 0) {
990 ch = *cp++;
991
992 if (ch & 0x80) {
993 fputs("M-", stdout);
994 ch &= 0x7f;
995 }
996
997 if (ch < ' ') {
998 fputc('^', stdout);
999 ch += '@';
1000 }
1001
1002 if (ch == 0x7f) {
1003 fputc('^', stdout);
1004 ch = '?';
1005 }
1006
1007 fputc(ch, stdout);
1008 }
1009
1010 fputs("$\n", stdout);
1011
1012 setCurNum(num1++);
1013 lp = lp->next;
1014 }
1015
1016 return TRUE;
1017 }
1018
1019
1020 /*
1021 * Insert a new line with the specified text.
1022 * The line is inserted so as to become the specified line,
1023 * thus pushing any existing and further lines down one.
1024 * The inserted line is also set to become the current line.
1025 * Returns TRUE if successful.
1026 */
1027 static int insertLine(int num, const char * data, int len)
1028 {
1029 LINE *newLp, *lp;
1030
1031 if ((num < 1) || (num > lastNum + 1)) {
1032 bb_error_msg("inserting at bad line number");
1033 return FALSE;
1034 }
1035
1036 newLp = malloc(sizeof(LINE) + len - 1);
1037
1038 if (newLp == NULL) {
1039 bb_error_msg("failed to allocate memory for line");
1040 return FALSE;
1041 }
1042
1043 memcpy(newLp->data, data, len);
1044 newLp->len = len;
1045
1046 if (num > lastNum)
1047 lp = &lines;
1048 else {
1049 lp = findLine(num);
1050
1051 if (lp == NULL) {
1052 free((char *) newLp);
1053 return FALSE;
1054 }
1055 }
1056
1057 newLp->next = lp;
1058 newLp->prev = lp->prev;
1059 lp->prev->next = newLp;
1060 lp->prev = newLp;
1061
1062 lastNum++;
1063 dirty = TRUE;
1064 return setCurNum(num);
1065 }
1066
1067
1068 /*
1069 * Delete lines from the given range.
1070 */
1071 static int deleteLines(int num1, int num2)
1072 {
1073 LINE *lp, *nlp, *plp;
1074 int count;
1075
1076 if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
1077 bb_error_msg("bad line numbers for delete");
1078 return FALSE;
1079 }
1080
1081 lp = findLine(num1);
1082
1083 if (lp == NULL)
1084 return FALSE;
1085
1086 if ((curNum >= num1) && (curNum <= num2)) {
1087 if (num2 < lastNum)
1088 setCurNum(num2 + 1);
1089 else if (num1 > 1)
1090 setCurNum(num1 - 1);
1091 else
1092 curNum = 0;
1093 }
1094
1095 count = num2 - num1 + 1;
1096
1097 if (curNum > num2)
1098 curNum -= count;
1099
1100 lastNum -= count;
1101
1102 while (count-- > 0) {
1103 nlp = lp->next;
1104 plp = lp->prev;
1105 plp->next = nlp;
1106 nlp->prev = plp;
1107 lp->next = NULL;
1108 lp->prev = NULL;
1109 lp->len = 0;
1110 free(lp);
1111 lp = nlp;
1112 }
1113
1114 dirty = TRUE;
1115
1116 return TRUE;
1117 }
1118
1119
1120 /*
1121 * Search for a line which contains the specified string.
1122 * If the string is NULL, then the previously searched for string
1123 * is used. The currently searched for string is saved for future use.
1124 * Returns the line number which matches, or 0 if there was no match
1125 * with an error printed.
1126 */
1127 static int searchLines(const char *str, int num1, int num2)
1128 {
1129 const LINE *lp;
1130 int len;
1131
1132 if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
1133 bb_error_msg("bad line numbers for search");
1134 return 0;
1135 }
1136
1137 if (*str == '\0') {
1138 if (searchString[0] == '\0') {
1139 bb_error_msg("no previous search string");
1140 return 0;
1141 }
1142
1143 str = searchString;
1144 }
1145
1146 if (str != searchString)
1147 strcpy(searchString, str);
1148
1149 len = strlen(str);
1150
1151 lp = findLine(num1);
1152
1153 if (lp == NULL)
1154 return 0;
1155
1156 while (num1 <= num2) {
1157 if (findString(lp, str, len, 0) >= 0)
1158 return num1;
1159
1160 num1++;
1161 lp = lp->next;
1162 }
1163
1164 bb_error_msg("cannot find string \"%s\"", str);
1165 return 0;
1166 }
1167
1168
1169 /*
1170 * Return a pointer to the specified line number.
1171 */
1172 static LINE *findLine(int num)
1173 {
1174 LINE *lp;
1175 int lnum;
1176
1177 if ((num < 1) || (num > lastNum)) {
1178 bb_error_msg("line number %d does not exist", num);
1179 return NULL;
1180 }
1181
1182 if (curNum <= 0) {
1183 curNum = 1;
1184 curLine = lines.next;
1185 }
1186
1187 if (num == curNum)
1188 return curLine;
1189
1190 lp = curLine;
1191 lnum = curNum;
1192
1193 if (num < (curNum / 2)) {
1194 lp = lines.next;
1195 lnum = 1;
1196 }
1197 else if (num > ((curNum + lastNum) / 2)) {
1198 lp = lines.prev;
1199 lnum = lastNum;
1200 }
1201
1202 while (lnum < num) {
1203 lp = lp->next;
1204 lnum++;
1205 }
1206
1207 while (lnum > num) {
1208 lp = lp->prev;
1209 lnum--;
1210 }
1211 return lp;
1212 }
1213
1214
1215 /*
1216 * Set the current line number.
1217 * Returns TRUE if successful.
1218 */
1219 static int setCurNum(int num)
1220 {
1221 LINE *lp;
1222
1223 lp = findLine(num);
1224
1225 if (lp == NULL)
1226 return FALSE;
1227
1228 curNum = num;
1229 curLine = lp;
1230 return TRUE;
1231 }