1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489 |
- Index: editors/Makefile.in
- ===================================================================
- --- editors/Makefile.in (revision 10144)
- +++ editors/Makefile.in (working copy)
- @@ -24,8 +24,9 @@
- srcdir=$(top_srcdir)/editors
-
- EDITOR-y:=
- -EDITOR-$(CONFIG_AWK) += awk.o
- -EDITOR-$(CONFIG_PATCH) += patch.o
- +EDITOR-$(CONFIG_AWK) += awk.o
- +EDITOR-$(CONFIG_ED) += ed.o
- +EDITOR-$(CONFIG_PATCH) += patch.o
- EDITOR-$(CONFIG_SED) += sed.o
- EDITOR-$(CONFIG_VI) += vi.o
- EDITOR_SRC:= $(EDITOR-y)
- Index: editors/Config.in
- ===================================================================
- --- editors/Config.in (revision 10144)
- +++ editors/Config.in (working copy)
- @@ -20,6 +20,12 @@
- Enable math functions of the Awk programming language.
- NOTE: This will require libm to be present for linking.
-
- +config CONFIG_ED
- + bool "ed"
- + default n
- + help
- + ed
- +
- config CONFIG_PATCH
- bool "patch"
- default n
- Index: include/usage.h
- ===================================================================
- --- include/usage.h (revision 10151)
- +++ include/usage.h (working copy)
- @@ -556,6 +561,9 @@
- "$ echo \"Erik\\nis\\ncool\"\n" \
- "Erik\\nis\\ncool\n")
-
- +#define ed_trivial_usage ""
- +#define ed_full_usage ""
- +
- #define env_trivial_usage \
- "[-iu] [-] [name=value]... [command]"
- #define env_full_usage \
- Index: include/applets.h
- ===================================================================
- --- include/applets.h (revision 10151)
- +++ include/applets.h (working copy)
- @@ -179,6 +179,9 @@
- #ifdef CONFIG_ECHO
- APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER)
- #endif
- +#ifdef CONFIG_ED
- + APPLET(ed, ed_main, _BB_DIR_BIN, _BB_SUID_NEVER)
- +#endif
- #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
- APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
- #endif
- --- /dev/null 2005-04-24 01:00:01.350003056 -0400
- +++ ed.c 2005-04-24 01:38:51.000000000 -0400
- @@ -0,0 +1,1425 @@
- +/*
- + * Copyright (c) 2002 by David I. Bell
- + * Permission is granted to use, distribute, or modify this source,
- + * provided that this copyright notice remains intact.
- + *
- + * The "ed" built-in command (much simplified)
- + */
- +
- +#include <stdio.h>
- +#include <stdlib.h>
- +#include <unistd.h>
- +#include <fcntl.h>
- +#include <string.h>
- +#include <memory.h>
- +#include <time.h>
- +#include <ctype.h>
- +#include <sys/param.h>
- +#include <malloc.h>
- +#include "busybox.h"
- +
- +#define USERSIZE 1024 /* max line length typed in by user */
- +#define INITBUF_SIZE 1024 /* initial buffer size */
- +
- +typedef int BOOL;
- +typedef int NUM;
- +typedef int LEN;
- +
- +typedef struct LINE LINE;
- +struct LINE {
- + LINE *next;
- + LINE *prev;
- + LEN len;
- + char data[1];
- +};
- +
- +static LINE lines;
- +static LINE *curLine;
- +static NUM curNum;
- +static NUM lastNum;
- +static NUM marks[26];
- +static BOOL dirty;
- +static char *fileName;
- +static char searchString[USERSIZE];
- +
- +static char *bufBase;
- +static char *bufPtr;
- +static LEN bufUsed;
- +static LEN bufSize;
- +
- +static void doCommands(void);
- +static void subCommand(const char * cmd, NUM num1, NUM num2);
- +static BOOL getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum);
- +static BOOL setCurNum(NUM num);
- +static BOOL initEdit(void);
- +static void termEdit(void);
- +static void addLines(NUM num);
- +static BOOL insertLine(NUM num, const char * data, LEN len);
- +static BOOL deleteLines(NUM num1, NUM num2);
- +static BOOL printLines(NUM num1, NUM num2, BOOL expandFlag);
- +static BOOL writeLines(const char * file, NUM num1, NUM num2);
- +static BOOL readLines(const char * file, NUM num);
- +static NUM searchLines(const char * str, NUM num1, NUM num2);
- +static LINE * findLine(NUM num);
- +
- +static LEN findString(const LINE * lp, const char * str, LEN len, LEN offset);
- +
- +int ed_main(int argc, char **argv)
- +{
- + if (!initEdit())
- + return EXIT_FAILURE;
- +
- + if (argc > 1) {
- + fileName = strdup(argv[1]);
- +
- + if (fileName == NULL) {
- + bb_error_msg("No memory");
- + termEdit();
- + return EXIT_SUCCESS;
- + }
- +
- + if (!readLines(fileName, 1)) {
- + termEdit();
- + return EXIT_SUCCESS;
- + }
- +
- + if (lastNum)
- + setCurNum(1);
- +
- + dirty = FALSE;
- + }
- +
- + doCommands();
- +
- + termEdit();
- + return EXIT_SUCCESS;
- +}
- +
- +/*
- + * Read commands until we are told to stop.
- + */
- +static void doCommands(void)
- +{
- + const char * cp;
- + char * endbuf;
- + char * newname;
- + int len;
- + NUM num1;
- + NUM num2;
- + BOOL have1;
- + BOOL have2;
- + char buf[USERSIZE];
- +
- + while (TRUE)
- + {
- + printf(": ");
- + fflush(stdout);
- +
- + if (fgets(buf, sizeof(buf), stdin) == NULL)
- + return;
- +
- + len = strlen(buf);
- +
- + if (len == 0)
- + return;
- +
- + endbuf = &buf[len - 1];
- +
- + if (*endbuf != '\n')
- + {
- + bb_error_msg("Command line too long");
- +
- + do
- + {
- + len = fgetc(stdin);
- + }
- + while ((len != EOF) && (len != '\n'));
- +
- + continue;
- + }
- +
- + while ((endbuf > buf) && isblank(endbuf[-1]))
- + endbuf--;
- +
- + *endbuf = '\0';
- +
- + cp = buf;
- +
- + while (isblank(*cp))
- + cp++;
- +
- + have1 = FALSE;
- + have2 = FALSE;
- +
- + if ((curNum == 0) && (lastNum > 0))
- + {
- + curNum = 1;
- + curLine = lines.next;
- + }
- +
- + if (!getNum(&cp, &have1, &num1))
- + continue;
- +
- + while (isblank(*cp))
- + cp++;
- +
- + if (*cp == ',')
- + {
- + cp++;
- +
- + if (!getNum(&cp, &have2, &num2))
- + continue;
- +
- + if (!have1)
- + num1 = 1;
- +
- + if (!have2)
- + num2 = lastNum;
- +
- + have1 = TRUE;
- + have2 = TRUE;
- + }
- +
- + if (!have1)
- + num1 = curNum;
- +
- + if (!have2)
- + num2 = num1;
- +
- + switch (*cp++)
- + {
- + case 'a':
- + addLines(num1 + 1);
- + break;
- +
- + case 'c':
- + deleteLines(num1, num2);
- + addLines(num1);
- + break;
- +
- + case 'd':
- + deleteLines(num1, num2);
- + break;
- +
- + case 'f':
- + if (*cp && !isblank(*cp))
- + {
- + bb_error_msg("Bad file command");
- + break;
- + }
- +
- + while (isblank(*cp))
- + cp++;
- +
- + if (*cp == '\0')
- + {
- + if (fileName)
- + printf("\"%s\"\n", fileName);
- + else
- + printf("No file name\n");
- +
- + break;
- + }
- +
- + newname = strdup(cp);
- +
- + if (newname == NULL)
- + {
- + bb_error_msg("No memory for file name");
- + break;
- + }
- +
- + if (fileName)
- + free(fileName);
- +
- + fileName = newname;
- + break;
- +
- + case 'i':
- + addLines(num1);
- + break;
- +
- + case 'k':
- + while (isblank(*cp))
- + cp++;
- +
- + if ((*cp < 'a') || (*cp > 'a') || cp[1])
- + {
- + bb_error_msg("Bad mark name");
- + break;
- + }
- +
- + marks[*cp - 'a'] = num2;
- + break;
- +
- + case 'l':
- + printLines(num1, num2, TRUE);
- + break;
- +
- + case 'p':
- + printLines(num1, num2, FALSE);
- + break;
- +
- + case 'q':
- + while (isblank(*cp))
- + cp++;
- +
- + if (have1 || *cp)
- + {
- + bb_error_msg("Bad quit command");
- + break;
- + }
- +
- + if (!dirty)
- + return;
- +
- + printf("Really quit? ");
- + fflush(stdout);
- +
- + buf[0] = '\0';
- + fgets(buf, sizeof(buf), stdin);
- + cp = buf;
- +
- + while (isblank(*cp))
- + cp++;
- +
- + if ((*cp == 'y') || (*cp == 'Y'))
- + return;
- +
- + break;
- +
- + case 'r':
- + if (*cp && !isblank(*cp))
- + {
- + bb_error_msg("Bad read command");
- + break;
- + }
- +
- + while (isblank(*cp))
- + cp++;
- +
- + if (*cp == '\0')
- + {
- + bb_error_msg("No file name");
- + break;
- + }
- +
- + if (!have1)
- + num1 = lastNum;
- +
- + if (readLines(cp, num1 + 1))
- + break;
- +
- + if (fileName == NULL)
- + fileName = strdup(cp);
- +
- + break;
- +
- + case 's':
- + subCommand(cp, num1, num2);
- + break;
- +
- + case 'w':
- + if (*cp && !isblank(*cp))
- + {
- + bb_error_msg("Bad write command");
- + break;
- + }
- +
- + while (isblank(*cp))
- + cp++;
- +
- + if (!have1) {
- + num1 = 1;
- + num2 = lastNum;
- + }
- +
- + if (*cp == '\0')
- + cp = fileName;
- +
- + if (cp == NULL)
- + {
- + bb_error_msg("No file name specified");
- + break;
- + }
- +
- + writeLines(cp, num1, num2);
- + break;
- +
- + case 'z':
- + switch (*cp)
- + {
- + case '-':
- + printLines(curNum-21, curNum, FALSE);
- + break;
- + case '.':
- + printLines(curNum-11, curNum+10, FALSE);
- + break;
- + default:
- + printLines(curNum, curNum+21, FALSE);
- + break;
- + }
- + break;
- +
- + case '.':
- + if (have1)
- + {
- + bb_error_msg("No arguments allowed");
- + break;
- + }
- +
- + printLines(curNum, curNum, FALSE);
- + break;
- +
- + case '-':
- + if (setCurNum(curNum - 1))
- + printLines(curNum, curNum, FALSE);
- +
- + break;
- +
- + case '=':
- + printf("%d\n", num1);
- + break;
- +
- + case '\0':
- + if (have1)
- + {
- + printLines(num2, num2, FALSE);
- + break;
- + }
- +
- + if (setCurNum(curNum + 1))
- + printLines(curNum, curNum, FALSE);
- +
- + break;
- +
- + default:
- + bb_error_msg("Unimplemented command");
- + break;
- + }
- + }
- +}
- +
- +
- +/*
- + * Do the substitute command.
- + * The current line is set to the last substitution done.
- + */
- +static void
- +subCommand(const char * cmd, NUM num1, NUM num2)
- +{
- + int delim;
- + char * cp;
- + char * oldStr;
- + char * newStr;
- + LEN oldLen;
- + LEN newLen;
- + LEN deltaLen;
- + LEN offset;
- + LINE * lp;
- + LINE * nlp;
- + BOOL globalFlag;
- + BOOL printFlag;
- + BOOL didSub;
- + BOOL needPrint;
- + char buf[USERSIZE];
- +
- + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
- + {
- + bb_error_msg("Bad line range for substitute");
- +
- + return;
- + }
- +
- + globalFlag = FALSE;
- + printFlag = FALSE;
- + didSub = FALSE;
- + needPrint = FALSE;
- +
- + /*
- + * Copy the command so we can modify it.
- + */
- + strcpy(buf, cmd);
- + cp = buf;
- +
- + if (isblank(*cp) || (*cp == '\0'))
- + {
- + bb_error_msg("Bad delimiter for substitute");
- +
- + return;
- + }
- +
- + delim = *cp++;
- + oldStr = cp;
- +
- + cp = strchr(cp, delim);
- +
- + if (cp == NULL)
- + {
- + bb_error_msg("Missing 2nd delimiter for substitute");
- +
- + return;
- + }
- +
- + *cp++ = '\0';
- +
- + newStr = cp;
- + cp = strchr(cp, delim);
- +
- + if (cp)
- + *cp++ = '\0';
- + else
- + cp = "";
- +
- + while (*cp) switch (*cp++)
- + {
- + case 'g':
- + globalFlag = TRUE;
- + break;
- +
- + case 'p':
- + printFlag = TRUE;
- + break;
- +
- + default:
- + bb_error_msg("Unknown option for substitute");
- +
- + return;
- + }
- +
- + if (*oldStr == '\0')
- + {
- + if (searchString[0] == '\0')
- + {
- + bb_error_msg("No previous search string");
- +
- + return;
- + }
- +
- + oldStr = searchString;
- + }
- +
- + if (oldStr != searchString)
- + strcpy(searchString, oldStr);
- +
- + lp = findLine(num1);
- +
- + if (lp == NULL)
- + return;
- +
- + oldLen = strlen(oldStr);
- + newLen = strlen(newStr);
- + deltaLen = newLen - oldLen;
- + offset = 0;
- + nlp = NULL;
- +
- + while (num1 <= num2)
- + {
- + offset = findString(lp, oldStr, oldLen, offset);
- +
- + if (offset < 0)
- + {
- + if (needPrint)
- + {
- + printLines(num1, num1, FALSE);
- + needPrint = FALSE;
- + }
- +
- + offset = 0;
- + lp = lp->next;
- + num1++;
- +
- + continue;
- + }
- +
- + needPrint = printFlag;
- + didSub = TRUE;
- + dirty = TRUE;
- +
- + /*
- + * If the replacement string is the same size or shorter
- + * than the old string, then the substitution is easy.
- + */
- + if (deltaLen <= 0)
- + {
- + memcpy(&lp->data[offset], newStr, newLen);
- +
- + if (deltaLen)
- + {
- + memcpy(&lp->data[offset + newLen],
- + &lp->data[offset + oldLen],
- + lp->len - offset - oldLen);
- +
- + lp->len += deltaLen;
- + }
- +
- + offset += newLen;
- +
- + if (globalFlag)
- + continue;
- +
- + if (needPrint)
- + {
- + printLines(num1, num1, FALSE);
- + needPrint = FALSE;
- + }
- +
- + lp = lp->next;
- + num1++;
- +
- + continue;
- + }
- +
- + /*
- + * The new string is larger, so allocate a new line
- + * structure and use that. Link it in in place of
- + * the old line structure.
- + */
- + nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen);
- +
- + if (nlp == NULL)
- + {
- + bb_error_msg("Cannot get memory for line");
- +
- + return;
- + }
- +
- + nlp->len = lp->len + deltaLen;
- +
- + memcpy(nlp->data, lp->data, offset);
- +
- + memcpy(&nlp->data[offset], newStr, newLen);
- +
- + memcpy(&nlp->data[offset + newLen],
- + &lp->data[offset + oldLen],
- + lp->len - offset - oldLen);
- +
- + nlp->next = lp->next;
- + nlp->prev = lp->prev;
- + nlp->prev->next = nlp;
- + nlp->next->prev = nlp;
- +
- + if (curLine == lp)
- + curLine = nlp;
- +
- + free(lp);
- + lp = nlp;
- +
- + offset += newLen;
- +
- + if (globalFlag)
- + continue;
- +
- + if (needPrint)
- + {
- + printLines(num1, num1, FALSE);
- + needPrint = FALSE;
- + }
- +
- + lp = lp->next;
- + num1++;
- + }
- +
- + if (!didSub)
- + bb_error_msg("No substitutions found for \"%s\"", oldStr);
- +}
- +
- +
- +/*
- + * Search a line for the specified string starting at the specified
- + * offset in the line. Returns the offset of the found string, or -1.
- + */
- +static LEN
- +findString( const LINE * lp, const char * str, LEN len, LEN offset)
- +{
- + LEN left;
- + const char * cp;
- + const char * ncp;
- +
- + cp = &lp->data[offset];
- + left = lp->len - offset;
- +
- + while (left >= len)
- + {
- + ncp = memchr(cp, *str, left);
- +
- + if (ncp == NULL)
- + return -1;
- +
- + left -= (ncp - cp);
- +
- + if (left < len)
- + return -1;
- +
- + cp = ncp;
- +
- + if (memcmp(cp, str, len) == 0)
- + return (cp - lp->data);
- +
- + cp++;
- + left--;
- + }
- +
- + return -1;
- +}
- +
- +
- +/*
- + * Add lines which are typed in by the user.
- + * The lines are inserted just before the specified line number.
- + * The lines are terminated by a line containing a single dot (ugly!),
- + * or by an end of file.
- + */
- +static void
- +addLines(NUM num)
- +{
- + int len;
- + char buf[USERSIZE + 1];
- +
- + while (fgets(buf, sizeof(buf), stdin))
- + {
- + if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
- + return;
- +
- + len = strlen(buf);
- +
- + if (len == 0)
- + return;
- +
- + if (buf[len - 1] != '\n')
- + {
- + bb_error_msg("Line too long");
- +
- + do
- + {
- + len = fgetc(stdin);
- + }
- + while ((len != EOF) && (len != '\n'));
- +
- + return;
- + }
- +
- + if (!insertLine(num++, buf, len))
- + return;
- + }
- +}
- +
- +
- +/*
- + * Parse a line number argument if it is present. This is a sum
- + * or difference of numbers, '.', '$', 'x, or a search string.
- + * Returns TRUE if successful (whether or not there was a number).
- + * Returns FALSE if there was a parsing error, with a message output.
- + * Whether there was a number is returned indirectly, as is the number.
- + * The character pointer which stopped the scan is also returned.
- + */
- +static BOOL
- +getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum)
- +{
- + const char * cp;
- + char * endStr;
- + char str[USERSIZE];
- + BOOL haveNum;
- + NUM value;
- + NUM num;
- + NUM sign;
- +
- + cp = *retcp;
- + haveNum = FALSE;
- + value = 0;
- + sign = 1;
- +
- + while (TRUE)
- + {
- + while (isblank(*cp))
- + cp++;
- +
- + switch (*cp)
- + {
- + case '.':
- + haveNum = TRUE;
- + num = curNum;
- + cp++;
- + break;
- +
- + case '$':
- + haveNum = TRUE;
- + num = lastNum;
- + cp++;
- + break;
- +
- + case '\'':
- + cp++;
- +
- + if ((*cp < 'a') || (*cp > 'z'))
- + {
- + bb_error_msg("Bad mark name");
- +
- + return FALSE;
- + }
- +
- + haveNum = TRUE;
- + num = marks[*cp++ - 'a'];
- + break;
- +
- + case '/':
- + strcpy(str, ++cp);
- + endStr = strchr(str, '/');
- +
- + if (endStr)
- + {
- + *endStr++ = '\0';
- + cp += (endStr - str);
- + }
- + else
- + cp = "";
- +
- + num = searchLines(str, curNum, lastNum);
- +
- + if (num == 0)
- + return FALSE;
- +
- + haveNum = TRUE;
- + break;
- +
- + default:
- + if (!isdigit(*cp))
- + {
- + *retcp = cp;
- + *retHaveNum = haveNum;
- + *retNum = value;
- +
- + return TRUE;
- + }
- +
- + num = 0;
- +
- + while (isdigit(*cp))
- + num = num * 10 + *cp++ - '0';
- +
- + haveNum = TRUE;
- + break;
- + }
- +
- + value += num * sign;
- +
- + while (isblank(*cp))
- + cp++;
- +
- + switch (*cp)
- + {
- + case '-':
- + sign = -1;
- + cp++;
- + break;
- +
- + case '+':
- + sign = 1;
- + cp++;
- + break;
- +
- + default:
- + *retcp = cp;
- + *retHaveNum = haveNum;
- + *retNum = value;
- +
- + return TRUE;
- + }
- + }
- +}
- +
- +
- +/*
- + * Initialize everything for editing.
- + */
- +static BOOL
- +initEdit(void)
- +{
- + int i;
- +
- + bufSize = INITBUF_SIZE;
- + bufBase = malloc(bufSize);
- +
- + if (bufBase == NULL)
- + {
- + bb_error_msg("No memory for buffer");
- +
- + return FALSE;
- + }
- +
- + bufPtr = bufBase;
- + bufUsed = 0;
- +
- + lines.next = &lines;
- + lines.prev = &lines;
- +
- + curLine = NULL;
- + curNum = 0;
- + lastNum = 0;
- + dirty = FALSE;
- + fileName = NULL;
- + searchString[0] = '\0';
- +
- + for (i = 0; i < 26; i++)
- + marks[i] = 0;
- +
- + return TRUE;
- +}
- +
- +
- +/*
- + * Finish editing.
- + */
- +static void
- +termEdit(void)
- +{
- + if (bufBase)
- + free(bufBase);
- +
- + bufBase = NULL;
- + bufPtr = NULL;
- + bufSize = 0;
- + bufUsed = 0;
- +
- + if (fileName)
- + free(fileName);
- +
- + fileName = NULL;
- +
- + searchString[0] = '\0';
- +
- + if (lastNum)
- + deleteLines(1, lastNum);
- +
- + lastNum = 0;
- + curNum = 0;
- + curLine = NULL;
- +}
- +
- +
- +/*
- + * Read lines from a file at the specified line number.
- + * Returns TRUE if the file was successfully read.
- + */
- +static BOOL
- +readLines(const char * file, NUM num)
- +{
- + int fd;
- + int cc;
- + LEN len;
- + LEN lineCount;
- + LEN charCount;
- + char * cp;
- +
- + if ((num < 1) || (num > lastNum + 1))
- + {
- + bb_error_msg("Bad line for read");
- +
- + return FALSE;
- + }
- +
- + fd = open(file, 0);
- +
- + if (fd < 0)
- + {
- + perror(file);
- +
- + return FALSE;
- + }
- +
- + bufPtr = bufBase;
- + bufUsed = 0;
- + lineCount = 0;
- + charCount = 0;
- + cc = 0;
- +
- + printf("\"%s\", ", file);
- + fflush(stdout);
- +
- + do
- + {
- + cp = memchr(bufPtr, '\n', bufUsed);
- +
- + if (cp)
- + {
- + len = (cp - bufPtr) + 1;
- +
- + if (!insertLine(num, bufPtr, len))
- + {
- + close(fd);
- +
- + return FALSE;
- + }
- +
- + bufPtr += len;
- + bufUsed -= len;
- + charCount += len;
- + lineCount++;
- + num++;
- +
- + continue;
- + }
- +
- + if (bufPtr != bufBase)
- + {
- + memcpy(bufBase, bufPtr, bufUsed);
- + bufPtr = bufBase + bufUsed;
- + }
- +
- + if (bufUsed >= bufSize)
- + {
- + len = (bufSize * 3) / 2;
- + cp = realloc(bufBase, len);
- +
- + if (cp == NULL)
- + {
- + bb_error_msg("No memory for buffer");
- + close(fd);
- +
- + return FALSE;
- + }
- +
- + bufBase = cp;
- + bufPtr = bufBase + bufUsed;
- + bufSize = len;
- + }
- +
- + cc = read(fd, bufPtr, bufSize - bufUsed);
- + bufUsed += cc;
- + bufPtr = bufBase;
- +
- + }
- + while (cc > 0);
- +
- + if (cc < 0)
- + {
- + perror(file);
- + close(fd);
- +
- + return FALSE;
- + }
- +
- + if (bufUsed)
- + {
- + if (!insertLine(num, bufPtr, bufUsed))
- + {
- + close(fd);
- +
- + return -1;
- + }
- +
- + lineCount++;
- + charCount += bufUsed;
- + }
- +
- + close(fd);
- +
- + printf("%d lines%s, %d chars\n", lineCount,
- + (bufUsed ? " (incomplete)" : ""), charCount);
- +
- + return TRUE;
- +}
- +
- +
- +/*
- + * Write the specified lines out to the specified file.
- + * Returns TRUE if successful, or FALSE on an error with a message output.
- + */
- +static BOOL
- +writeLines(const char * file, NUM num1, NUM num2)
- +{
- + int fd;
- + LINE * lp;
- + LEN lineCount;
- + LEN charCount;
- +
- + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
- + {
- + bb_error_msg("Bad line range for write");
- +
- + return FALSE;
- + }
- +
- + lineCount = 0;
- + charCount = 0;
- +
- + fd = creat(file, 0666);
- +
- + if (fd < 0) {
- + perror(file);
- +
- + return FALSE;
- + }
- +
- + printf("\"%s\", ", file);
- + fflush(stdout);
- +
- + lp = findLine(num1);
- +
- + if (lp == NULL)
- + {
- + close(fd);
- +
- + return FALSE;
- + }
- +
- + while (num1++ <= num2)
- + {
- + if (write(fd, lp->data, lp->len) != lp->len)
- + {
- + perror(file);
- + close(fd);
- +
- + return FALSE;
- + }
- +
- + charCount += lp->len;
- + lineCount++;
- + lp = lp->next;
- + }
- +
- + if (close(fd) < 0)
- + {
- + perror(file);
- +
- + return FALSE;
- + }
- +
- + printf("%d lines, %d chars\n", lineCount, charCount);
- +
- + return TRUE;
- +}
- +
- +
- +/*
- + * Print lines in a specified range.
- + * The last line printed becomes the current line.
- + * If expandFlag is TRUE, then the line is printed specially to
- + * show magic characters.
- + */
- +static BOOL
- +printLines(NUM num1, NUM num2, BOOL expandFlag)
- +{
- + const LINE * lp;
- + const unsigned char * cp;
- + int ch;
- + LEN count;
- +
- + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
- + {
- + bb_error_msg("Bad line range for print");
- +
- + return FALSE;
- + }
- +
- + lp = findLine(num1);
- +
- + if (lp == NULL)
- + return FALSE;
- +
- + while (num1 <= num2)
- + {
- + if (!expandFlag)
- + {
- + write(1, lp->data, lp->len);
- + setCurNum(num1++);
- + lp = lp->next;
- +
- + continue;
- + }
- +
- + /*
- + * Show control characters and characters with the
- + * high bit set specially.
- + */
- + cp = lp->data;
- + count = lp->len;
- +
- + if ((count > 0) && (cp[count - 1] == '\n'))
- + count--;
- +
- + while (count-- > 0)
- + {
- + ch = *cp++;
- +
- + if (ch & 0x80)
- + {
- + fputs("M-", stdout);
- + ch &= 0x7f;
- + }
- +
- + if (ch < ' ')
- + {
- + fputc('^', stdout);
- + ch += '@';
- + }
- +
- + if (ch == 0x7f)
- + {
- + fputc('^', stdout);
- + ch = '?';
- + }
- +
- + fputc(ch, stdout);
- + }
- +
- + fputs("$\n", stdout);
- +
- + setCurNum(num1++);
- + lp = lp->next;
- + }
- +
- + return TRUE;
- +}
- +
- +
- +/*
- + * Insert a new line with the specified text.
- + * The line is inserted so as to become the specified line,
- + * thus pushing any existing and further lines down one.
- + * The inserted line is also set to become the current line.
- + * Returns TRUE if successful.
- + */
- +static BOOL
- +insertLine(NUM num, const char * data, LEN len)
- +{
- + LINE * newLp;
- + LINE * lp;
- +
- + if ((num < 1) || (num > lastNum + 1))
- + {
- + bb_error_msg("Inserting at bad line number");
- +
- + return FALSE;
- + }
- +
- + newLp = (LINE *) malloc(sizeof(LINE) + len - 1);
- +
- + if (newLp == NULL)
- + {
- + bb_error_msg("Failed to allocate memory for line");
- +
- + return FALSE;
- + }
- +
- + memcpy(newLp->data, data, len);
- + newLp->len = len;
- +
- + if (num > lastNum)
- + lp = &lines;
- + else
- + {
- + lp = findLine(num);
- +
- + if (lp == NULL)
- + {
- + free((char *) newLp);
- +
- + return FALSE;
- + }
- + }
- +
- + newLp->next = lp;
- + newLp->prev = lp->prev;
- + lp->prev->next = newLp;
- + lp->prev = newLp;
- +
- + lastNum++;
- + dirty = TRUE;
- +
- + return setCurNum(num);
- +}
- +
- +
- +/*
- + * Delete lines from the given range.
- + */
- +static BOOL
- +deleteLines(NUM num1, NUM num2)
- +{
- + LINE * lp;
- + LINE * nlp;
- + LINE * plp;
- + NUM count;
- +
- + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
- + {
- + bb_error_msg("Bad line numbers for delete");
- +
- + return FALSE;
- + }
- +
- + lp = findLine(num1);
- +
- + if (lp == NULL)
- + return FALSE;
- +
- + if ((curNum >= num1) && (curNum <= num2))
- + {
- + if (num2 < lastNum)
- + setCurNum(num2 + 1);
- + else if (num1 > 1)
- + setCurNum(num1 - 1);
- + else
- + curNum = 0;
- + }
- +
- + count = num2 - num1 + 1;
- +
- + if (curNum > num2)
- + curNum -= count;
- +
- + lastNum -= count;
- +
- + while (count-- > 0)
- + {
- + nlp = lp->next;
- + plp = lp->prev;
- + plp->next = nlp;
- + nlp->prev = plp;
- + lp->next = NULL;
- + lp->prev = NULL;
- + lp->len = 0;
- + free(lp);
- + lp = nlp;
- + }
- +
- + dirty = TRUE;
- +
- + return TRUE;
- +}
- +
- +
- +/*
- + * Search for a line which contains the specified string.
- + * If the string is NULL, then the previously searched for string
- + * is used. The currently searched for string is saved for future use.
- + * Returns the line number which matches, or 0 if there was no match
- + * with an error printed.
- + */
- +static NUM
- +searchLines(const char * str, NUM num1, NUM num2)
- +{
- + const LINE * lp;
- + int len;
- +
- + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
- + {
- + bb_error_msg("Bad line numbers for search");
- +
- + return 0;
- + }
- +
- + if (*str == '\0')
- + {
- + if (searchString[0] == '\0')
- + {
- + bb_error_msg("No previous search string");
- +
- + return 0;
- + }
- +
- + str = searchString;
- + }
- +
- + if (str != searchString)
- + strcpy(searchString, str);
- +
- + len = strlen(str);
- +
- + lp = findLine(num1);
- +
- + if (lp == NULL)
- + return 0;
- +
- + while (num1 <= num2)
- + {
- + if (findString(lp, str, len, 0) >= 0)
- + return num1;
- +
- + num1++;
- + lp = lp->next;
- + }
- +
- + bb_error_msg("Cannot find string \"%s\"", str);
- +
- + return 0;
- +}
- +
- +
- +/*
- + * Return a pointer to the specified line number.
- + */
- +static LINE *
- +findLine(NUM num)
- +{
- + LINE * lp;
- + NUM lnum;
- +
- + if ((num < 1) || (num > lastNum))
- + {
- + bb_error_msg("Line number %d does not exist", num);
- +
- + return NULL;
- + }
- +
- + if (curNum <= 0)
- + {
- + curNum = 1;
- + curLine = lines.next;
- + }
- +
- + if (num == curNum)
- + return curLine;
- +
- + lp = curLine;
- + lnum = curNum;
- +
- + if (num < (curNum / 2))
- + {
- + lp = lines.next;
- + lnum = 1;
- + }
- + else if (num > ((curNum + lastNum) / 2))
- + {
- + lp = lines.prev;
- + lnum = lastNum;
- + }
- +
- + while (lnum < num)
- + {
- + lp = lp->next;
- + lnum++;
- + }
- +
- + while (lnum > num)
- + {
- + lp = lp->prev;
- + lnum--;
- + }
- +
- + return lp;
- +}
- +
- +
- +/*
- + * Set the current line number.
- + * Returns TRUE if successful.
- + */
- +static BOOL
- +setCurNum(NUM num)
- +{
- + LINE * lp;
- +
- + lp = findLine(num);
- +
- + if (lp == NULL)
- + return FALSE;
- +
- + curNum = num;
- + curLine = lp;
- +
- + return TRUE;
- +}
- +
- +/* END CODE */
|