blob: 6d51830a5196c6abc2f3514b2ab130b586bd35f9 [file] [log] [blame]
Mike Frysinger84ab2672005-04-23 01:50:55 +00001Index: 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)
17Index: 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
34Index: 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 \
48Index: 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
Mike Frysingercf131bb2005-04-24 05:18:00 +000062--- /dev/null 2005-04-24 01:00:01.350003056 -0400
Mike Frysinger560047c2005-04-24 05:39:52 +000063+++ ed.c 2005-04-24 01:38:51.000000000 -0400
64@@ -0,0 +1,1425 @@
Mike Frysinger84ab2672005-04-23 01:50:55 +000065+/*
Mike Frysingercf131bb2005-04-24 05:18:00 +000066+ * 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.
Mike Frysinger84ab2672005-04-23 01:50:55 +000069+ *
Mike Frysingercf131bb2005-04-24 05:18:00 +000070+ * The "ed" built-in command (much simplified)
Mike Frysinger84ab2672005-04-23 01:50:55 +000071+ */
72+
Mike Frysinger84ab2672005-04-23 01:50:55 +000073+#include <stdio.h>
Mike Frysingercf131bb2005-04-24 05:18:00 +000074+#include <stdlib.h>
Mike Frysinger84ab2672005-04-23 01:50:55 +000075+#include <unistd.h>
Mike Frysingercf131bb2005-04-24 05:18:00 +000076+#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>
Mike Frysinger560047c2005-04-24 05:39:52 +000083+#include "busybox.h"
Mike Frysinger84ab2672005-04-23 01:50:55 +000084+
Mike Frysingercf131bb2005-04-24 05:18:00 +000085+#define USERSIZE 1024 /* max line length typed in by user */
86+#define INITBUF_SIZE 1024 /* initial buffer size */
Mike Frysinger84ab2672005-04-23 01:50:55 +000087+
Mike Frysingercf131bb2005-04-24 05:18:00 +000088+typedef int BOOL;
Mike Frysingercf131bb2005-04-24 05:18:00 +000089+typedef int NUM;
90+typedef int LEN;
Mike Frysinger84ab2672005-04-23 01:50:55 +000091+
Mike Frysinger560047c2005-04-24 05:39:52 +000092+typedef struct LINE LINE;
93+struct LINE {
94+ LINE *next;
95+ LINE *prev;
Mike Frysingercf131bb2005-04-24 05:18:00 +000096+ LEN len;
Mike Frysinger560047c2005-04-24 05:39:52 +000097+ char data[1];
Mike Frysinger84ab2672005-04-23 01:50:55 +000098+};
99+
Mike Frysinger560047c2005-04-24 05:39:52 +0000100+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];
Mike Frysinger84ab2672005-04-23 01:50:55 +0000108+
Mike Frysinger560047c2005-04-24 05:39:52 +0000109+static char *bufBase;
110+static char *bufPtr;
111+static LEN bufUsed;
112+static LEN bufSize;
Mike Frysingercf131bb2005-04-24 05:18:00 +0000113+
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+
Mike Frysinger560047c2005-04-24 05:39:52 +0000129+static LEN findString(const LINE * lp, const char * str, LEN len, LEN offset);
Mike Frysingercf131bb2005-04-24 05:18:00 +0000130+
Mike Frysinger560047c2005-04-24 05:39:52 +0000131+int ed_main(int argc, char **argv)
Mike Frysinger84ab2672005-04-23 01:50:55 +0000132+{
Mike Frysingercf131bb2005-04-24 05:18:00 +0000133+ if (!initEdit())
Mike Frysinger560047c2005-04-24 05:39:52 +0000134+ return EXIT_FAILURE;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000135+
Mike Frysinger560047c2005-04-24 05:39:52 +0000136+ if (argc > 1) {
Mike Frysingercf131bb2005-04-24 05:18:00 +0000137+ fileName = strdup(argv[1]);
Mike Frysinger84ab2672005-04-23 01:50:55 +0000138+
Mike Frysinger560047c2005-04-24 05:39:52 +0000139+ if (fileName == NULL) {
140+ bb_error_msg("No memory");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000141+ termEdit();
Mike Frysinger560047c2005-04-24 05:39:52 +0000142+ return EXIT_SUCCESS;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000143+ }
Mike Frysinger84ab2672005-04-23 01:50:55 +0000144+
Mike Frysinger560047c2005-04-24 05:39:52 +0000145+ if (!readLines(fileName, 1)) {
Mike Frysingercf131bb2005-04-24 05:18:00 +0000146+ termEdit();
Mike Frysinger560047c2005-04-24 05:39:52 +0000147+ return EXIT_SUCCESS;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000148+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +0000149+
150+ if (lastNum)
151+ setCurNum(1);
152+
153+ dirty = FALSE;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000154+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +0000155+
156+ doCommands();
157+
158+ termEdit();
Mike Frysinger560047c2005-04-24 05:39:52 +0000159+ return EXIT_SUCCESS;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000160+}
161+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000162+/*
163+ * Read commands until we are told to stop.
164+ */
Mike Frysinger560047c2005-04-24 05:39:52 +0000165+static void doCommands(void)
Mike Frysinger84ab2672005-04-23 01:50:55 +0000166+{
Mike Frysingercf131bb2005-04-24 05:18:00 +0000167+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000194+ bb_error_msg("Command line too long");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000195+
196+ do
197+ {
198+ len = fgetc(stdin);
199+ }
200+ while ((len != EOF) && (len != '\n'));
201+
202+ continue;
203+ }
204+
Mike Frysinger560047c2005-04-24 05:39:52 +0000205+ while ((endbuf > buf) && isblank(endbuf[-1]))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000206+ endbuf--;
207+
208+ *endbuf = '\0';
209+
210+ cp = buf;
211+
Mike Frysinger560047c2005-04-24 05:39:52 +0000212+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000213+ 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+
Mike Frysinger560047c2005-04-24 05:39:52 +0000227+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000228+ 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':
Mike Frysinger560047c2005-04-24 05:39:52 +0000269+ if (*cp && !isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000270+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000271+ bb_error_msg("Bad file command");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000272+ break;
273+ }
274+
Mike Frysinger560047c2005-04-24 05:39:52 +0000275+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000276+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000292+ bb_error_msg("No memory for file name");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000293+ 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':
Mike Frysinger560047c2005-04-24 05:39:52 +0000307+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000308+ cp++;
309+
310+ if ((*cp < 'a') || (*cp > 'a') || cp[1])
311+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000312+ bb_error_msg("Bad mark name");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000313+ 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':
Mike Frysinger560047c2005-04-24 05:39:52 +0000328+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000329+ cp++;
330+
331+ if (have1 || *cp)
332+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000333+ bb_error_msg("Bad quit command");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000334+ 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+
Mike Frysinger560047c2005-04-24 05:39:52 +0000347+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000348+ cp++;
349+
350+ if ((*cp == 'y') || (*cp == 'Y'))
351+ return;
352+
353+ break;
354+
355+ case 'r':
Mike Frysinger560047c2005-04-24 05:39:52 +0000356+ if (*cp && !isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000357+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000358+ bb_error_msg("Bad read command");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000359+ break;
360+ }
361+
Mike Frysinger560047c2005-04-24 05:39:52 +0000362+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000363+ cp++;
364+
365+ if (*cp == '\0')
366+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000367+ bb_error_msg("No file name");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000368+ 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':
Mike Frysinger560047c2005-04-24 05:39:52 +0000387+ if (*cp && !isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000388+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000389+ bb_error_msg("Bad write command");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000390+ break;
391+ }
392+
Mike Frysinger560047c2005-04-24 05:39:52 +0000393+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000394+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000406+ bb_error_msg("No file name specified");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000407+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000431+ bb_error_msg("No arguments allowed");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000432+ 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:
Mike Frysinger560047c2005-04-24 05:39:52 +0000461+ bb_error_msg("Unimplemented command");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000462+ break;
463+ }
464+ }
Mike Frysinger84ab2672005-04-23 01:50:55 +0000465+}
466+
467+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000468+/*
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)
Mike Frysinger84ab2672005-04-23 01:50:55 +0000474+{
Mike Frysingercf131bb2005-04-24 05:18:00 +0000475+ 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];
Mike Frysinger84ab2672005-04-23 01:50:55 +0000490+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000491+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
Mike Frysinger84ab2672005-04-23 01:50:55 +0000492+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000493+ bb_error_msg("Bad line range for substitute");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000494+
495+ return;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000496+ }
Mike Frysinger84ab2672005-04-23 01:50:55 +0000497+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000498+ globalFlag = FALSE;
499+ printFlag = FALSE;
500+ didSub = FALSE;
501+ needPrint = FALSE;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000502+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000503+ /*
504+ * Copy the command so we can modify it.
505+ */
506+ strcpy(buf, cmd);
507+ cp = buf;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000508+
Mike Frysinger560047c2005-04-24 05:39:52 +0000509+ if (isblank(*cp) || (*cp == '\0'))
Mike Frysinger84ab2672005-04-23 01:50:55 +0000510+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000511+ bb_error_msg("Bad delimiter for substitute");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000512+
513+ return;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000514+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +0000515+
516+ delim = *cp++;
517+ oldStr = cp;
518+
519+ cp = strchr(cp, delim);
520+
521+ if (cp == NULL)
Mike Frysinger84ab2672005-04-23 01:50:55 +0000522+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000523+ bb_error_msg("Missing 2nd delimiter for substitute");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000524+
525+ return;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000526+ }
Mike Frysinger84ab2672005-04-23 01:50:55 +0000527+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000528+ *cp++ = '\0';
Mike Frysinger84ab2672005-04-23 01:50:55 +0000529+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000530+ newStr = cp;
531+ cp = strchr(cp, delim);
Mike Frysinger84ab2672005-04-23 01:50:55 +0000532+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000533+ if (cp)
534+ *cp++ = '\0';
Mike Frysinger84ab2672005-04-23 01:50:55 +0000535+ else
Mike Frysingercf131bb2005-04-24 05:18:00 +0000536+ 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:
Mike Frysinger560047c2005-04-24 05:39:52 +0000549+ bb_error_msg("Unknown option for substitute");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000550+
551+ return;
552+ }
553+
554+ if (*oldStr == '\0')
555+ {
556+ if (searchString[0] == '\0')
557+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000558+ bb_error_msg("No previous search string");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000559+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000646+ bb_error_msg("Cannot get memory for line");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000647+
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)
Mike Frysinger560047c2005-04-24 05:39:52 +0000688+ bb_error_msg("No substitutions found for \"%s\"", oldStr);
Mike Frysinger84ab2672005-04-23 01:50:55 +0000689+}
690+
691+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000692+/*
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)
Mike Frysinger84ab2672005-04-23 01:50:55 +0000698+{
Mike Frysingercf131bb2005-04-24 05:18:00 +0000699+ LEN left;
700+ const char * cp;
701+ const char * ncp;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000702+
Mike Frysingercf131bb2005-04-24 05:18:00 +0000703+ cp = &lp->data[offset];
704+ left = lp->len - offset;
705+
706+ while (left >= len)
Mike Frysinger84ab2672005-04-23 01:50:55 +0000707+ {
Mike Frysingercf131bb2005-04-24 05:18:00 +0000708+ 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--;
Mike Frysinger84ab2672005-04-23 01:50:55 +0000725+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +0000726+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000755+ bb_error_msg("Line too long");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000756+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000798+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000799+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000820+ bb_error_msg("Bad mark name");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000821+
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:
Mike Frysinger560047c2005-04-24 05:39:52 +0000850+ if (!isdigit(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000851+ {
852+ *retcp = cp;
853+ *retHaveNum = haveNum;
854+ *retNum = value;
855+
856+ return TRUE;
857+ }
858+
859+ num = 0;
860+
Mike Frysinger560047c2005-04-24 05:39:52 +0000861+ while (isdigit(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000862+ num = num * 10 + *cp++ - '0';
863+
864+ haveNum = TRUE;
865+ break;
866+ }
867+
868+ value += num * sign;
869+
Mike Frysinger560047c2005-04-24 05:39:52 +0000870+ while (isblank(*cp))
Mike Frysingercf131bb2005-04-24 05:18:00 +0000871+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000909+ bb_error_msg("No memory for buffer");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000910+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +0000980+ bb_error_msg("Bad line for read");
Mike Frysingercf131bb2005-04-24 05:18:00 +0000981+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001040+ bb_error_msg("No memory for buffer");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001041+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001102+ bb_error_msg("Bad line range for write");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001103+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001174+ bb_error_msg("Bad line range for print");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001175+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001188+ write(1, lp->data, lp->len);
Mike Frysingercf131bb2005-04-24 05:18:00 +00001189+ 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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001255+ bb_error_msg("Inserting at bad line number");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001256+
1257+ return FALSE;
1258+ }
1259+
1260+ newLp = (LINE *) malloc(sizeof(LINE) + len - 1);
1261+
1262+ if (newLp == NULL)
1263+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001264+ bb_error_msg("Failed to allocate memory for line");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001265+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001311+ bb_error_msg("Bad line numbers for delete");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001312+
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+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001372+ bb_error_msg("Bad line numbers for search");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001373+
1374+ return 0;
1375+ }
1376+
1377+ if (*str == '\0')
1378+ {
1379+ if (searchString[0] == '\0')
1380+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001381+ bb_error_msg("No previous search string");
Mike Frysingercf131bb2005-04-24 05:18:00 +00001382+
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+
Mike Frysinger560047c2005-04-24 05:39:52 +00001408+ bb_error_msg("Cannot find string \"%s\"", str);
Mike Frysingercf131bb2005-04-24 05:18:00 +00001409+
Mike Frysinger84ab2672005-04-23 01:50:55 +00001410+ return 0;
Mike Frysingercf131bb2005-04-24 05:18:00 +00001411+}
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))
Mike Frysinger84ab2672005-04-23 01:50:55 +00001424+ {
Mike Frysinger560047c2005-04-24 05:39:52 +00001425+ bb_error_msg("Line number %d does not exist", num);
Mike Frysingercf131bb2005-04-24 05:18:00 +00001426+
1427+ return NULL;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001428+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +00001429+
1430+ if (curNum <= 0)
Mike Frysinger84ab2672005-04-23 01:50:55 +00001431+ {
Mike Frysingercf131bb2005-04-24 05:18:00 +00001432+ curNum = 1;
1433+ curLine = lines.next;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001434+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +00001435+
1436+ if (num == curNum)
1437+ return curLine;
1438+
1439+ lp = curLine;
1440+ lnum = curNum;
1441+
1442+ if (num < (curNum / 2))
Mike Frysinger84ab2672005-04-23 01:50:55 +00001443+ {
Mike Frysingercf131bb2005-04-24 05:18:00 +00001444+ lp = lines.next;
1445+ lnum = 1;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001446+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +00001447+ else if (num > ((curNum + lastNum) / 2))
Mike Frysinger84ab2672005-04-23 01:50:55 +00001448+ {
Mike Frysingercf131bb2005-04-24 05:18:00 +00001449+ lp = lines.prev;
1450+ lnum = lastNum;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001451+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +00001452+
1453+ while (lnum < num)
Mike Frysinger84ab2672005-04-23 01:50:55 +00001454+ {
Mike Frysingercf131bb2005-04-24 05:18:00 +00001455+ lp = lp->next;
1456+ lnum++;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001457+ }
Mike Frysinger84ab2672005-04-23 01:50:55 +00001458+
Mike Frysingercf131bb2005-04-24 05:18:00 +00001459+ while (lnum > num)
Mike Frysinger84ab2672005-04-23 01:50:55 +00001460+ {
Mike Frysingercf131bb2005-04-24 05:18:00 +00001461+ lp = lp->prev;
1462+ lnum--;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001463+ }
Mike Frysingercf131bb2005-04-24 05:18:00 +00001464+
1465+ return lp;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001466+}
1467+
1468+
Mike Frysingercf131bb2005-04-24 05:18:00 +00001469+/*
1470+ * Set the current line number.
1471+ * Returns TRUE if successful.
1472+ */
1473+static BOOL
1474+setCurNum(NUM num)
Mike Frysinger84ab2672005-04-23 01:50:55 +00001475+{
Mike Frysingercf131bb2005-04-24 05:18:00 +00001476+ LINE * lp;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001477+
Mike Frysingercf131bb2005-04-24 05:18:00 +00001478+ lp = findLine(num);
Mike Frysinger84ab2672005-04-23 01:50:55 +00001479+
Mike Frysingercf131bb2005-04-24 05:18:00 +00001480+ if (lp == NULL)
1481+ return FALSE;
1482+
1483+ curNum = num;
1484+ curLine = lp;
1485+
1486+ return TRUE;
Mike Frysinger84ab2672005-04-23 01:50:55 +00001487+}
1488+
Mike Frysingercf131bb2005-04-24 05:18:00 +00001489+/* END CODE */