* reordered a little bit
[mascara-docs.git] / i86 / elks / elkscmd / sash / cmd_ed.c
bloba858e5a5b618e459b970a09aa689d4fb44c246ea
1 /*
2 * Copyright (c) 1993 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
6 * The "ed" built-in command (much simplified)
7 */
9 #include "sash.h"
10 #ifdef CMD_ED
12 #define USERSIZE 1024 /* max line length typed in by user */
13 #define INITBUFSIZE 1024 /* initial buffer size */
16 typedef int NUM;
17 typedef int LEN;
19 typedef struct LINE LINE;
20 struct LINE {
21 LINE *next;
22 LINE *prev;
23 LEN len;
24 char data[1];
28 static LINE lines;
29 static LINE *curline;
30 static NUM curnum;
31 static NUM lastnum;
32 static NUM marks[26];
33 static BOOL dirty;
34 static char *filename;
35 static char searchstring[USERSIZE];
37 static char *bufbase;
38 static char *bufptr;
39 static LEN bufused;
40 static LEN bufsize;
43 static void docommands();
44 static void subcommand();
45 static BOOL getnum();
46 static BOOL setcurnum();
47 static BOOL initedit();
48 static void termedit();
49 static void addlines();
50 static BOOL insertline();
51 static BOOL deletelines();
52 static BOOL printlines();
53 static BOOL writelines();
54 static BOOL readlines();
55 static NUM searchlines();
56 static LEN findstring();
57 static LINE *findline();
60 void
61 do_ed(argc, argv)
62 char **argv;
64 if (!initedit())
65 return;
67 if (argc > 1) {
68 filename = strdup(argv[1]);
69 if (filename == NULL) {
70 fprintf(stderr, "No memory\n");
71 termedit();
72 return;
75 if (!readlines(filename, 1)) {
76 termedit();
77 return;
80 if (lastnum)
81 setcurnum(1);
83 dirty = FALSE;
86 docommands();
88 termedit();
93 * Read commands until we are told to stop.
95 static void
96 docommands()
98 char *cp;
99 int len;
100 NUM num1;
101 NUM num2;
102 BOOL have1;
103 BOOL have2;
104 char buf[USERSIZE];
106 while (TRUE) {
107 intflag = FALSE;
108 printf(": ");
109 fflush(stdout);
111 if (fgets(buf, sizeof(buf), stdin) == NULL)
112 return;
114 len = strlen(buf);
115 if (len == 0)
116 return;
118 cp = &buf[len - 1];
119 if (*cp != '\n') {
120 fprintf(stderr, "Command line too long\n");
121 do {
122 len = fgetc(stdin);
123 } while ((len != EOF) && (len != '\n'));
125 continue;
128 while ((cp > buf) && isblank(cp[-1]))
129 cp--;
130 *cp = '\0';
132 cp = buf;
133 while (isblank(*cp))
134 *cp++;
136 have1 = FALSE;
137 have2 = FALSE;
139 if ((curnum == 0) && (lastnum > 0)) {
140 curnum = 1;
141 curline = lines.next;
144 if (!getnum(&cp, &have1, &num1))
145 continue;
147 while (isblank(*cp))
148 cp++;
150 if (*cp == ',') {
151 cp++;
152 if (!getnum(&cp, &have2, &num2))
153 continue;
155 if (!have1)
156 num1 = 1;
158 if (!have2)
159 num2 = lastnum;
161 have1 = TRUE;
162 have2 = TRUE;
165 if (!have1)
166 num1 = curnum;
168 if (!have2)
169 num2 = num1;
171 switch (*cp++) {
172 case 'a':
173 addlines(num1 + 1);
174 break;
176 case 'c':
177 deletelines(num1, num2);
178 addlines(num1);
179 break;
181 case 'd':
182 deletelines(num1, num2);
183 break;
185 case 'f':
186 if (*cp && !isblank(*cp)) {
187 fprintf(stderr, "Bad file command\n");
188 break;
191 while (isblank(*cp))
192 cp++;
193 if (*cp == '\0') {
194 if (filename)
195 printf("\"%s\"\n", filename);
196 else
197 printf("No filename\n");
198 break;
201 cp = strdup(cp);
202 if (cp == NULL) {
203 fprintf(stderr, "No memory for filename\n");
204 break;
207 if (filename)
208 free(filename);
209 filename = cp;
210 break;
212 case 'i':
213 addlines(num1);
214 break;
216 case 'k':
217 while (isblank(*cp))
218 cp++;
220 if ((*cp < 'a') || (*cp > 'a') || cp[1]) {
221 fprintf(stderr, "Bad mark name\n");
222 break;
225 marks[*cp - 'a'] = num2;
226 break;
228 case 'l':
229 printlines(num1, num2, TRUE);
230 break;
232 case 'p':
233 printlines(num1, num2, FALSE);
234 break;
236 case 'q':
237 while (isblank(*cp))
238 cp++;
239 if (have1 || *cp) {
240 fprintf(stderr, "Bad quit command\n");
241 break;
244 if (!dirty)
245 return;
247 printf("Really quit? ");
248 fflush(stdout);
250 buf[0] = '\0';
251 fgets(buf, sizeof(buf), stdin);
252 cp = buf;
253 while (isblank(*cp))
254 cp++;
255 if ((*cp == 'y') || (*cp == 'Y'))
256 return;
257 break;
259 case 'r':
260 if (*cp && !isblank(*cp)) {
261 fprintf(stderr, "Bad read command\n");
262 break;
265 while (isblank(*cp))
266 cp++;
267 if (*cp == '\0') {
268 fprintf(stderr, "No filename\n");
269 break;
272 if (!have1)
273 num1 = lastnum;
275 if (readlines(cp, num1 + 1))
276 break;
278 if (filename == NULL)
279 filename = strdup(cp);
280 break;
282 case 's':
283 subcommand(cp, num1, num2);
284 break;
286 case 'w':
287 if (*cp && !isblank(*cp)) {
288 fprintf(stderr, "Bad write command\n");
289 break;
291 while (isblank(*cp))
292 cp++;
294 if (!have1) {
295 num1 = 1;
296 num2 = lastnum;
299 if (*cp == '\0')
300 cp = filename;
301 if (cp == NULL) {
302 fprintf(stderr, "No file name specified\n");
303 break;
306 writelines(cp, num1, num2);
307 break;
309 case 'z':
310 switch (*cp) {
311 case '-':
312 printlines(curnum-21, curnum, FALSE);
313 break;
314 case '.':
315 printlines(curnum-11, curnum+10, FALSE);
316 break;
317 default:
318 printlines(curnum, curnum+21, FALSE);
319 break;
321 break;
323 case '.':
324 if (have1) {
325 fprintf(stderr, "No arguments allowed\n");
326 break;
328 printlines(curnum, curnum, FALSE);
329 break;
331 case '-':
332 if (setcurnum(curnum - 1))
333 printlines(curnum, curnum, FALSE);
334 break;
336 case '=':
337 printf("%d\n", num1);
338 break;
340 case '\0':
341 if (have1) {
342 printlines(num2, num2, FALSE);
343 break;
346 if (setcurnum(curnum + 1))
347 printlines(curnum, curnum, FALSE);
348 break;
350 default:
351 fprintf(stderr, "Unimplemented command\n");
352 break;
359 * Do the substitute command.
360 * The current line is set to the last substitution done.
362 static void
363 subcommand(cp, num1, num2)
364 char *cp;
365 NUM num1;
366 NUM num2;
368 int delim;
369 char *oldstr;
370 char *newstr;
371 LEN oldlen;
372 LEN newlen;
373 LEN deltalen;
374 LEN offset;
375 LINE *lp;
376 LINE *nlp;
377 BOOL globalflag;
378 BOOL printflag;
379 BOOL didsub;
380 BOOL needprint;
382 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
383 fprintf(stderr, "Bad line range for substitute\n");
384 return;
387 globalflag = FALSE;
388 printflag = FALSE;
389 didsub = FALSE;
390 needprint = FALSE;
392 if (isblank(*cp) || (*cp == '\0')) {
393 fprintf(stderr, "Bad delimiter for substitute\n");
394 return;
397 delim = *cp++;
398 oldstr = cp;
400 cp = strchr(cp, delim);
401 if (cp == NULL) {
402 fprintf(stderr, "Missing 2nd delimiter for substitute\n");
403 return;
405 *cp++ = '\0';
407 newstr = cp;
408 cp = strchr(cp, delim);
409 if (cp)
410 *cp++ = '\0';
411 else
412 cp = "";
414 while (*cp) switch (*cp++) {
415 case 'g':
416 globalflag = TRUE;
417 break;
419 case 'p':
420 printflag = TRUE;
421 break;
423 default:
424 fprintf(stderr, "Unknown option for substitute\n");
425 return;
428 if (*oldstr == '\0') {
429 if (searchstring[0] == '\0') {
430 fprintf(stderr, "No previous search string\n");
431 return;
433 oldstr = searchstring;
436 if (oldstr != searchstring)
437 strcpy(searchstring, oldstr);
439 lp = findline(num1);
440 if (lp == NULL)
441 return;
443 oldlen = strlen(oldstr);
444 newlen = strlen(newstr);
445 deltalen = newlen - oldlen;
446 offset = 0;
448 while (num1 <= num2) {
449 offset = findstring(lp, oldstr, oldlen, offset);
450 if (offset < 0) {
451 if (needprint) {
452 printlines(num1, num1, FALSE);
453 needprint = FALSE;
456 offset = 0;
457 lp = lp->next;
458 num1++;
459 continue;
462 needprint = printflag;
463 didsub = TRUE;
464 dirty = TRUE;
467 * If the replacement string is the same size or shorter
468 * than the old string, then the substitution is easy.
470 if (deltalen <= 0) {
471 memcpy(&lp->data[offset], newstr, newlen);
473 if (deltalen) {
474 memcpy(&lp->data[offset + newlen],
475 &lp->data[offset + oldlen],
476 lp->len - offset - oldlen);
478 lp->len += deltalen;
481 offset += newlen;
482 if (globalflag)
483 continue;
485 if (needprint) {
486 printlines(num1, num1, FALSE);
487 needprint = FALSE;
490 lp = nlp->next;
491 num1++;
492 continue;
496 * The new string is larger, so allocate a new line
497 * structure and use that. Link it in in place of
498 * the old line structure.
500 nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltalen);
501 if (nlp == NULL) {
502 fprintf(stderr, "Cannot get memory for line\n");
503 return;
505 nlp->len = lp->len + deltalen;
507 memcpy(nlp->data, lp->data, offset);
509 memcpy(&nlp->data[offset], newstr, newlen);
511 memcpy(&nlp->data[offset + newlen],
512 &lp->data[offset + oldlen],
513 lp->len - offset - oldlen);
515 nlp->next = lp->next;
516 nlp->prev = lp->prev;
517 nlp->prev->next = nlp;
518 nlp->next->prev = nlp;
520 if (curline == lp)
521 curline = nlp;
523 free(lp);
524 lp = nlp;
526 offset += newlen;
528 if (globalflag)
529 continue;
531 if (needprint) {
532 printlines(num1, num1, FALSE);
533 needprint = FALSE;
536 lp = lp->next;
537 num1++;
540 if (!didsub)
541 fprintf(stderr, "No substitutions found for \"%s\"\n", oldstr);
546 * Search a line for the specified string starting at the specified
547 * offset in the line. Returns the offset of the found string, or -1.
549 static LEN
550 findstring(lp, str, len, offset)
551 LINE *lp;
552 char *str;
553 LEN len;
554 LEN offset;
556 LEN left;
557 char *cp;
558 char *ncp;
560 cp = &lp->data[offset];
561 left = lp->len - offset;
563 while (left >= len) {
564 ncp = memchr(cp, *str, left);
565 if (ncp == NULL)
566 return -1;
568 left -= (ncp - cp);
569 if (left < len)
570 return -1;
572 cp = ncp;
573 if (memcmp(cp, str, len) == 0)
574 return (cp - lp->data);
576 cp++;
577 left--;
580 return -1;
585 * Add lines which are typed in by the user.
586 * The lines are inserted just before the specified line number.
587 * The lines are terminated by a line containing a single dot (ugly!),
588 * or by an end of file.
590 static void
591 addlines(num)
592 NUM num;
594 int len;
595 char buf[USERSIZE + 1];
597 while (fgets(buf, sizeof(buf), stdin)) {
598 if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
599 return;
601 len = strlen(buf);
602 if (len == 0)
603 return;
605 if (buf[len - 1] != '\n') {
606 fprintf(stderr, "Line too long\n");
607 do {
608 len = fgetc(stdin);
609 } while ((len != EOF) && (len != '\n'));
610 return;
613 if (!insertline(num++, buf, len))
614 return;
620 * Parse a line number argument if it is present. This is a sum
621 * or difference of numbers, '.', '$', 'x, or a search string.
622 * Returns TRUE if successful (whether or not there was a number).
623 * Returns FALSE if there was a parsing error, with a message output.
624 * Whether there was a number is returned indirectly, as is the number.
625 * The character pointer which stopped the scan is also returned.
627 static BOOL
628 getnum(retcp, rethavenum, retnum)
629 char **retcp;
630 BOOL *rethavenum;
631 NUM *retnum;
633 char *cp;
634 char *str;
635 BOOL havenum;
636 NUM value;
637 NUM num;
638 NUM sign;
640 cp = *retcp;
641 havenum = FALSE;
642 value = 0;
643 sign = 1;
645 while (TRUE) {
646 while (isblank(*cp))
647 cp++;
649 switch (*cp) {
650 case '.':
651 havenum = TRUE;
652 num = curnum;
653 cp++;
654 break;
656 case '$':
657 havenum = TRUE;
658 num = lastnum;
659 cp++;
660 break;
662 case '\'':
663 cp++;
664 if ((*cp < 'a') || (*cp > 'z')) {
665 fprintf(stderr, "Bad mark name\n");
666 return FALSE;
669 havenum = TRUE;
670 num = marks[*cp++ - 'a'];
671 break;
673 case '/':
674 str = ++cp;
675 cp = strchr(str, '/');
676 if (cp)
677 *cp++ = '\0';
678 else
679 cp = "";
680 num = searchlines(str, curnum, lastnum);
681 if (num == 0)
682 return FALSE;
684 havenum = TRUE;
685 break;
687 default:
688 if (!isdecimal(*cp)) {
689 *retcp = cp;
690 *rethavenum = havenum;
691 *retnum = value;
692 return TRUE;
695 num = 0;
696 while (isdecimal(*cp))
697 num = num * 10 + *cp++ - '0';
698 havenum = TRUE;
699 break;
702 value += num * sign;
704 while (isblank(*cp))
705 cp++;
707 switch (*cp) {
708 case '-':
709 sign = -1;
710 cp++;
711 break;
712 case '+':
713 sign = 1;
714 cp++;
715 break;
717 default:
718 *retcp = cp;
719 *rethavenum = havenum;
720 *retnum = value;
721 return TRUE;
728 * Initialize everything for editing.
730 static BOOL
731 initedit()
733 int i;
735 bufsize = INITBUFSIZE;
736 bufbase = malloc(bufsize);
737 if (bufbase == NULL) {
738 fprintf(stderr, "No memory for buffer\n");
739 return FALSE;
742 bufptr = bufbase;
743 bufused = 0;
745 lines.next = &lines;
746 lines.prev = &lines;
748 curline = NULL;
749 curnum = 0;
750 lastnum = 0;
751 dirty = FALSE;
752 filename = NULL;
753 searchstring[0] = '\0';
755 for (i = 0; i < 26; i++)
756 marks[i] = 0;
761 * Finish editing.
763 static void
764 termedit()
766 if (bufbase)
767 free(bufbase);
768 bufbase = NULL;
769 bufptr = NULL;
770 bufsize = 0;
771 bufused = 0;
773 if (filename)
774 free(filename);
775 filename = NULL;
777 searchstring[0] = '\0';
779 if (lastnum)
780 deletelines(1, lastnum);
782 lastnum = 0;
783 curnum = 0;
784 curline = NULL;
789 * Read lines from a file at the specified line number.
790 * Returns TRUE if the file was successfully read.
792 static BOOL
793 readlines(file, num)
794 char *file;
795 NUM num;
797 int fd;
798 int cc;
799 LEN len;
800 LEN linecount;
801 LEN charcount;
802 char *cp;
804 if ((num < 1) || (num > lastnum + 1)) {
805 fprintf(stderr, "Bad line for read\n");
806 return FALSE;
809 fd = open(file, 0);
810 if (fd < 0) {
811 perror(file);
812 return FALSE;
815 bufptr = bufbase;
816 bufused = 0;
817 linecount = 0;
818 charcount = 0;
820 printf("\"%s\", ", file);
821 fflush(stdout);
823 do {
824 if (intflag) {
825 printf("INTERRUPTED, ");
826 bufused = 0;
827 break;
830 cp = memchr(bufptr, '\n', bufused);
831 if (cp) {
832 len = (cp - bufptr) + 1;
833 if (!insertline(num, bufptr, len)) {
834 close(fd);
835 return FALSE;
838 bufptr += len;
839 bufused -= len;
840 charcount += len;
841 linecount++;
842 num++;
843 continue;
846 if (bufptr != bufbase) {
847 memcpy(bufbase, bufptr, bufused);
848 bufptr = bufbase + bufused;
851 if (bufused >= bufsize) {
852 len = (bufsize * 3) / 2;
853 cp = realloc(bufbase, len);
854 if (cp == NULL) {
855 fprintf(stderr, "No memory for buffer\n");
856 close(fd);
857 return FALSE;
860 bufbase = cp;
861 bufptr = bufbase + bufused;
862 bufsize = len;
865 cc = read(fd, bufptr, bufsize - bufused);
866 bufused += cc;
867 bufptr = bufbase;
869 } while (cc > 0);
871 if (cc < 0) {
872 perror(file);
873 close(fd);
874 return FALSE;
877 if (bufused) {
878 if (!insertline(num, bufptr, bufused)) {
879 close(fd);
880 return -1;
882 linecount++;
883 charcount += bufused;
886 close(fd);
888 printf("%d lines%s, %d chars\n", linecount,
889 (bufused ? " (incomplete)" : ""), charcount);
891 return TRUE;
896 * Write the specified lines out to the specified file.
897 * Returns TRUE if successful, or FALSE on an error with a message output.
899 static BOOL
900 writelines(file, num1, num2)
901 char *file;
902 NUM num1;
903 NUM num2;
905 int fd;
906 LINE *lp;
907 LEN linecount;
908 LEN charcount;
910 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
911 fprintf(stderr, "Bad line range for write\n");
912 return FALSE;
915 linecount = 0;
916 charcount = 0;
918 fd = creat(file, 0666);
919 if (fd < 0) {
920 perror(file);
921 return FALSE;
924 printf("\"%s\", ", file);
925 fflush(stdout);
927 lp = findline(num1);
928 if (lp == NULL) {
929 close(fd);
930 return FALSE;
933 while (num1++ <= num2) {
934 if (write(fd, lp->data, lp->len) != lp->len) {
935 perror(file);
936 close(fd);
937 return FALSE;
940 charcount += lp->len;
941 linecount++;
942 lp = lp->next;
945 if (close(fd) < 0) {
946 perror(file);
947 return FALSE;
950 printf("%d lines, %d chars\n", linecount, charcount);
952 return TRUE;
957 * Print lines in a specified range.
958 * The last line printed becomes the current line.
959 * If expandflag is TRUE, then the line is printed specially to
960 * show magic characters.
962 static BOOL
963 printlines(num1, num2, expandflag)
964 NUM num1;
965 NUM num2;
966 BOOL expandflag;
968 LINE *lp;
969 unsigned char *cp;
970 int ch;
971 LEN count;
973 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
974 fprintf(stderr, "Bad line range for print\n");
975 return FALSE;
978 lp = findline(num1);
979 if (lp == NULL)
980 return FALSE;
982 while (!intflag && (num1 <= num2)) {
983 if (!expandflag) {
984 write(STDOUT, lp->data, lp->len);
985 setcurnum(num1++);
986 lp = lp->next;
987 continue;
991 * Show control characters and characters with the
992 * high bit set specially.
994 cp = lp->data;
995 count = lp->len;
996 if ((count > 0) && (cp[count - 1] == '\n'))
997 count--;
999 while (count-- > 0) {
1000 ch = *cp++;
1001 if (ch & 0x80) {
1002 fputs("M-", stdout);
1003 ch &= 0x7f;
1005 if (ch < ' ') {
1006 fputc('^', stdout);
1007 ch += '@';
1009 if (ch == 0x7f) {
1010 fputc('^', stdout);
1011 ch = '?';
1013 fputc(ch, stdout);
1015 fputs("$\n", stdout);
1017 setcurnum(num1++);
1018 lp = lp->next;
1021 return TRUE;
1026 * Insert a new line with the specified text.
1027 * The line is inserted so as to become the specified line,
1028 * thus pushing any existing and further lines down one.
1029 * The inserted line is also set to become the current line.
1030 * Returns TRUE if successful.
1032 static BOOL
1033 insertline(num, data, len)
1034 NUM num;
1035 char *data;
1036 LEN len;
1038 LINE *newlp;
1039 LINE *lp;
1041 if ((num < 1) || (num > lastnum + 1)) {
1042 fprintf(stderr, "Inserting at bad line number\n");
1043 return FALSE;
1046 newlp = (LINE *) malloc(sizeof(LINE) + len - 1);
1047 if (newlp == NULL) {
1048 fprintf(stderr, "Failed to allocate memory for line\n");
1049 return FALSE;
1052 memcpy(newlp->data, data, len);
1053 newlp->len = len;
1055 if (num > lastnum)
1056 lp = &lines;
1057 else {
1058 lp = findline(num);
1059 if (lp == NULL) {
1060 free((char *) newlp);
1061 return FALSE;
1065 newlp->next = lp;
1066 newlp->prev = lp->prev;
1067 lp->prev->next = newlp;
1068 lp->prev = newlp;
1070 lastnum++;
1071 dirty = TRUE;
1073 return setcurnum(num);
1078 * Delete lines from the given range.
1080 static BOOL
1081 deletelines(num1, num2)
1082 NUM num1;
1083 NUM num2;
1085 LINE *lp;
1086 LINE *nlp;
1087 LINE *plp;
1088 NUM count;
1090 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
1091 fprintf(stderr, "Bad line numbers for delete\n");
1092 return FALSE;
1095 lp = findline(num1);
1096 if (lp == NULL)
1097 return FALSE;
1099 if ((curnum >= num1) && (curnum <= num2)) {
1100 if (num2 < lastnum)
1101 setcurnum(num2 + 1);
1102 else if (num1 > 1)
1103 setcurnum(num1 - 1);
1104 else
1105 curnum = 0;
1108 count = num2 - num1 + 1;
1110 if (curnum > num2)
1111 curnum -= count;
1113 lastnum -= count;
1115 while (count-- > 0) {
1116 nlp = lp->next;
1117 plp = lp->prev;
1118 plp->next = nlp;
1119 nlp->prev = plp;
1120 lp->next = NULL;
1121 lp->prev = NULL;
1122 lp->len = 0;
1123 free(lp);
1124 lp = nlp;
1127 dirty = TRUE;
1129 return TRUE;
1134 * Search for a line which contains the specified string.
1135 * If the string is NULL, then the previously searched for string
1136 * is used. The currently searched for string is saved for future use.
1137 * Returns the line number which matches, or 0 if there was no match
1138 * with an error printed.
1140 static NUM
1141 searchlines(str, num1, num2)
1142 char *str;
1143 NUM num1;
1144 NUM num2;
1146 LINE *lp;
1147 int len;
1149 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
1150 fprintf(stderr, "Bad line numbers for search\n");
1151 return 0;
1154 if (*str == '\0') {
1155 if (searchstring[0] == '\0') {
1156 fprintf(stderr, "No previous search string\n");
1157 return 0;
1159 str = searchstring;
1162 if (str != searchstring)
1163 strcpy(searchstring, str);
1165 len = strlen(str);
1167 lp = findline(num1);
1168 if (lp == NULL)
1169 return 0;
1171 while (num1 <= num2) {
1172 if (findstring(lp, str, len, 0) >= 0)
1173 return num1;
1175 num1++;
1176 lp = lp->next;
1179 fprintf(stderr, "Cannot find string \"%s\"\n", str);
1181 return 0;
1186 * Return a pointer to the specified line number.
1188 static LINE *
1189 findline(num)
1190 NUM num;
1192 LINE *lp;
1193 NUM lnum;
1195 if ((num < 1) || (num > lastnum)) {
1196 fprintf(stderr, "Line number %d does not exist\n", num);
1197 return NULL;
1200 if (curnum <= 0) {
1201 curnum = 1;
1202 curline = lines.next;
1205 if (num == curnum)
1206 return curline;
1208 lp = curline;
1209 lnum = curnum;
1211 if (num < (curnum / 2)) {
1212 lp = lines.next;
1213 lnum = 1;
1215 else if (num > ((curnum + lastnum) / 2)) {
1216 lp = lines.prev;
1217 lnum = lastnum;
1220 while (lnum < num) {
1221 lp = lp->next;
1222 lnum++;
1225 while (lnum > num) {
1226 lp = lp->prev;
1227 lnum--;
1230 return lp;
1235 * Set the current line number.
1236 * Returns TRUE if successful.
1238 static BOOL
1239 setcurnum(num)
1240 NUM num;
1242 LINE *lp;
1244 lp = findline(num);
1245 if (lp == NULL)
1246 return FALSE;
1248 curnum = num;
1249 curline = lp;
1251 return TRUE;
1254 #endif /* CMD_ED */
1255 /* END CODE */