source: MondoRescue/branches/stable/mindi-busybox/editors/ed.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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