| 5800001 //----------------------------------------------------------
5800002 // 2009.08.18
5800003 // Modified by Daniele Giacomini for `os16', to
5800004 // harmonize with it, even, when possible, on coding
5800005 // style.
5800006 //
5800007 // The original was taken form ELKS sources:
5800008 // `elkscmd/misc_utils/ed.c'.
5800009 //----------------------------------------------------------
5800010 //
5800011 // Copyright (c) 1993 by David I. Bell
5800012 // Permission is granted to use, distribute, or modify
5800013 // this source, provided that this copyright notice
5800014 // remains intact.
5800015 //
5800016 // The "ed" built-in command (much simplified)
5800017 //
5800018 //----------------------------------------------------------
5800019 
5800020 #include <stdio.h>
5800021 #include <ctype.h>
5800022 #include <unistd.h>
5800023 #include <stdbool.h>
5800024 #include <string.h>
5800025 #include <stdlib.h>
5800026 #include <fcntl.h>
5800027 //----------------------------------------------------------
5800028 #define isoctal(ch)  (((ch) >= '0') && ((ch) <= '7'))
5800029 #define USERSIZE     1024       /* max line length typed in 
5800030                                    by user */
5800031 #define INITBUFSIZE  1024       /* initial buffer size */
5800032 //----------------------------------------------------------
5800033 typedef int num_t;
5800034 typedef int len_t;
5800035 //
5800036 // The following is the type definition of structure
5800037 // `line_t', but the structure contains pointers to the
5800038 // same kind of type. With the compiler Bcc, it is the
5800039 // only way to declare it.
5800040 //
5800041 typedef struct line line_t;
5800042 //
5800043 struct line
5800044 {
5800045   line_t *next;
5800046   line_t *prev;
5800047   len_t len;
5800048   char data[1];
5800049 };
5800050 //
5800051 static line_t lines;
5800052 static line_t *curline;
5800053 static num_t curnum;
5800054 static num_t lastnum;
5800055 static num_t marks[26];
5800056 static bool dirty;
5800057 static char *filename;
5800058 static char searchstring[USERSIZE];
5800059 //
5800060 static char *bufbase;
5800061 static char *bufptr;
5800062 static len_t bufused;
5800063 static len_t bufsize;
5800064 //----------------------------------------------------------
5800065 static void docommands (void);
5800066 static void subcommand (char *cp, num_t num1, num_t num2);
5800067 static bool getnum (char **retcp, bool * rethavenum,
5800068                     num_t * retnum);
5800069 static bool setcurnum (num_t num);
5800070 static bool initedit (void);
5800071 static void termedit (void);
5800072 static void addlines (num_t num);
5800073 static bool insertline (num_t num, char *data, len_t len);
5800074 static bool deletelines (num_t num1, num_t num2);
5800075 static bool printlines (num_t num1, num_t num2,
5800076                         bool expandflag);
5800077 static bool writelines (char *file, num_t num1, num_t num2);
5800078 static bool readlines (char *file, num_t num);
5800079 static num_t searchlines (char *str, num_t num1,
5800080                           num_t num2);
5800081 static len_t findstring (line_t * lp, char *str,
5800082                          len_t len, len_t offset);
5800083 static line_t *findline (num_t num);
5800084 //----------------------------------------------------------
5800085 // Main.
5800086 //----------------------------------------------------------
5800087 int
5800088 main (int argc, char *argv[], char *envp[])
5800089 {
5800090   if (!initedit ())
5800091     return (2);
5800092   // 
5800093   if (argc > 1)
5800094     {
5800095       filename = strdup (argv[1]);
5800096       if (filename == NULL)
5800097         {
5800098           fprintf (stderr, "No memory\n");
5800099           termedit ();
5800100           return (1);
5800101         }
5800102       // 
5800103       if (!readlines (filename, 1))
5800104         {
5800105           termedit ();
5800106           return (0);
5800107         }
5800108       // 
5800109       if (lastnum)
5800110         setcurnum (1);
5800111       // 
5800112       dirty = false;
5800113     }
5800114   // 
5800115   docommands ();
5800116   // 
5800117   termedit ();
5800118   return (0);
5800119 }
5800120 
5800121 //----------------------------------------------------------
5800122 // Read commands until we are told to stop.
5800123 //----------------------------------------------------------
5800124 void
5800125 docommands (void)
5800126 {
5800127   char *cp;
5800128   int len;
5800129   num_t num1;
5800130   num_t num2;
5800131   bool have1;
5800132   bool have2;
5800133   char buf[USERSIZE];
5800134   // 
5800135   while (true)
5800136     {
5800137       printf (": ");
5800138       fflush (stdout);
5800139       // 
5800140       if (fgets (buf, sizeof (buf), stdin) == NULL)
5800141         {
5800142           return;
5800143         }
5800144       // 
5800145       len = strlen (buf);
5800146       if (len == 0)
5800147         {
5800148           return;
5800149         }
5800150       // 
5800151       cp = &buf[len - 1];
5800152       if (*cp != '\n')
5800153         {
5800154           fprintf (stderr, "Command line too long\n");
5800155           do
5800156             {
5800157               len = fgetc (stdin);
5800158             }
5800159           while ((len != EOF) && (len != '\n'));
5800160           // 
5800161           continue;
5800162         }
5800163       // 
5800164       while ((cp > buf) && isblank (cp[-1]))
5800165         {
5800166           cp--;
5800167         }
5800168       // 
5800169       *cp = '\0';
5800170       // 
5800171       cp = buf;
5800172       // 
5800173       while (isblank (*cp))
5800174         {
5800175           // *cp++;
5800176           cp++;
5800177         }
5800178       // 
5800179       have1 = false;
5800180       have2 = false;
5800181       // 
5800182       if ((curnum == 0) && (lastnum > 0))
5800183         {
5800184           curnum = 1;
5800185           curline = lines.next;
5800186         }
5800187       // 
5800188       if (!getnum (&cp, &have1, &num1))
5800189         {
5800190           continue;
5800191         }
5800192       // 
5800193       while (isblank (*cp))
5800194         {
5800195           cp++;
5800196         }
5800197       // 
5800198       if (*cp == ',')
5800199         {
5800200           cp++;
5800201           if (!getnum (&cp, &have2, &num2))
5800202             {
5800203               continue;
5800204             }
5800205           // 
5800206           if (!have1)
5800207             {
5800208               num1 = 1;
5800209             }
5800210           if (!have2)
5800211             {
5800212               num2 = lastnum;
5800213             }
5800214           have1 = true;
5800215           have2 = true;
5800216         }
5800217       // 
5800218       if (!have1)
5800219         {
5800220           num1 = curnum;
5800221         }
5800222       if (!have2)
5800223         {
5800224           num2 = num1;
5800225         }
5800226       // 
5800227       // Command interpretation switch.
5800228       // 
5800229       switch (*cp++)
5800230         {
5800231         case 'a':
5800232           addlines (num1 + 1);
5800233           break;
5800234           // 
5800235         case 'c':
5800236           deletelines (num1, num2);
5800237           addlines (num1);
5800238           break;
5800239           // 
5800240         case 'd':
5800241           deletelines (num1, num2);
5800242           break;
5800243           // 
5800244         case 'f':
5800245           if (*cp && !isblank (*cp))
5800246             {
5800247               fprintf (stderr, "Bad file command\n");
5800248               break;
5800249             }
5800250           // 
5800251           while (isblank (*cp))
5800252             {
5800253               cp++;
5800254             }
5800255           if (*cp == '\0')
5800256             {
5800257               if (filename)
5800258                 {
5800259                   printf ("\"%s\"\n", filename);
5800260                 }
5800261               else
5800262                 {
5800263                   printf ("No filename\n");
5800264                 }
5800265               break;
5800266             }
5800267           // 
5800268           cp = strdup (cp);
5800269           // 
5800270           if (cp == NULL)
5800271             {
5800272               fprintf (stderr, "No memory for filename\n");
5800273               break;
5800274             }
5800275           // 
5800276           if (filename)
5800277             {
5800278               free (filename);
5800279             }
5800280           // 
5800281           filename = cp;
5800282           break;
5800283           // 
5800284         case 'i':
5800285           addlines (num1);
5800286           break;
5800287           // 
5800288         case 'k':
5800289           while (isblank (*cp))
5800290             {
5800291               cp++;
5800292             }
5800293           // 
5800294           if ((*cp < 'a') || (*cp > 'a') || cp[1])
5800295             {
5800296               fprintf (stderr, "Bad mark name\n");
5800297               break;
5800298             }
5800299           // 
5800300           marks[*cp - 'a'] = num2;
5800301           break;
5800302           // 
5800303         case 'l':
5800304           printlines (num1, num2, true);
5800305           break;
5800306           // 
5800307         case 'p':
5800308           printlines (num1, num2, false);
5800309           break;
5800310           // 
5800311         case 'q':
5800312           while (isblank (*cp))
5800313             {
5800314               cp++;
5800315             }
5800316           // 
5800317           if (have1 || *cp)
5800318             {
5800319               fprintf (stderr, "Bad quit command\n");
5800320               break;
5800321             }
5800322           // 
5800323           if (!dirty)
5800324             {
5800325               return;
5800326             }
5800327           // 
5800328           printf ("Really quit? ");
5800329           fflush (stdout);
5800330           // 
5800331           buf[0] = '\0';
5800332           fgets (buf, sizeof (buf), stdin);
5800333           cp = buf;
5800334           // 
5800335           while (isblank (*cp))
5800336             {
5800337               cp++;
5800338             }
5800339           // 
5800340           if ((*cp == 'y') || (*cp == 'Y'))
5800341             {
5800342               return;
5800343             }
5800344           // 
5800345           break;
5800346           // 
5800347         case 'r':
5800348           if (*cp && !isblank (*cp))
5800349             {
5800350               fprintf (stderr, "Bad read command\n");
5800351               break;
5800352             }
5800353           // 
5800354           while (isblank (*cp))
5800355             {
5800356               cp++;
5800357             }
5800358           // 
5800359           if (*cp == '\0')
5800360             {
5800361               fprintf (stderr, "No filename\n");
5800362               break;
5800363             }
5800364           // 
5800365           if (!have1)
5800366             {
5800367               num1 = lastnum;
5800368             }
5800369           // 
5800370           // Open the file and add to the buffer
5800371           // at the next line.
5800372           // 
5800373           if (readlines (cp, num1 + 1))
5800374             {
5800375               // 
5800376               // If the file open fails, just
5800377               // break the command.
5800378               // 
5800379               break;
5800380             }
5800381           // 
5800382           // Set the default file name, if no
5800383           // previous name is available.
5800384           // 
5800385           if (filename == NULL)
5800386             {
5800387               filename = strdup (cp);
5800388             }
5800389           // 
5800390           break;
5800391 
5800392         case 's':
5800393           subcommand (cp, num1, num2);
5800394           break;
5800395           // 
5800396         case 'w':
5800397           if (*cp && !isblank (*cp))
5800398             {
5800399               fprintf (stderr, "Bad write command\n");
5800400               break;
5800401             }
5800402           // 
5800403           while (isblank (*cp))
5800404             {
5800405               cp++;
5800406             }
5800407           // 
5800408           if (!have1)
5800409             {
5800410               num1 = 1;
5800411               num2 = lastnum;
5800412             }
5800413           // 
5800414           // If the file name is not specified, use
5800415           // the
5800416           // default one.
5800417           // 
5800418           if (*cp == '\0')
5800419             {
5800420               cp = filename;
5800421             }
5800422           // 
5800423           // If even the default file name is not
5800424           // specified,
5800425           // tell it.
5800426           // 
5800427           if (cp == NULL)
5800428             {
5800429               fprintf (stderr, "No file name specified\n");
5800430               break;
5800431             }
5800432           // 
5800433           // Write the file.
5800434           // 
5800435           writelines (cp, num1, num2);
5800436           // 
5800437           break;
5800438           // 
5800439         case 'z':
5800440           switch (*cp)
5800441             {
5800442             case '-':
5800443               printlines (curnum - 21, curnum, false);
5800444               break;
5800445             case '.':
5800446               printlines (curnum - 11, curnum + 10, false);
5800447               break;
5800448             default:
5800449               printlines (curnum, curnum + 21, false);
5800450               break;
5800451             }
5800452           break;
5800453           // 
5800454         case '.':
5800455           if (have1)
5800456             {
5800457               fprintf (stderr, "No arguments allowed\n");
5800458               break;
5800459             }
5800460           printlines (curnum, curnum, false);
5800461           break;
5800462           // 
5800463         case '-':
5800464           if (setcurnum (curnum - 1))
5800465             {
5800466               printlines (curnum, curnum, false);
5800467             }
5800468           break;
5800469           // 
5800470         case '=':
5800471           printf ("%d\n", num1);
5800472           break;
5800473           // 
5800474         case '\0':
5800475           if (have1)
5800476             {
5800477               printlines (num2, num2, false);
5800478               break;
5800479             }
5800480           // 
5800481           if (setcurnum (curnum + 1))
5800482             {
5800483               printlines (curnum, curnum, false);
5800484             }
5800485           break;
5800486           // 
5800487         default:
5800488           fprintf (stderr, "Unimplemented command\n");
5800489           break;
5800490         }
5800491     }
5800492 }
5800493 
5800494 //----------------------------------------------------------
5800495 // Do the substitute command.
5800496 // The current line is set to the last substitution
5800497 // done.
5800498 //----------------------------------------------------------
5800499 void
5800500 subcommand (char *cp, num_t num1, num_t num2)
5800501 {
5800502   int delim;
5800503   char *oldstr;
5800504   char *newstr;
5800505   len_t oldlen;
5800506   len_t newlen;
5800507   len_t deltalen;
5800508   len_t offset;
5800509   line_t *lp;
5800510   line_t *nlp;
5800511   bool globalflag;
5800512   bool printflag;
5800513   bool didsub;
5800514   bool needprint;
5800515 
5800516   if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
5800517     {
5800518       fprintf (stderr, "Bad line range for substitute\n");
5800519       return;
5800520     }
5800521   // 
5800522   globalflag = false;
5800523   printflag = false;
5800524   didsub = false;
5800525   needprint = false;
5800526   // 
5800527   if (isblank (*cp) || (*cp == '\0'))
5800528     {
5800529       fprintf (stderr, "Bad delimiter for substitute\n");
5800530       return;
5800531     }
5800532   // 
5800533   delim = *cp++;
5800534   oldstr = cp;
5800535   // 
5800536   cp = strchr (cp, delim);
5800537   // 
5800538   if (cp == NULL)
5800539     {
5800540       fprintf (stderr,
5800541                "Missing 2nd delimiter for " "substitute\n");
5800542       return;
5800543     }
5800544   // 
5800545   *cp++ = '\0';
5800546   // 
5800547   newstr = cp;
5800548   cp = strchr (cp, delim);
5800549   // 
5800550   if (cp)
5800551     {
5800552       *cp++ = '\0';
5800553     }
5800554   else
5800555     {
5800556       cp = "";
5800557     }
5800558   while (*cp)
5800559     {
5800560       switch (*cp++)
5800561         {
5800562         case 'g':
5800563           globalflag = true;
5800564           break;
5800565           // 
5800566         case 'p':
5800567           printflag = true;
5800568           break;
5800569           // 
5800570         default:
5800571           fprintf (stderr,
5800572                    "Unknown option for substitute\n");
5800573           return;
5800574         }
5800575     }
5800576   // 
5800577   if (*oldstr == '\0')
5800578     {
5800579       if (searchstring[0] == '\0')
5800580         {
5800581           fprintf (stderr, "No previous search string\n");
5800582           return;
5800583         }
5800584       oldstr = searchstring;
5800585     }
5800586   // 
5800587   if (oldstr != searchstring)
5800588     {
5800589       strcpy (searchstring, oldstr);
5800590     }
5800591   // 
5800592   lp = findline (num1);
5800593   if (lp == NULL)
5800594     {
5800595       return;
5800596     }
5800597   // 
5800598   oldlen = strlen (oldstr);
5800599   newlen = strlen (newstr);
5800600   deltalen = newlen - oldlen;
5800601   offset = 0;
5800602   // 
5800603   while (num1 <= num2)
5800604     {
5800605       offset = findstring (lp, oldstr, oldlen, offset);
5800606       if (offset < 0)
5800607         {
5800608           if (needprint)
5800609             {
5800610               printlines (num1, num1, false);
5800611               needprint = false;
5800612             }
5800613           // 
5800614           offset = 0;
5800615           lp = lp->next;
5800616           num1++;
5800617           continue;
5800618         }
5800619       // 
5800620       needprint = printflag;
5800621       didsub = true;
5800622       dirty = true;
5800623 
5800624       // ---------------------------------------------
5800625       // If the replacement string is the same size or 
5800626       // shorter
5800627       // than the old string, then the substitution is 
5800628       // easy.
5800629       // ---------------------------------------------
5800630 
5800631       if (deltalen <= 0)
5800632         {
5800633           memcpy (&lp->data[offset], newstr, newlen);
5800634           // 
5800635           if (deltalen)
5800636             {
5800637               memcpy (&lp->data[offset + newlen],
5800638                       &lp->data[offset + oldlen],
5800639                       lp->len - offset - oldlen);
5800640               // 
5800641               lp->len += deltalen;
5800642             }
5800643           // 
5800644           offset += newlen;
5800645           // 
5800646           if (globalflag)
5800647             {
5800648               continue;
5800649             }
5800650           // 
5800651           if (needprint)
5800652             {
5800653               printlines (num1, num1, false);
5800654               needprint = false;
5800655             }
5800656           // 
5800657           lp = nlp->next;
5800658           num1++;
5800659           continue;
5800660         }
5800661 
5800662       // ---------------------------------------------
5800663       // The new string is larger, so allocate a new
5800664       // line structure and use that.
5800665       // Link it in place of the old line structure.
5800666       // ---------------------------------------------
5800667 
5800668       nlp =
5800669         (line_t *) malloc (sizeof (line_t) + lp->len +
5800670                            deltalen);
5800671       // 
5800672       if (nlp == NULL)
5800673         {
5800674           fprintf (stderr, "Cannot get memory for line\n");
5800675           return;
5800676         }
5800677       // 
5800678       nlp->len = lp->len + deltalen;
5800679       // 
5800680       memcpy (nlp->data, lp->data, offset);
5800681       // 
5800682       memcpy (&nlp->data[offset], newstr, newlen);
5800683       // 
5800684       memcpy (&nlp->data[offset + newlen],
5800685               &lp->data[offset + oldlen],
5800686               lp->len - offset - oldlen);
5800687       // 
5800688       nlp->next = lp->next;
5800689       nlp->prev = lp->prev;
5800690       nlp->prev->next = nlp;
5800691       nlp->next->prev = nlp;
5800692       // 
5800693       if (curline == lp)
5800694         {
5800695           curline = nlp;
5800696         }
5800697       // 
5800698       free (lp);
5800699       lp = nlp;
5800700       // 
5800701       offset += newlen;
5800702       // 
5800703       if (globalflag)
5800704         {
5800705           continue;
5800706         }
5800707       // 
5800708       if (needprint)
5800709         {
5800710           printlines (num1, num1, false);
5800711           needprint = false;
5800712         }
5800713       // 
5800714       lp = lp->next;
5800715       num1++;
5800716     }
5800717   // 
5800718   if (!didsub)
5800719     {
5800720       fprintf (stderr,
5800721                "No substitutions found for \"%s\"\n",
5800722                oldstr);
5800723     }
5800724 }
5800725 
5800726 //----------------------------------------------------------
5800727 // Search a line for the specified string starting at
5800728 // the specified offset in the line.  Returns the
5800729 // offset of the found string, or -1.
5800730 //----------------------------------------------------------
5800731 len_t
5800732 findstring (line_t * lp, char *str, len_t len, len_t offset)
5800733 {
5800734   len_t left;
5800735   char *cp;
5800736   char *ncp;
5800737   // 
5800738   cp = &lp->data[offset];
5800739   left = lp->len - offset;
5800740   // 
5800741   while (left >= len)
5800742     {
5800743       ncp = memchr (cp, *str, left);
5800744       if (ncp == NULL)
5800745         {
5800746           return (len_t) - 1;
5800747         }
5800748       // 
5800749       left -= (ncp - cp);
5800750       if (left < len)
5800751         {
5800752           return (len_t) - 1;
5800753         }
5800754       // 
5800755       cp = ncp;
5800756       if (memcmp (cp, str, len) == 0)
5800757         {
5800758           return (len_t) (cp - lp->data);
5800759         }
5800760       // 
5800761       cp++;
5800762       left--;
5800763     }
5800764   // 
5800765   return (len_t) - 1;
5800766 }
5800767 
5800768 //----------------------------------------------------------
5800769 // Add lines which are typed in by the user.
5800770 // The lines are inserted just before the specified
5800771 // line number.
5800772 // The lines are terminated by a line containing a
5800773 // single dot (ugly!), or by an end of file.
5800774 //----------------------------------------------------------
5800775 void
5800776 addlines (num_t num)
5800777 {
5800778   int len;
5800779   char buf[USERSIZE + 1];
5800780   // 
5800781   while (fgets (buf, sizeof (buf), stdin))
5800782     {
5800783       if ((buf[0] == '.') && (buf[1] == '\n')
5800784           && (buf[2] == '\0'))
5800785         {
5800786           return;
5800787         }
5800788       // 
5800789       len = strlen (buf);
5800790       // 
5800791       if (len == 0)
5800792         {
5800793           return;
5800794         }
5800795       // 
5800796       if (buf[len - 1] != '\n')
5800797         {
5800798           fprintf (stderr, "Line too long\n");
5800799           // 
5800800           do
5800801             {
5800802               len = fgetc (stdin);
5800803             }
5800804           while ((len != EOF) && (len != '\n'));
5800805           // 
5800806           return;
5800807         }
5800808       // 
5800809       if (!insertline (num++, buf, len))
5800810         {
5800811           return;
5800812         }
5800813     }
5800814 }
5800815 
5800816 //----------------------------------------------------------
5800817 // Parse a line number argument if it is present.  This
5800818 // is a sum or difference of numbers, '.', '$', 'x, or
5800819 // a search string. 
5800820 // Returns true if successful (whether or not there was
5800821 // a number). 
5800822 // Returns false if there was a parsing error, with a
5800823 // message output.
5800824 // Whether there was a number is returned indirectly,
5800825 // as is the number.
5800826 // The character pointer which stopped the scan is also
5800827 // returned.
5800828 //----------------------------------------------------------
5800829 static bool
5800830 getnum (char **retcp, bool * rethavenum, num_t * retnum)
5800831 {
5800832   char *cp;
5800833   char *str;
5800834   bool havenum;
5800835   num_t value;
5800836   num_t num;
5800837   num_t sign;
5800838   // 
5800839   cp = *retcp;
5800840   havenum = false;
5800841   value = 0;
5800842   sign = 1;
5800843   // 
5800844   while (true)
5800845     {
5800846       while (isblank (*cp))
5800847         {
5800848           cp++;
5800849         }
5800850       // 
5800851       switch (*cp)
5800852         {
5800853         case '.':
5800854           havenum = true;
5800855           num = curnum;
5800856           cp++;
5800857           break;
5800858           // 
5800859         case '$':
5800860           havenum = true;
5800861           num = lastnum;
5800862           cp++;
5800863           break;
5800864           // 
5800865         case '\'':
5800866           cp++;
5800867           if ((*cp < 'a') || (*cp > 'z'))
5800868             {
5800869               fprintf (stderr, "Bad mark name\n");
5800870               return false;
5800871             }
5800872           // 
5800873           havenum = true;
5800874           num = marks[*cp++ - 'a'];
5800875           break;
5800876           // 
5800877         case '/':
5800878           str = ++cp;
5800879           cp = strchr (str, '/');
5800880           if (cp)
5800881             {
5800882               *cp++ = '\0';
5800883             }
5800884           else
5800885             {
5800886               cp = "";
5800887             }
5800888           num = searchlines (str, curnum, lastnum);
5800889           if (num == 0)
5800890             {
5800891               return false;
5800892             }
5800893           // 
5800894           havenum = true;
5800895           break;
5800896           // 
5800897         default:
5800898           if (!isdigit (*cp))
5800899             {
5800900               *retcp = cp;
5800901               *rethavenum = havenum;
5800902               *retnum = value;
5800903               return true;
5800904             }
5800905           // 
5800906           num = 0;
5800907           while (isdigit (*cp))
5800908             {
5800909               num = num * 10 + *cp++ - '0';
5800910             }
5800911           havenum = true;
5800912           break;
5800913         }
5800914       // 
5800915       value += num * sign;
5800916       // 
5800917       while (isblank (*cp))
5800918         {
5800919           cp++;
5800920         }
5800921       // 
5800922       switch (*cp)
5800923         {
5800924         case '-':
5800925           sign = -1;
5800926           cp++;
5800927           break;
5800928           // 
5800929         case '+':
5800930           sign = 1;
5800931           cp++;
5800932           break;
5800933           // 
5800934         default:
5800935           *retcp = cp;
5800936           *rethavenum = havenum;
5800937           *retnum = value;
5800938           return true;
5800939         }
5800940     }
5800941 }
5800942 
5800943 //----------------------------------------------------------
5800944 // Initialize everything for editing.
5800945 //----------------------------------------------------------
5800946 bool
5800947 initedit (void)
5800948 {
5800949   int i;
5800950   // 
5800951   bufsize = INITBUFSIZE;
5800952   bufbase = malloc (bufsize);
5800953   // 
5800954   if (bufbase == NULL)
5800955     {
5800956       fprintf (stderr, "No memory for buffer\n");
5800957       return false;
5800958     }
5800959   // 
5800960   bufptr = bufbase;
5800961   bufused = 0;
5800962   // 
5800963   lines.next = &lines;
5800964   lines.prev = &lines;
5800965   // 
5800966   curline = NULL;
5800967   curnum = 0;
5800968   lastnum = 0;
5800969   dirty = false;
5800970   filename = NULL;
5800971   searchstring[0] = '\0';
5800972   // 
5800973   for (i = 0; i < 26; i++)
5800974     {
5800975       marks[i] = 0;
5800976     }
5800977   // 
5800978   return true;
5800979 }
5800980 
5800981 //----------------------------------------------------------
5800982 // Finish editing.
5800983 //----------------------------------------------------------
5800984 void
5800985 termedit (void)
5800986 {
5800987   if (bufbase)
5800988     free (bufbase);
5800989   bufbase = NULL;
5800990   // 
5800991   bufptr = NULL;
5800992   bufsize = 0;
5800993   bufused = 0;
5800994   // 
5800995   if (filename)
5800996     free (filename);
5800997   filename = NULL;
5800998   // 
5800999   searchstring[0] = '\0';
5801000   // 
5801001   if (lastnum)
5801002     deletelines (1, lastnum);
5801003   // 
5801004   lastnum = 0;
5801005   curnum = 0;
5801006   curline = NULL;
5801007 }
5801008 
5801009 //----------------------------------------------------------
5801010 // Read lines from a file at the specified line number.
5801011 // Returns true if the file was successfully read.
5801012 //----------------------------------------------------------
5801013 bool
5801014 readlines (char *file, num_t num)
5801015 {
5801016   int fd;
5801017   int cc;
5801018   len_t len;
5801019   len_t linecount;
5801020   len_t charcount;
5801021   char *cp;
5801022   // 
5801023   if ((num < 1) || (num > lastnum + 1))
5801024     {
5801025       fprintf (stderr, "Bad line for read\n");
5801026       return false;
5801027     }
5801028   // 
5801029   fd = open (file, O_RDONLY);
5801030   if (fd < 0)
5801031     {
5801032       perror (file);
5801033       return false;
5801034     }
5801035   // 
5801036   bufptr = bufbase;
5801037   bufused = 0;
5801038   linecount = 0;
5801039   charcount = 0;
5801040   // 
5801041   printf ("\"%s\", ", file);
5801042   fflush (stdout);
5801043   // 
5801044   do
5801045     {
5801046       cp = memchr (bufptr, '\n', bufused);
5801047       if (cp)
5801048         {
5801049           len = (cp - bufptr) + 1;
5801050           // 
5801051           if (!insertline (num, bufptr, len))
5801052             {
5801053               close (fd);
5801054               return false;
5801055             }
5801056           // 
5801057           bufptr += len;
5801058           bufused -= len;
5801059           charcount += len;
5801060           linecount++;
5801061           num++;
5801062           continue;
5801063         }
5801064       // 
5801065       if (bufptr != bufbase)
5801066         {
5801067           memcpy (bufbase, bufptr, bufused);
5801068           bufptr = bufbase + bufused;
5801069         }
5801070       // 
5801071       if (bufused >= bufsize)
5801072         {
5801073           len = (bufsize * 3) / 2;
5801074           cp = realloc (bufbase, len);
5801075           if (cp == NULL)
5801076             {
5801077               fprintf (stderr, "No memory for buffer\n");
5801078               close (fd);
5801079               return false;
5801080             }
5801081           // 
5801082           bufbase = cp;
5801083           bufptr = bufbase + bufused;
5801084           bufsize = len;
5801085         }
5801086       // 
5801087       cc = read (fd, bufptr, bufsize - bufused);
5801088       bufused += cc;
5801089       bufptr = bufbase;
5801090     }
5801091   while (cc > 0);
5801092   // 
5801093   if (cc < 0)
5801094     {
5801095       perror (file);
5801096       close (fd);
5801097       return false;
5801098     }
5801099   // 
5801100   if (bufused)
5801101     {
5801102       if (!insertline (num, bufptr, bufused))
5801103         {
5801104           close (fd);
5801105           return -1;
5801106         }
5801107       linecount++;
5801108       charcount += bufused;
5801109     }
5801110   // 
5801111   close (fd);
5801112   // 
5801113   printf ("%d lines%s, %d chars\n",
5801114           linecount, (bufused ? " (incomplete)" : ""),
5801115           charcount);
5801116   // 
5801117   return true;
5801118 }
5801119 
5801120 //----------------------------------------------------------
5801121 // Write the specified lines out to the specified file.
5801122 // Returns true if successful, or false on an error
5801123 // with a message output.
5801124 //----------------------------------------------------------
5801125 bool
5801126 writelines (char *file, num_t num1, num_t num2)
5801127 {
5801128   int fd;
5801129   line_t *lp;
5801130   len_t linecount;
5801131   len_t charcount;
5801132   // 
5801133   if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
5801134     {
5801135       fprintf (stderr, "Bad line range for write\n");
5801136       return false;
5801137     }
5801138   // 
5801139   linecount = 0;
5801140   charcount = 0;
5801141   // 
5801142   fd = creat (file, 0666);
5801143   if (fd < 0)
5801144     {
5801145       perror (file);
5801146       return false;
5801147     }
5801148   // 
5801149   printf ("\"%s\", ", file);
5801150   fflush (stdout);
5801151   // 
5801152   lp = findline (num1);
5801153   if (lp == NULL)
5801154     {
5801155       close (fd);
5801156       return false;
5801157     }
5801158   // 
5801159   while (num1++ <= num2)
5801160     {
5801161       if (write (fd, lp->data, lp->len) != lp->len)
5801162         {
5801163           perror (file);
5801164           close (fd);
5801165           return false;
5801166         }
5801167       // 
5801168       charcount += lp->len;
5801169       linecount++;
5801170       lp = lp->next;
5801171     }
5801172   // 
5801173   if (close (fd) < 0)
5801174     {
5801175       perror (file);
5801176       return false;
5801177     }
5801178   // 
5801179   printf ("%d lines, %d chars\n", linecount, charcount);
5801180   // 
5801181   return true;
5801182 }
5801183 
5801184 //----------------------------------------------------------
5801185 // Print lines in a specified range.
5801186 // The last line printed becomes the current line.
5801187 // If expandflag is true, then the line is printed
5801188 // specially to show magic characters.
5801189 //----------------------------------------------------------
5801190 bool
5801191 printlines (num_t num1, num_t num2, bool expandflag)
5801192 {
5801193   line_t *lp;
5801194   unsigned char *cp;
5801195   int ch;
5801196   len_t count;
5801197   // 
5801198   if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
5801199     {
5801200       fprintf (stderr, "Bad line range for print\n");
5801201       return false;
5801202     }
5801203   // 
5801204   lp = findline (num1);
5801205   if (lp == NULL)
5801206     {
5801207       return false;
5801208     }
5801209   // 
5801210   while (num1 <= num2)
5801211     {
5801212       if (!expandflag)
5801213         {
5801214           write (STDOUT_FILENO, lp->data, lp->len);
5801215           setcurnum (num1++);
5801216           lp = lp->next;
5801217           continue;
5801218         }
5801219 
5801220       // -----------------------------------------------
5801221       // Show control characters and characters with
5801222       // the high bit set specially.
5801223       // -----------------------------------------------
5801224 
5801225       cp = (unsigned char *) lp->data;
5801226       count = lp->len;
5801227       // 
5801228       if ((count > 0) && (cp[count - 1] == '\n'))
5801229         {
5801230           count--;
5801231         }
5801232       // 
5801233       while (count-- > 0)
5801234         {
5801235           ch = *cp++;
5801236           if (ch & 0x80)
5801237             {
5801238               fputs ("M-", stdout);
5801239               ch &= 0x7f;
5801240             }
5801241           if (ch < ' ')
5801242             {
5801243               fputc ('^', stdout);
5801244               ch += '@';
5801245             }
5801246           if (ch == 0x7f)
5801247             {
5801248               fputc ('^', stdout);
5801249               ch = '?';
5801250             }
5801251           fputc (ch, stdout);
5801252         }
5801253       // 
5801254       fputs ("$\n", stdout);
5801255       // 
5801256       setcurnum (num1++);
5801257       lp = lp->next;
5801258     }
5801259   // 
5801260   return true;
5801261 }
5801262 
5801263 //----------------------------------------------------------
5801264 // Insert a new line with the specified text.
5801265 // The line is inserted so as to become the specified
5801266 // line, thus pushing any existing and further lines
5801267 // down one.
5801268 // The inserted line is also set to become the current
5801269 // line.
5801270 // Returns true if successful.
5801271 //----------------------------------------------------------
5801272 bool
5801273 insertline (num_t num, char *data, len_t len)
5801274 {
5801275   line_t *newlp;
5801276   line_t *lp;
5801277   // 
5801278   if ((num < 1) || (num > lastnum + 1))
5801279     {
5801280       fprintf (stderr, "Inserting at bad line number\n");
5801281       return false;
5801282     }
5801283   // 
5801284   newlp = (line_t *) malloc (sizeof (line_t) + len - 1);
5801285   if (newlp == NULL)
5801286     {
5801287       fprintf (stderr,
5801288                "Failed to allocate memory for line\n");
5801289       return false;
5801290     }
5801291   // 
5801292   memcpy (newlp->data, data, len);
5801293   newlp->len = len;
5801294   // 
5801295   if (num > lastnum)
5801296     {
5801297       lp = &lines;
5801298     }
5801299   else
5801300     {
5801301       lp = findline (num);
5801302       if (lp == NULL)
5801303         {
5801304           free ((char *) newlp);
5801305           return false;
5801306         }
5801307     }
5801308   // 
5801309   newlp->next = lp;
5801310   newlp->prev = lp->prev;
5801311   lp->prev->next = newlp;
5801312   lp->prev = newlp;
5801313   // 
5801314   lastnum++;
5801315   dirty = true;
5801316   // 
5801317   return setcurnum (num);
5801318 }
5801319 
5801320 //----------------------------------------------------------
5801321 // Delete lines from the given range.
5801322 //----------------------------------------------------------
5801323 bool
5801324 deletelines (num_t num1, num_t num2)
5801325 {
5801326   line_t *lp;
5801327   line_t *nlp;
5801328   line_t *plp;
5801329   num_t count;
5801330   // 
5801331   if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
5801332     {
5801333       fprintf (stderr, "Bad line numbers for delete\n");
5801334       return false;
5801335     }
5801336   // 
5801337   lp = findline (num1);
5801338   if (lp == NULL)
5801339     {
5801340       return false;
5801341     }
5801342   // 
5801343   if ((curnum >= num1) && (curnum <= num2))
5801344     {
5801345       if (num2 < lastnum)
5801346         {
5801347           setcurnum (num2 + 1);
5801348         }
5801349       else if (num1 > 1)
5801350         {
5801351           setcurnum (num1 - 1);
5801352         }
5801353       else
5801354         {
5801355           curnum = 0;
5801356         }
5801357     }
5801358   // 
5801359   count = num2 - num1 + 1;
5801360   // 
5801361   if (curnum > num2)
5801362     {
5801363       curnum -= count;
5801364     }
5801365   // 
5801366   lastnum -= count;
5801367   // 
5801368   while (count-- > 0)
5801369     {
5801370       nlp = lp->next;
5801371       plp = lp->prev;
5801372       plp->next = nlp;
5801373       nlp->prev = plp;
5801374       lp->next = NULL;
5801375       lp->prev = NULL;
5801376       lp->len = 0;
5801377       free (lp);
5801378       lp = nlp;
5801379     }
5801380   // 
5801381   dirty = true;
5801382   // 
5801383   return true;
5801384 }
5801385 
5801386 //----------------------------------------------------------
5801387 // Search for a line which contains the specified
5801388 // string.
5801389 // If the string is NULL, then the previously searched
5801390 // for string is used.  The currently searched for
5801391 // string is saved for future use.
5801392 // Returns the line number which matches, or 0 if there
5801393 // was no match with an error printed.
5801394 //----------------------------------------------------------
5801395 num_t
5801396 searchlines (char *str, num_t num1, num_t num2)
5801397 {
5801398   line_t *lp;
5801399   int len;
5801400   // 
5801401   if ((num1 < 1) || (num2 > lastnum) || (num1 > num2))
5801402     {
5801403       fprintf (stderr, "Bad line numbers for search\n");
5801404       return 0;
5801405     }
5801406   // 
5801407   if (*str == '\0')
5801408     {
5801409       if (searchstring[0] == '\0')
5801410         {
5801411           fprintf (stderr, "No previous search string\n");
5801412           return 0;
5801413         }
5801414       str = searchstring;
5801415     }
5801416   // 
5801417   if (str != searchstring)
5801418     {
5801419       strcpy (searchstring, str);
5801420     }
5801421   // 
5801422   len = strlen (str);
5801423   // 
5801424   lp = findline (num1);
5801425   if (lp == NULL)
5801426     {
5801427       return 0;
5801428     }
5801429   // 
5801430   while (num1 <= num2)
5801431     {
5801432       if (findstring (lp, str, len, 0) >= 0)
5801433         {
5801434           return num1;
5801435         }
5801436       // 
5801437       num1++;
5801438       lp = lp->next;
5801439     }
5801440   // 
5801441   fprintf (stderr, "Cannot find string \"%s\"\n", str);
5801442   // 
5801443   return 0;
5801444 }
5801445 
5801446 //----------------------------------------------------------
5801447 // Return a pointer to the specified line number.
5801448 //----------------------------------------------------------
5801449 line_t *
5801450 findline (num_t num)
5801451 {
5801452   line_t *lp;
5801453   num_t lnum;
5801454   // 
5801455   if ((num < 1) || (num > lastnum))
5801456     {
5801457       fprintf (stderr,
5801458                "Line number %d does not exist\n", num);
5801459       return NULL;
5801460     }
5801461   // 
5801462   if (curnum <= 0)
5801463     {
5801464       curnum = 1;
5801465       curline = lines.next;
5801466     }
5801467   // 
5801468   if (num == curnum)
5801469     {
5801470       return curline;
5801471     }
5801472   // 
5801473   lp = curline;
5801474   lnum = curnum;
5801475   // 
5801476   if (num < (curnum / 2))
5801477     {
5801478       lp = lines.next;
5801479       lnum = 1;
5801480     }
5801481   else if (num > ((curnum + lastnum) / 2))
5801482     {
5801483       lp = lines.prev;
5801484       lnum = lastnum;
5801485     }
5801486   // 
5801487   while (lnum < num)
5801488     {
5801489       lp = lp->next;
5801490       lnum++;
5801491     }
5801492   // 
5801493   while (lnum > num)
5801494     {
5801495       lp = lp->prev;
5801496       lnum--;
5801497     }
5801498   // 
5801499   return lp;
5801500 }
5801501 
5801502 //----------------------------------------------------------
5801503 // Set the current line number.
5801504 // Returns true if successful.
5801505 //----------------------------------------------------------
5801506 bool
5801507 setcurnum (num_t num)
5801508 {
5801509   line_t *lp;
5801510   // 
5801511   lp = findline (num);
5801512   if (lp == NULL)
5801513     {
5801514       return false;
5801515     }
5801516   // 
5801517   curnum = num;
5801518   curline = lp;
5801519   // 
5801520   return true;
5801521 }
5801522 
5801523 /* END CODE */
 |