4250001 //----------------------------------------------------------------------
4250002 // 2009.08.18
4250003 // Modified by Daniele Giacomini for `os16', to harmonize with it,
4250004 // even, when possible, on coding style.
4250005 //
4250006 // The original was taken form ELKS sources: `elkscmd/misc_utils/ed.c'.
4250007 //----------------------------------------------------------------------
4250008 //
4250009 // Copyright (c) 1993 by David I. Bell
4250010 // Permission is granted to use, distribute, or modify this source,
4250011 // provided that this copyright notice remains intact.
4250012 //
4250013 // The "ed" built-in command (much simplified)
4250014 //
4250015 //----------------------------------------------------------------------
4250016
4250017 #include <stdio.h>
4250018 #include <ctype.h>
4250019 #include <unistd.h>
4250020 #include <stdbool.h>
4250021 #include <string.h>
4250022 #include <stdlib.h>
4250023 #include <fcntl.h>
4250024 //----------------------------------------------------------------------
4250025 #define isoctal(ch) (((ch) >= '0') && ((ch) <= '7'))
4250026 #define USERSIZE 1024 /* max line length typed in by user */
4250027 #define INITBUFSIZE 1024 /* initial buffer size */
4250028 //----------------------------------------------------------------------
4250029 typedef int num_t;
4250030 typedef int len_t;
4250031 //
4250032 // The following is the type definition of structure `line_t', but the
4250033 // structure contains pointers to the same kind of type. With the
4250034 // compiler Bcc, it is the only way to declare it.
4250035 //
4250036 typedef struct line line_t;
4250037 //
4250038 struct line {
4250039 line_t *next;
4250040 line_t *prev;
4250041 len_t len;
4250042 char data[1];
4250043 };
4250044 //
4250045 static line_t lines;
4250046 static line_t *curline;
4250047 static num_t curnum;
4250048 static num_t lastnum;
4250049 static num_t marks[26];
4250050 static bool dirty;
4250051 static char *filename;
4250052 static char searchstring[USERSIZE];
4250053 //
4250054 static char *bufbase;
4250055 static char *bufptr;
4250056 static len_t bufused;
4250057 static len_t bufsize;
4250058 //----------------------------------------------------------------------
4250059 static void docommands (void);
4250060 static void subcommand (char *cp, num_t num1, num_t num2);
4250061 static bool getnum (char **retcp, bool *rethavenum,
4250062 num_t *retnum);
4250063 static bool setcurnum (num_t num);
4250064 static bool initedit (void);
4250065 static void termedit (void);
4250066 static void addlines (num_t num);
4250067 static bool insertline (num_t num, char *data, len_t len);
4250068 static bool deletelines (num_t num1, num_t num2);
4250069 static bool printlines (num_t num1, num_t num2, bool expandflag);
4250070 static bool writelines (char *file, num_t num1, num_t num2);
4250071 static bool readlines (char *file, num_t num);
4250072 static num_t searchlines (char *str, num_t num1, num_t num2);
4250073 static len_t findstring (line_t *lp, char *str, len_t len,
4250074 len_t offset);
4250075 static line_t *findline (num_t num);
4250076 //----------------------------------------------------------------------
4250077 // Main.
4250078 //----------------------------------------------------------------------
4250079 int
4250080 main (int argc, char *argv[], char *envp[])
4250081 {
4250082 if (!initedit ()) return (2);
4250083 //
4250084 if (argc > 1)
4250085 {
4250086 filename = strdup (argv[1]);
4250087 if (filename == NULL)
4250088 {
4250089 fprintf (stderr, "No memory\n");
4250090 termedit ();
4250091 return (1);
4250092 }
4250093 //
4250094 if (!readlines (filename, 1))
4250095 {
4250096 termedit ();
4250097 return (0);
4250098 }
4250099 //
4250100 if (lastnum) setcurnum(1);
4250101 //
4250102 dirty = false;
4250103 }
4250104 //
4250105 docommands ();
4250106 //
4250107 termedit ();
4250108 return (0);
4250109 }
4250110 //----------------------------------------------------------------------
4250111 // Read commands until we are told to stop.
4250112 //----------------------------------------------------------------------
4250113 void
4250114 docommands (void)
4250115 {
4250116 char *cp;
4250117 int len;
4250118 num_t num1;
4250119 num_t num2;
4250120 bool have1;
4250121 bool have2;
4250122 char buf[USERSIZE];
4250123 //
4250124 while (true)
4250125 {
4250126 printf(": ");
4250127 fflush (stdout);
4250128 //
4250129 if (fgets (buf, sizeof(buf), stdin) == NULL)
4250130 {
4250131 return;
4250132 }
4250133 //
4250134 len = strlen (buf);
4250135 if (len == 0)
4250136 {
4250137 return;
4250138 }
4250139 //
4250140 cp = &buf[len - 1];
4250141 if (*cp != '\n')
4250142 {
4250143 fprintf(stderr, "Command line too long\n");
4250144 do
4250145 {
4250146 len = fgetc(stdin);
4250147 }
4250148 while ((len != EOF) && (len != '\n'));
4250149 //
4250150 continue;
4250151 }
4250152 //
4250153 while ((cp > buf) && isblank (cp[-1]))
4250154 {
4250155 cp--;
4250156 }
4250157 //
4250158 *cp = '\0';
4250159 //
4250160 cp = buf;
4250161 //
4250162 while (isblank (*cp))
4250163 {
4250164 //*cp++;
4250165 cp++;
4250166 }
4250167 //
4250168 have1 = false;
4250169 have2 = false;
4250170 //
4250171 if ((curnum == 0) && (lastnum > 0))
4250172 {
4250173 curnum = 1;
4250174 curline = lines.next;
4250175 }
4250176 //
4250177 if (!getnum (&cp, &have1, &num1))
4250178 {
4250179 continue;
4250180 }
4250181 //
4250182 while (isblank (*cp))
4250183 {
4250184 cp++;
4250185 }
4250186 //
4250187 if (*cp == ',')
4250188 {
4250189 cp++;
4250190 if (!getnum (&cp, &have2, &num2))
4250191 {
4250192 continue;
4250193 }
4250194 //
4250195 if (!have1)
4250196 {
4250197 num1 = 1;
4250198 }
4250199 if (!have2)
4250200 {
4250201 num2 = lastnum;
4250202 }
4250203 have1 = true;
4250204 have2 = true;
4250205 }
4250206 //
4250207 if (!have1)
4250208 {
4250209 num1 = curnum;
4250210 }
4250211 if (!have2)
4250212 {
4250213 num2 = num1;
4250214 }
4250215 //
4250216 // Command interpretation switch.
4250217 //
4250218 switch (*cp++)
4250219 {
4250220 case 'a':
4250221 addlines (num1 + 1);
4250222 break;
4250223 //
4250224 case 'c':
4250225 deletelines (num1, num2);
4250226 addlines (num1);
4250227 break;
4250228 //
4250229 case 'd':
4250230 deletelines (num1, num2);
4250231 break;
4250232 //
4250233 case 'f':
4250234 if (*cp && !isblank (*cp))
4250235 {
4250236 fprintf (stderr, "Bad file command\n");
4250237 break;
4250238 }
4250239 //
4250240 while (isblank (*cp))
4250241 {
4250242 cp++;
4250243 }
4250244 if (*cp == '\0')
4250245 {
4250246 if (filename)
4250247 {
4250248 printf ("\"%s\"\n", filename);
4250249 }
4250250 else
4250251 {
4250252 printf ("No filename\n");
4250253 }
4250254 break;
4250255 }
4250256 //
4250257 cp = strdup (cp);
4250258 //
4250259 if (cp == NULL)
4250260 {
4250261 fprintf (stderr, "No memory for filename\n");
4250262 break;
4250263 }
4250264 //
4250265 if (filename)
4250266 {
4250267 free(filename);
4250268 }
4250269 //
4250270 filename = cp;
4250271 break;
4250272 //
4250273 case 'i':
4250274 addlines (num1);
4250275 break;
4250276 //
4250277 case 'k':
4250278 while (isblank(*cp))
4250279 {
4250280 cp++;
4250281 }
4250282 //
4250283 if ((*cp < 'a') || (*cp > 'a') || cp[1])
4250284 {
4250285 fprintf (stderr, "Bad mark name\n");
4250286 break;
4250287 }
4250288 //
4250289 marks[*cp - 'a'] = num2;
4250290 break;
4250291 //
4250292 case 'l':
4250293 printlines (num1, num2, true);
4250294 break;
4250295 //
4250296 case 'p':
4250297 printlines (num1, num2, false);
4250298 break;
4250299 //
4250300 case 'q':
4250301 while (isblank(*cp))
4250302 {
4250303 cp++;
4250304 }
4250305 //
4250306 if (have1 || *cp)
4250307 {
4250308 fprintf (stderr, "Bad quit command\n");
4250309 break;
4250310 }
4250311 //
4250312 if (!dirty)
4250313 {
4250314 return;
4250315 }
4250316 //
4250317 printf ("Really quit? ");
4250318 fflush (stdout);
4250319 //
4250320 buf[0] = '\0';
4250321 fgets (buf, sizeof(buf), stdin);
4250322 cp = buf;
4250323 //
4250324 while (isblank (*cp))
4250325 {
4250326 cp++;
4250327 }
4250328 //
4250329 if ((*cp == 'y') || (*cp == 'Y'))
4250330 {
4250331 return;
4250332 }
4250333 //
4250334 break;
4250335 //
4250336 case 'r':
4250337 if (*cp && !isblank(*cp))
4250338 {
4250339 fprintf (stderr, "Bad read command\n");
4250340 break;
4250341 }
4250342 //
4250343 while (isblank(*cp))
4250344 {
4250345 cp++;
4250346 }
4250347 //
4250348 if (*cp == '\0')
4250349 {
4250350 fprintf (stderr, "No filename\n");
4250351 break;
4250352 }
4250353 //
4250354 if (!have1)
4250355 {
4250356 num1 = lastnum;
4250357 }
4250358 //
4250359 // Open the file and add to the buffer
4250360 // at the next line.
4250361 //
4250362 if (readlines (cp, num1 + 1))
4250363 {
4250364 //
4250365 // If the file open fails, just
4250366 // break the command.
4250367 //
4250368 break;
4250369 }
4250370 //
4250371 // Set the default file name, if no
4250372 // previous name is available.
4250373 //
4250374 if (filename == NULL)
4250375 {
4250376 filename = strdup (cp);
4250377 }
4250378 //
4250379 break;
4250380
4250381 case 's':
4250382 subcommand (cp, num1, num2);
4250383 break;
4250384 //
4250385 case 'w':
4250386 if (*cp && !isblank(*cp))
4250387 {
4250388 fprintf(stderr, "Bad write command\n");
4250389 break;
4250390 }
4250391 //
4250392 while (isblank(*cp))
4250393 {
4250394 cp++;
4250395 }
4250396 //
4250397 if (!have1)
4250398 {
4250399 num1 = 1;
4250400 num2 = lastnum;
4250401 }
4250402 //
4250403 // If the file name is not specified, use the
4250404 // default one.
4250405 //
4250406 if (*cp == '\0')
4250407 {
4250408 cp = filename;
4250409 }
4250410 //
4250411 // If even the default file name is not specified,
4250412 // tell it.
4250413 //
4250414 if (cp == NULL)
4250415 {
4250416 fprintf (stderr, "No file name specified\n");
4250417 break;
4250418 }
4250419 //
4250420 // Write the file.
4250421 //
4250422 writelines (cp, num1, num2);
4250423 //
4250424 break;
4250425 //
4250426 case 'z':
4250427 switch (*cp)
4250428 {
4250429 case '-':
4250430 printlines (curnum-21, curnum, false);
4250431 break;
4250432 case '.':
4250433 printlines (curnum-11, curnum+10, false);
4250434 break;
4250435 default:
4250436 printlines (curnum, curnum+21, false);
4250437 break;
4250438 }
4250439 break;
4250440 //
4250441 case '.':
4250442 if (have1)
4250443 {
4250444 fprintf (stderr, "No arguments allowed\n");
4250445 break;
4250446 }
4250447 printlines (curnum, curnum, false);
4250448 break;
4250449 //
4250450 case '-':
4250451 if (setcurnum (curnum - 1))
4250452 {
4250453 printlines (curnum, curnum, false);
4250454 }
4250455 break;
4250456 //
4250457 case '=':
4250458 printf ("%d\n", num1);
4250459 break;
4250460 //
4250461 case '\0':
4250462 if (have1)
4250463 {
4250464 printlines (num2, num2, false);
4250465 break;
4250466 }
4250467 //
4250468 if (setcurnum (curnum + 1))
4250469 {
4250470 printlines (curnum, curnum, false);
4250471 }
4250472 break;
4250473 //
4250474 default:
4250475 fprintf (stderr, "Unimplemented command\n");
4250476 break;
4250477 }
4250478 }
4250479 }
4250480 //----------------------------------------------------------------------
4250481 // Do the substitute command.
4250482 // The current line is set to the last substitution done.
4250483 //----------------------------------------------------------------------
4250484 void
4250485 subcommand (char *cp, num_t num1, num_t num2)
4250486 {
4250487 int delim;
4250488 char *oldstr;
4250489 char *newstr;
4250490 len_t oldlen;
4250491 len_t newlen;
4250492 len_t deltalen;
4250493 len_t offset;
4250494 line_t *lp;
4250495 line_t *nlp;
4250496 bool globalflag;
4250497 bool printflag;
4250498 bool didsub;
4250499 bool needprint;
4250500
4250501 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
4250502 {
4250503 fprintf (stderr, "Bad line range for substitute\n");
4250504 return;
4250505 }
4250506 //
4250507 globalflag = false;
4250508 printflag = false;
4250509 didsub = false;
4250510 needprint = false;
4250511 //
4250512 if (isblank (*cp) || (*cp == '\0'))
4250513 {
4250514 fprintf (stderr, "Bad delimiter for substitute\n");
4250515 return;
4250516 }
4250517 //
4250518 delim = *cp++;
4250519 oldstr = cp;
4250520 //
4250521 cp = strchr (cp, delim);
4250522 //
4250523 if (cp == NULL)
4250524 {
4250525 fprintf (stderr, "Missing 2nd delimiter for substitute\n");
4250526 return;
4250527 }
4250528 //
4250529 *cp++ = '\0';
4250530 //
4250531 newstr = cp;
4250532 cp = strchr (cp, delim);
4250533 //
4250534 if (cp)
4250535 {
4250536 *cp++ = '\0';
4250537 }
4250538 else
4250539 {
4250540 cp = "";
4250541 }
4250542 while (*cp)
4250543 {
4250544 switch (*cp++)
4250545 {
4250546 case 'g':
4250547 globalflag = true;
4250548 break;
4250549 //
4250550 case 'p':
4250551 printflag = true;
4250552 break;
4250553 //
4250554 default:
4250555 fprintf (stderr, "Unknown option for substitute\n");
4250556 return;
4250557 }
4250558 }
4250559 //
4250560 if (*oldstr == '\0')
4250561 {
4250562 if (searchstring[0] == '\0')
4250563 {
4250564 fprintf (stderr, "No previous search string\n");
4250565 return;
4250566 }
4250567 oldstr = searchstring;
4250568 }
4250569 //
4250570 if (oldstr != searchstring)
4250571 {
4250572 strcpy (searchstring, oldstr);
4250573 }
4250574 //
4250575 lp = findline (num1);
4250576 if (lp == NULL)
4250577 {
4250578 return;
4250579 }
4250580 //
4250581 oldlen = strlen(oldstr);
4250582 newlen = strlen(newstr);
4250583 deltalen = newlen - oldlen;
4250584 offset = 0;
4250585 //
4250586 while (num1 <= num2)
4250587 {
4250588 offset = findstring (lp, oldstr, oldlen, offset);
4250589 if (offset < 0)
4250590 {
4250591 if (needprint)
4250592 {
4250593 printlines (num1, num1, false);
4250594 needprint = false;
4250595 }
4250596 //
4250597 offset = 0;
4250598 lp = lp->next;
4250599 num1++;
4250600 continue;
4250601 }
4250602 //
4250603 needprint = printflag;
4250604 didsub = true;
4250605 dirty = true;
4250606
4250607 //--------------------------------------------------------------
4250608 // If the replacement string is the same size or shorter
4250609 // than the old string, then the substitution is easy.
4250610 //--------------------------------------------------------------
4250611
4250612 if (deltalen <= 0)
4250613 {
4250614 memcpy (&lp->data[offset], newstr, newlen);
4250615 //
4250616 if (deltalen)
4250617 {
4250618 memcpy (&lp->data[offset + newlen],
4250619 &lp->data[offset + oldlen],
4250620 lp->len - offset - oldlen);
4250621 //
4250622 lp->len += deltalen;
4250623 }
4250624 //
4250625 offset += newlen;
4250626 //
4250627 if (globalflag)
4250628 {
4250629 continue;
4250630 }
4250631 //
4250632 if (needprint)
4250633 {
4250634 printlines(num1, num1, false);
4250635 needprint = false;
4250636 }
4250637 //
4250638 lp = nlp->next;
4250639 num1++;
4250640 continue;
4250641 }
4250642
4250643 //--------------------------------------------------------------
4250644 // The new string is larger, so allocate a new line
4250645 // structure and use that. Link it in in place of
4250646 // the old line structure.
4250647 //--------------------------------------------------------------
4250648
4250649 nlp = (line_t *) malloc (sizeof (line_t) + lp->len + deltalen);
4250650 //
4250651 if (nlp == NULL)
4250652 {
4250653 fprintf (stderr, "Cannot get memory for line\n");
4250654 return;
4250655 }
4250656 //
4250657 nlp->len = lp->len + deltalen;
4250658 //
4250659 memcpy (nlp->data, lp->data, offset);
4250660 //
4250661 memcpy (&nlp->data[offset], newstr, newlen);
4250662 //
4250663 memcpy (&nlp->data[offset + newlen],
4250664 &lp->data[offset + oldlen],
4250665 lp->len - offset - oldlen);
4250666 //
4250667 nlp->next = lp->next;
4250668 nlp->prev = lp->prev;
4250669 nlp->prev->next = nlp;
4250670 nlp->next->prev = nlp;
4250671 //
4250672 if (curline == lp)
4250673 {
4250674 curline = nlp;
4250675 }
4250676 //
4250677 free(lp);
4250678 lp = nlp;
4250679 //
4250680 offset += newlen;
4250681 //
4250682 if (globalflag)
4250683 {
4250684 continue;
4250685 }
4250686 //
4250687 if (needprint)
4250688 {
4250689 printlines (num1, num1, false);
4250690 needprint = false;
4250691 }
4250692 //
4250693 lp = lp->next;
4250694 num1++;
4250695 }
4250696 //
4250697 if (!didsub)
4250698 {
4250699 fprintf (stderr, "No substitutions found for \"%s\"\n", oldstr);
4250700 }
4250701 }
4250702 //----------------------------------------------------------------------
4250703 // Search a line for the specified string starting at the specified
4250704 // offset in the line. Returns the offset of the found string, or -1.
4250705 //----------------------------------------------------------------------
4250706 len_t
4250707 findstring (line_t *lp, char *str, len_t len, len_t offset)
4250708 {
4250709 len_t left;
4250710 char *cp;
4250711 char *ncp;
4250712 //
4250713 cp = &lp->data[offset];
4250714 left = lp->len - offset;
4250715 //
4250716 while (left >= len)
4250717 {
4250718 ncp = memchr(cp, *str, left);
4250719 if (ncp == NULL)
4250720 {
4250721 return (len_t) -1;
4250722 }
4250723 //
4250724 left -= (ncp - cp);
4250725 if (left < len)
4250726 {
4250727 return (len_t) -1;
4250728 }
4250729 //
4250730 cp = ncp;
4250731 if (memcmp(cp, str, len) == 0)
4250732 {
4250733 return (len_t) (cp - lp->data);
4250734 }
4250735 //
4250736 cp++;
4250737 left--;
4250738 }
4250739 //
4250740 return (len_t) -1;
4250741 }
4250742 //----------------------------------------------------------------------
4250743 // Add lines which are typed in by the user.
4250744 // The lines are inserted just before the specified line number.
4250745 // The lines are terminated by a line containing a single dot (ugly!),
4250746 // or by an end of file.
4250747 //----------------------------------------------------------------------
4250748 void
4250749 addlines (num_t num)
4250750 {
4250751 int len;
4250752 char buf[USERSIZE + 1];
4250753 //
4250754 while (fgets (buf, sizeof (buf), stdin))
4250755 {
4250756 if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
4250757 {
4250758 return;
4250759 }
4250760 //
4250761 len = strlen (buf);
4250762 //
4250763 if (len == 0)
4250764 {
4250765 return;
4250766 }
4250767 //
4250768 if (buf[len - 1] != '\n')
4250769 {
4250770 fprintf (stderr, "Line too long\n");
4250771 //
4250772 do
4250773 {
4250774 len = fgetc(stdin);
4250775 }
4250776 while ((len != EOF) && (len != '\n'));
4250777 //
4250778 return;
4250779 }
4250780 //
4250781 if (!insertline (num++, buf, len))
4250782 {
4250783 return;
4250784 }
4250785 }
4250786 }
4250787 //----------------------------------------------------------------------
4250788 // Parse a line number argument if it is present. This is a sum
4250789 // or difference of numbers, '.', '$', 'x, or a search string.
4250790 // Returns true if successful (whether or not there was a number).
4250791 // Returns false if there was a parsing error, with a message output.
4250792 // Whether there was a number is returned indirectly, as is the number.
4250793 // The character pointer which stopped the scan is also returned.
4250794 //----------------------------------------------------------------------
4250795 static bool
4250796 getnum (char **retcp, bool *rethavenum, num_t *retnum)
4250797 {
4250798 char *cp;
4250799 char *str;
4250800 bool havenum;
4250801 num_t value;
4250802 num_t num;
4250803 num_t sign;
4250804 //
4250805 cp = *retcp;
4250806 havenum = false;
4250807 value = 0;
4250808 sign = 1;
4250809 //
4250810 while (true)
4250811 {
4250812 while (isblank(*cp))
4250813 {
4250814 cp++;
4250815 }
4250816 //
4250817 switch (*cp)
4250818 {
4250819 case '.':
4250820 havenum = true;
4250821 num = curnum;
4250822 cp++;
4250823 break;
4250824 //
4250825 case '$':
4250826 havenum = true;
4250827 num = lastnum;
4250828 cp++;
4250829 break;
4250830 //
4250831 case '\'':
4250832 cp++;
4250833 if ((*cp < 'a') || (*cp > 'z'))
4250834 {
4250835 fprintf (stderr, "Bad mark name\n");
4250836 return false;
4250837 }
4250838 //
4250839 havenum = true;
4250840 num = marks[*cp++ - 'a'];
4250841 break;
4250842 //
4250843 case '/':
4250844 str = ++cp;
4250845 cp = strchr (str, '/');
4250846 if (cp)
4250847 {
4250848 *cp++ = '\0';
4250849 }
4250850 else
4250851 {
4250852 cp = "";
4250853 }
4250854 num = searchlines (str, curnum, lastnum);
4250855 if (num == 0)
4250856 {
4250857 return false;
4250858 }
4250859 //
4250860 havenum = true;
4250861 break;
4250862 //
4250863 default:
4250864 if (!isdigit (*cp))
4250865 {
4250866 *retcp = cp;
4250867 *rethavenum = havenum;
4250868 *retnum = value;
4250869 return true;
4250870 }
4250871 //
4250872 num = 0;
4250873 while (isdigit(*cp))
4250874 {
4250875 num = num * 10 + *cp++ - '0';
4250876 }
4250877 havenum = true;
4250878 break;
4250879 }
4250880 //
4250881 value += num * sign;
4250882 //
4250883 while (isblank (*cp))
4250884 {
4250885 cp++;
4250886 }
4250887 //
4250888 switch (*cp)
4250889 {
4250890 case '-':
4250891 sign = -1;
4250892 cp++;
4250893 break;
4250894 //
4250895 case '+':
4250896 sign = 1;
4250897 cp++;
4250898 break;
4250899 //
4250900 default:
4250901 *retcp = cp;
4250902 *rethavenum = havenum;
4250903 *retnum = value;
4250904 return true;
4250905 }
4250906 }
4250907 }
4250908 //----------------------------------------------------------------------
4250909 // Initialize everything for editing.
4250910 //----------------------------------------------------------------------
4250911 bool
4250912 initedit (void)
4250913 {
4250914 int i;
4250915 //
4250916 bufsize = INITBUFSIZE;
4250917 bufbase = malloc (bufsize);
4250918 //
4250919 if (bufbase == NULL)
4250920 {
4250921 fprintf (stderr, "No memory for buffer\n");
4250922 return false;
4250923 }
4250924 //
4250925 bufptr = bufbase;
4250926 bufused = 0;
4250927 //
4250928 lines.next = &lines;
4250929 lines.prev = &lines;
4250930 //
4250931 curline = NULL;
4250932 curnum = 0;
4250933 lastnum = 0;
4250934 dirty = false;
4250935 filename = NULL;
4250936 searchstring[0] = '\0';
4250937 //
4250938 for (i = 0; i < 26; i++)
4250939 {
4250940 marks[i] = 0;
4250941 }
4250942 //
4250943 return true;
4250944 }
4250945 //----------------------------------------------------------------------
4250946 // Finish editing.
4250947 //----------------------------------------------------------------------
4250948 void
4250949 termedit (void)
4250950 {
4250951 if (bufbase) free(bufbase);
4250952 bufbase = NULL;
4250953 //
4250954 bufptr = NULL;
4250955 bufsize = 0;
4250956 bufused = 0;
4250957 //
4250958 if (filename) free(filename);
4250959 filename = NULL;
4250960 //
4250961 searchstring[0] = '\0';
4250962 //
4250963 if (lastnum) deletelines (1, lastnum);
4250964 //
4250965 lastnum = 0;
4250966 curnum = 0;
4250967 curline = NULL;
4250968 }
4250969 //----------------------------------------------------------------------
4250970 // Read lines from a file at the specified line number.
4250971 // Returns true if the file was successfully read.
4250972 //----------------------------------------------------------------------
4250973 bool
4250974 readlines (char *file, num_t num)
4250975 {
4250976 int fd;
4250977 int cc;
4250978 len_t len;
4250979 len_t linecount;
4250980 len_t charcount;
4250981 char *cp;
4250982 //
4250983 if ((num < 1) || (num > lastnum + 1))
4250984 {
4250985 fprintf (stderr, "Bad line for read\n");
4250986 return false;
4250987 }
4250988 //
4250989 fd = open (file, O_RDONLY);
4250990 if (fd < 0)
4250991 {
4250992 perror (file);
4250993 return false;
4250994 }
4250995 //
4250996 bufptr = bufbase;
4250997 bufused = 0;
4250998 linecount = 0;
4250999 charcount = 0;
4251000 //
4251001 printf ("\"%s\", ", file);
4251002 fflush(stdout);
4251003 //
4251004 do
4251005 {
4251006 cp = memchr(bufptr, '\n', bufused);
4251007 if (cp)
4251008 {
4251009 len = (cp - bufptr) + 1;
4251010 //
4251011 if (!insertline (num, bufptr, len))
4251012 {
4251013 close (fd);
4251014 return false;
4251015 }
4251016 //
4251017 bufptr += len;
4251018 bufused -= len;
4251019 charcount += len;
4251020 linecount++;
4251021 num++;
4251022 continue;
4251023 }
4251024 //
4251025 if (bufptr != bufbase)
4251026 {
4251027 memcpy (bufbase, bufptr, bufused);
4251028 bufptr = bufbase + bufused;
4251029 }
4251030 //
4251031 if (bufused >= bufsize)
4251032 {
4251033 len = (bufsize * 3) / 2;
4251034 cp = realloc (bufbase, len);
4251035 if (cp == NULL)
4251036 {
4251037 fprintf (stderr, "No memory for buffer\n");
4251038 close (fd);
4251039 return false;
4251040 }
4251041 //
4251042 bufbase = cp;
4251043 bufptr = bufbase + bufused;
4251044 bufsize = len;
4251045 }
4251046 //
4251047 cc = read (fd, bufptr, bufsize - bufused);
4251048 bufused += cc;
4251049 bufptr = bufbase;
4251050 }
4251051 while (cc > 0);
4251052 //
4251053 if (cc < 0)
4251054 {
4251055 perror (file);
4251056 close (fd);
4251057 return false;
4251058 }
4251059 //
4251060 if (bufused)
4251061 {
4251062 if (!insertline (num, bufptr, bufused))
4251063 {
4251064 close (fd);
4251065 return -1;
4251066 }
4251067 linecount++;
4251068 charcount += bufused;
4251069 }
4251070 //
4251071 close (fd);
4251072 //
4251073 printf ("%d lines%s, %d chars\n",
4251074 linecount,
4251075 (bufused ? " (incomplete)" : ""),
4251076 charcount);
4251077 //
4251078 return true;
4251079 }
4251080 //----------------------------------------------------------------------
4251081 // Write the specified lines out to the specified file.
4251082 // Returns true if successful, or false on an error with a message
4251083 // output.
4251084 //----------------------------------------------------------------------
4251085 bool
4251086 writelines (char *file, num_t num1, num_t num2)
4251087 {
4251088 int fd;
4251089 line_t *lp;
4251090 len_t linecount;
4251091 len_t charcount;
4251092 //
4251093 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
4251094 {
4251095 fprintf (stderr, "Bad line range for write\n");
4251096 return false;
4251097 }
4251098 //
4251099 linecount = 0;
4251100 charcount = 0;
4251101 //
4251102 fd = creat (file, 0666);
4251103 if (fd < 0)
4251104 {
4251105 perror (file);
4251106 return false;
4251107 }
4251108 //
4251109 printf("\"%s\", ", file);
4251110 fflush (stdout);
4251111 //
4251112 lp = findline (num1);
4251113 if (lp == NULL)
4251114 {
4251115 close (fd);
4251116 return false;
4251117 }
4251118 //
4251119 while (num1++ <= num2)
4251120 {
4251121 if (write(fd, lp->data, lp->len) != lp->len)
4251122 {
4251123 perror(file);
4251124 close(fd);
4251125 return false;
4251126 }
4251127 //
4251128 charcount += lp->len;
4251129 linecount++;
4251130 lp = lp->next;
4251131 }
4251132 //
4251133 if (close(fd) < 0)
4251134 {
4251135 perror(file);
4251136 return false;
4251137 }
4251138 //
4251139 printf ("%d lines, %d chars\n", linecount, charcount);
4251140 //
4251141 return true;
4251142 }
4251143 //----------------------------------------------------------------------
4251144 // Print lines in a specified range.
4251145 // The last line printed becomes the current line.
4251146 // If expandflag is true, then the line is printed specially to
4251147 // show magic characters.
4251148 //----------------------------------------------------------------------
4251149 bool
4251150 printlines (num_t num1, num_t num2, bool expandflag)
4251151 {
4251152 line_t *lp;
4251153 unsigned char *cp;
4251154 int ch;
4251155 len_t count;
4251156 //
4251157 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
4251158 {
4251159 fprintf (stderr, "Bad line range for print\n");
4251160 return false;
4251161 }
4251162 //
4251163 lp = findline (num1);
4251164 if (lp == NULL)
4251165 {
4251166 return false;
4251167 }
4251168 //
4251169 while (num1 <= num2)
4251170 {
4251171 if (!expandflag)
4251172 {
4251173 write (STDOUT_FILENO, lp->data, lp->len);
4251174 setcurnum (num1++);
4251175 lp = lp->next;
4251176 continue;
4251177 }
4251178
4251179 //--------------------------------------------------------------
4251180 // Show control characters and characters with the
4251181 // high bit set specially.
4251182 //--------------------------------------------------------------
4251183
4251184 cp = (unsigned char *) lp->data;
4251185 count = lp->len;
4251186 //
4251187 if ((count > 0) && (cp[count - 1] == '\n'))
4251188 {
4251189 count--;
4251190 }
4251191 //
4251192 while (count-- > 0)
4251193 {
4251194 ch = *cp++;
4251195 if (ch & 0x80)
4251196 {
4251197 fputs ("M-", stdout);
4251198 ch &= 0x7f;
4251199 }
4251200 if (ch < ' ')
4251201 {
4251202 fputc ('^', stdout);
4251203 ch += '@';
4251204 }
4251205 if (ch == 0x7f)
4251206 {
4251207 fputc ('^', stdout);
4251208 ch = '?';
4251209 }
4251210 fputc (ch, stdout);
4251211 }
4251212 //
4251213 fputs ("$\n", stdout);
4251214 //
4251215 setcurnum (num1++);
4251216 lp = lp->next;
4251217 }
4251218 //
4251219 return true;
4251220 }
4251221 //----------------------------------------------------------------------
4251222 // Insert a new line with the specified text.
4251223 // The line is inserted so as to become the specified line,
4251224 // thus pushing any existing and further lines down one.
4251225 // The inserted line is also set to become the current line.
4251226 // Returns true if successful.
4251227 //----------------------------------------------------------------------
4251228 bool
4251229 insertline (num_t num, char *data, len_t len)
4251230 {
4251231 line_t *newlp;
4251232 line_t *lp;
4251233 //
4251234 if ((num < 1) || (num > lastnum + 1))
4251235 {
4251236 fprintf (stderr, "Inserting at bad line number\n");
4251237 return false;
4251238 }
4251239 //
4251240 newlp = (line_t *) malloc (sizeof (line_t) + len - 1);
4251241 if (newlp == NULL)
4251242 {
4251243 fprintf (stderr, "Failed to allocate memory for line\n");
4251244 return false;
4251245 }
4251246 //
4251247 memcpy (newlp->data, data, len);
4251248 newlp->len = len;
4251249 //
4251250 if (num > lastnum)
4251251 {
4251252 lp = &lines;
4251253 }
4251254 else
4251255 {
4251256 lp = findline (num);
4251257 if (lp == NULL)
4251258 {
4251259 free ((char *) newlp);
4251260 return false;
4251261 }
4251262 }
4251263 //
4251264 newlp->next = lp;
4251265 newlp->prev = lp->prev;
4251266 lp->prev->next = newlp;
4251267 lp->prev = newlp;
4251268 //
4251269 lastnum++;
4251270 dirty = true;
4251271 //
4251272 return setcurnum (num);
4251273 }
4251274 //----------------------------------------------------------------------
4251275 // Delete lines from the given range.
4251276 //----------------------------------------------------------------------
4251277 bool
4251278 deletelines (num_t num1, num_t num2)
4251279 {
4251280 line_t *lp;
4251281 line_t *nlp;
4251282 line_t *plp;
4251283 num_t count;
4251284 //
4251285 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
4251286 {
4251287 fprintf (stderr, "Bad line numbers for delete\n");
4251288 return false;
4251289 }
4251290 //
4251291 lp = findline (num1);
4251292 if (lp == NULL)
4251293 {
4251294 return false;
4251295 }
4251296 //
4251297 if ((curnum >= num1) && (curnum <= num2))
4251298 {
4251299 if (num2 < lastnum)
4251300 {
4251301 setcurnum (num2 + 1);
4251302 }
4251303 else if (num1 > 1)
4251304 {
4251305 setcurnum (num1 - 1);
4251306 }
4251307 else
4251308 {
4251309 curnum = 0;
4251310 }
4251311 }
4251312 //
4251313 count = num2 - num1 + 1;
4251314 //
4251315 if (curnum > num2)
4251316 {
4251317 curnum -= count;
4251318 }
4251319 //
4251320 lastnum -= count;
4251321 //
4251322 while (count-- > 0)
4251323 {
4251324 nlp = lp->next;
4251325 plp = lp->prev;
4251326 plp->next = nlp;
4251327 nlp->prev = plp;
4251328 lp->next = NULL;
4251329 lp->prev = NULL;
4251330 lp->len = 0;
4251331 free(lp);
4251332 lp = nlp;
4251333 }
4251334 //
4251335 dirty = true;
4251336 //
4251337 return true;
4251338 }
4251339 //----------------------------------------------------------------------
4251340 // Search for a line which contains the specified string.
4251341 // If the string is NULL, then the previously searched for string
4251342 // is used. The currently searched for string is saved for future use.
4251343 // Returns the line number which matches, or 0 if there was no match
4251344 // with an error printed.
4251345 //----------------------------------------------------------------------
4251346 num_t
4251347 searchlines (char *str, num_t num1, num_t num2)
4251348 {
4251349 line_t *lp;
4251350 int len;
4251351 //
4251352 if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
4251353 {
4251354 fprintf (stderr, "Bad line numbers for search\n");
4251355 return 0;
4251356 }
4251357 //
4251358 if (*str == '\0')
4251359 {
4251360 if (searchstring[0] == '\0')
4251361 {
4251362 fprintf(stderr, "No previous search string\n");
4251363 return 0;
4251364 }
4251365 str = searchstring;
4251366 }
4251367 //
4251368 if (str != searchstring)
4251369 {
4251370 strcpy(searchstring, str);
4251371 }
4251372 //
4251373 len = strlen(str);
4251374 //
4251375 lp = findline (num1);
4251376 if (lp == NULL)
4251377 {
4251378 return 0;
4251379 }
4251380 //
4251381 while (num1 <= num2)
4251382 {
4251383 if (findstring(lp, str, len, 0) >= 0)
4251384 {
4251385 return num1;
4251386 }
4251387 //
4251388 num1++;
4251389 lp = lp->next;
4251390 }
4251391 //
4251392 fprintf (stderr, "Cannot find string \"%s\"\n", str);
4251393 //
4251394 return 0;
4251395 }
4251396 //----------------------------------------------------------------------
4251397 // Return a pointer to the specified line number.
4251398 //----------------------------------------------------------------------
4251399 line_t *
4251400 findline (num_t num)
4251401 {
4251402 line_t *lp;
4251403 num_t lnum;
4251404 //
4251405 if ((num < 1) || (num > lastnum))
4251406 {
4251407 fprintf (stderr, "Line number %d does not exist\n", num);
4251408 return NULL;
4251409 }
4251410 //
4251411 if (curnum <= 0)
4251412 {
4251413 curnum = 1;
4251414 curline = lines.next;
4251415 }
4251416 //
4251417 if (num == curnum)
4251418 {
4251419 return curline;
4251420 }
4251421 //
4251422 lp = curline;
4251423 lnum = curnum;
4251424 //
4251425 if (num < (curnum / 2))
4251426 {
4251427 lp = lines.next;
4251428 lnum = 1;
4251429 }
4251430 else if (num > ((curnum + lastnum) / 2))
4251431 {
4251432 lp = lines.prev;
4251433 lnum = lastnum;
4251434 }
4251435 //
4251436 while (lnum < num)
4251437 {
4251438 lp = lp->next;
4251439 lnum++;
4251440 }
4251441 //
4251442 while (lnum > num)
4251443 {
4251444 lp = lp->prev;
4251445 lnum--;
4251446 }
4251447 //
4251448 return lp;
4251449 }
4251450 //----------------------------------------------------------------------
4251451 // Set the current line number.
4251452 // Returns true if successful.
4251453 //----------------------------------------------------------------------
4251454 bool
4251455 setcurnum (num_t num)
4251456 {
4251457 line_t *lp;
4251458 //
4251459 lp = findline (num);
4251460 if (lp == NULL)
4251461 {
4251462 return false;
4251463 }
4251464 //
4251465 curnum = num;
4251466 curline = lp;
4251467 //
4251468 return true;
4251469 }
4251470
4251471 /* END CODE */
|