sources-request@mirror.UUCP (01/27/87)
Submitted by: emoryu1!arnold (Arnold D. Robbins) Mod.sources: Volume 8, Issue 1 Archive-name: se/Part01 Here is the second release of the Georgia Tech Screen Editor, 'se'. There were enough changes that a whole new posting is warranted. Major Changes: All Georgia Tech specific stuff removed. It understands window size changes on 4.3BSD and ATT Unix PC/3B1 Support for the shared library on the ATT Unix PC/3B1 Considerable source code reorganization in certain files. Enjoy, Arnold Robbins #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # ascii.h # constdefs.h # docmd1.c # docmd2.c export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(6131 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' # # $Header: README,v 1.3 86/07/17 17:52:23 arnold Exp $ # # $Log: README,v $ # Revision 1.3 86/07/17 17:52:23 arnold # Fixed some spelling mistakes. # # Revision 1.2 86/07/17 17:19:06 arnold # Removed GT specific stuff, added discussion of window sensitivities. # # Revision 1.1 86/05/06 13:34:09 osadr # Initial revision # # # README: This directory contains the source files for the Unix version of the Georgia Tech Screen Editor "Se". It has three subdirectories which contain things that se needs. Here is a rundown of the various files. Files containing documentation are: README -- this file. se.m4 -- nroff manual page for se (has to be munged to create se.1). scriptse.1 -- nroff manual page for scriptse. The header files are: ascii.h -- definition of ASCII mnemonics and control characters. extern.h -- external data definitions for the screen editor. se.h -- global #define's for the screen editor. constdefs.h -- global constants, also used by files in subdirectories. The C source files are: main.c -- main program and declaration of globals, initialization. edit.c -- main command loop to get and execute commands, file handling. docmd1.c -- command decoder and functions for most commands. docmd2.c -- functions for the rest of the commands. misc.c -- miscellanious functions. scratch.c -- scratch file manipulating functions. screen.c -- routines to keep track of the screen contents. term.c -- routines for changing the terminal. The subdirectories are: libchangetty -- routines to change the terminal driver back and forth. pat -- pattern matching routines. se_h -- contains help scripts for all commands in se. Miscellanious files: where -- shell file to determine System V (R 1 or 2), 4.1, or 4.2 BSD. m4munge -- manipulate output of where for m4 for se man page makefile -- the makefile for make(1). print2 -- inode used by make for printing only changed stuff. scriptse.c -- quick and dirty C program to make scripts for se. scriptse.1 -- manual page for same. Executable files: se -- executable version of the screen editor. scriptse -- the executable version of the script maker. Conditional Compilation flags: The flag HARD_TERMS, if added to the CFLAGS macro in the makefile, will remove the terminal-independent code which uses termlib, and put back the original, terminal-types-hardwired-into-the-program code. The only reason to do this is if se has to run on a system without the termlib package. Using termlib, se is considerably smaller, as well as more flexible. The flag OLD_SCRATCH, if added to the CFLAGS macro in the makefile, will cause se to use the original, linked-list method for keeping track of lines in the buffer. This method is faster for rearranging lines, but considerably slower for simply looking up lines. Currently, se uses the method given in Software Tools in Pascal, which keeps the lines in order in an array. It is slower at rearranging, but as fast as possible for finding lines in the buffer. This version also takes less data and code space. The flag OLD_GLOB, if added to the CFLAGS macro in the makefile, will keep se from special casing commands whose effect is to reverse the order of the lines in the buffer. The special casing code can save an *incredible* amount of time for this pathological case, so it is best to leave things alone. This only applies to the Software Tools in Pascal style line handling. The flag LOG_USAGE, if added to the CFLAGS macro in the makefile, will cause se to write usage "statistics" to a log file, consisting of the login name and time and date when an individual used se. The logfile path name in the log() routine in edit.c should be changed to use a system accounting file somewhere. It currently creates a file in /usr/tmp. The 'where' command creates a file called 'flags', which the makefile cats inside ``s. These define and/or undefine the flags USG for System V, S5R2 if for Release 2, BSD for 4.1 and 4.2, and BSD4_2 for 4.2 specific code. Miscellanious: Code which is dependent on the Berkeley job control stuff is also conditionally compiled in, so that on systems without it, it won't get in the way. Code has been added which should allow se to come up under USG Unix 5.0 (System V). If S5R2 is defined, se will use the terminfo package. Otherwise, it assumes Release 1, and that the BSD termlib package has been ported and is available. There is code in term.c to test if se is running on a system with windows or not. It currently understands the windows on an ATT Unix PC (or 3B1) and the windowing ioctl's in BRL Unix, which should be identical to those in 4.3 BSD. Comments: It is a big piece of software. But, if you 1) read both Software Tools and Software Tools in Pascal (the chapters on editing and pattern matching, if you don't want to read all of the books), and 2) take your time, you should be able to understand, and eventually make changes to it, as necessary. Authors: Se started out as the version of 'ed' that came with the book 'Software Tools', by Kernighan and Plauger, which was written in Ratfor. On the Pr1me computers at the School of Information and Computer Science at Georgia Tech, Dan Forsyth, Perry Flinn, and Alan Akin added all the enhancements suggested in the exercises in the book, and some more of their own. Jack Waugh made extensive modifications to turn it into a screen editor; further work was done by Dan Forsyth. All of this was in an improved Georgia Tech version of Ratfor. Later, Dan Forsyth, then (and now) at Medical Systems Development Corporation, converted the Ratfor version into C, for Berkeley Unix (4.1 BSD). At Georgia Tech, Arnold Robbins took the C version and added many new features and improvements, the most important of which was termcap support and System V support. The existing help screens were edited and completed at that time, as well. This was completed in early 1985. Arnold Robbins is now at ...!gatech!emory!arnold, and will make every reasonable attempt to answer any questions anyone may have about it, but in no way promises to support or enhance 'se'. SHAR_EOF fi # end of overwriting check echo shar: extracting "'ascii.h'" '(1389 characters)' if test -f 'ascii.h' then echo shar: will not over-write existing file "'ascii.h'" else cat << \SHAR_EOF > 'ascii.h' /* * $Header: ascii.h,v 1.1 86/05/06 13:35:19 osadr Exp $ */ /* * $Log: ascii.h,v $ * Revision 1.1 86/05/06 13:35:19 osadr * Initial revision * * */ /* ** ascii.h ** ** definitions of ASCII mnemonics and synonyms. */ #ifndef _ASCII_H #define _ASCII_H #define NUL '\0' #define SOH '\001' #define STX '\002' #define ETX '\003' #define EOT '\004' #define ENQ '\005' #define ACK '\006' #define BEL '\007' #define BS '\010' #define HT '\011' #define LF '\012' #define VT '\013' #define FF '\014' #define CR '\015' #define SO '\016' #define SI '\017' #define DLE '\020' #define DC1 '\021' #define DC2 '\022' #define DC3 '\023' #define DC4 '\024' #define NAK '\025' #define SYN '\026' #define ETB '\027' #define CAN '\030' #define EM '\031' #define SUB '\032' #define ESC '\033' #define FS '\034' #define GS '\035' #define RS '\036' #define US '\037' #define SP '\040' #define DEL '\177' #define CTRL_A SOH #define CTRL_B STX #define CTRL_C ETX #define CTRL_D EOT #define CTRL_E ENQ #define CTRL_F ACK #define CTRL_G BEL #define CTRL_H BS #define CTRL_I HT #define CTRL_J LF #define CTRL_K VT #define CTRL_L FF #define CTRL_M CR #define CTRL_N SO #define CTRL_O SI #define CTRL_P DLE #define CTRL_Q DC1 #define CTRL_R DC2 #define CTRL_S DC3 #define CTRL_T DC4 #define CTRL_U NAK #define CTRL_V SYN #define CTRL_W ETB #define CTRL_X CAN #define CTRL_Y EM #define CTRL_Z SUB #endif SHAR_EOF fi # end of overwriting check echo shar: extracting "'constdefs.h'" '(325 characters)' if test -f 'constdefs.h' then echo shar: will not over-write existing file "'constdefs.h'" else cat << \SHAR_EOF > 'constdefs.h' /* * $Header: constdefs.h,v 1.1 86/05/06 13:35:37 osadr Exp $ */ /* * $Log: constdefs.h,v $ * Revision 1.1 86/05/06 13:35:37 osadr * Initial revision * * */ /* ** constdefs.h ** ** Standard macro definitions for se screen editor */ #define EOS '\0' #define ERR (-3) #define OK (-2) #define NO 0 #define YES 1 SHAR_EOF fi # end of overwriting check echo shar: extracting "'docmd1.c'" '(27523 characters)' if test -f 'docmd1.c' then echo shar: will not over-write existing file "'docmd1.c'" else cat << \SHAR_EOF > 'docmd1.c' #ifndef lint static char RCSid[] = "$Header: docmd1.c,v 1.3 86/07/17 17:19:37 arnold Exp $"; #endif /* * $Log: docmd1.c,v $ * Revision 1.3 86/07/17 17:19:37 arnold * Some general code cleaning up. * * Revision 1.2 86/07/11 15:10:20 osadr * Removed Georgia Tech specific items. * * Revision 1.1 86/05/06 13:36:44 osadr * Initial revision * * */ /* ** docmd1.c ** ** main command processor. routines for individual commands */ #include "se.h" #include "extern.h" /* static data definitions -- variables only needed in this file */ static char Tlpat[MAXPAT] = ""; /* saved character list for y/t command */ static char Tabstr[MAXLINE] = ""; /* string representation of tab stops */ static char Ddir = FORWARD; /* delete direction */ static int Compress; /* compress/expand tabs on read/write */ /* docmd --- handle all commands except globals */ int docmd (lin, i, glob, status) char lin[]; int i, glob, *status; { char file[MAXLINE], sub[MAXPAT]; char kname; int gflag, line3, pflag, flag, fflag, junk, allbut, tflag; int append (), ckchar (), ckp (), ckupd (), copy (); int delete (), domark (), doopt (), doprnt (), doread (); int doshell (); int dotlit (), doundo (), dowrit (), getfn (), getkn (); int getone (), getrange (), getrhs (), getstr (), inject (); int join (), makset (), move (), nextln (), optpat (); int prevln (), substr (), draw_box (); char *expand_env (); *status = ERR; if (intrpt ()) /* catch a pending interrupt */ return (*status); switch (lin[i]) { case APPENDCOM: case UCAPPENDCOM: if (lin[i + 1] == '\n' || lin[i + 1] == ':') { defalt (Curln, Curln); if (lin[i + 1] == '\n') { /* avoid updating with inline insertion */ adjust_window (Line1, Line2); updscreen (); } *status = append (Line2, &lin[i + 1]); } break; case PRINTCUR: if (lin[i + 1] == '\n') { defalt (Curln, Curln); saynum (Line2); *status = OK; } break; case OVERLAYCOM: case UCOVERLAYCOM: defalt (Curln, Curln); if (lin[i + 1] == '\n') overlay (status); break; case CHANGE: case UCCHANGE: defalt (Curln, Curln); if (Line1 <= 0) Errcode = EORANGE; else if (lin[i + 1] == '\n' || lin[i + 1] == ':') { if (lin[i + 1] == '\n') { /* avoid updating with inline insertion */ adjust_window (Line2, Line2); updscreen (); } First_affected = min (First_affected, Line1); if (lin[i + 1] == '\n') warn_deleted (Line1, Line2); *status = append (Line2, &lin[i + 1]); if (*status != ERR) { line3 = Curln; delete (Line1, Line2, status); Curln = line3 - (Line2 - Line1 + 1); /* adjust for deleted lines */ } } break; case DELCOM: case UCDELCOM: if (ckp (lin, i + 1, &pflag, status) == OK) { defalt (Curln, Curln); if (delete (Line1, Line2, status) == OK && Ddir == FORWARD && nextln (Curln) != 0) Curln = nextln (Curln); } break; case INSERT: case UCINSERT: defalt (Curln, Curln); if (Line1 <= 0) Errcode = EORANGE; else if (lin[i + 1] == '\n' || lin[i + 1] == ':') { if (lin[i + 1] == '\n') { /* avoid updating with inline insertion */ adjust_window (Line1, Line2); updscreen (); } *status = append (prevln (Line2), &lin[i + 1]); } break; case MOVECOM: case UCMOVECOM: i++; if (getone (lin, &i, &line3, status) == EOF) *status = ERR; if (*status == OK && ckp (lin, i, &pflag, status) == OK) { defalt (Curln, Curln); *status = move (line3); } break; case COPYCOM: case UCCOPYCOM: i++; if (getone (lin, &i, &line3, status) == EOF) *status = ERR; if (*status == OK && ckp (lin, i, &pflag, status) == OK) { defalt (Curln, Curln); *status = copy (line3); } break; case SUBSTITUTE: case UCSUBSTITUTE: i++; if (lin[i] == '\n') { /* turn "s\n" into "s//%/\n" */ lin[i+0] = '/'; lin[i+1] = '/'; lin[i+2] = '%'; lin[i+3] = '/'; lin[i+4] = '\n'; lin[i+5] = EOS; Peekc = SKIP_RIGHT; } else { /* try to handle "s/stuff\n" */ int j, missing_delim; missing_delim = YES; for (j = i + 1; lin[j] != '\n'; j++) if (lin[j] == ESCAPE && lin[j+1] == lin[i]) j++; /* skip esc, loop continues */ else if (lin[j] == lin[i]) { missing_delim = NO; break; /* for */ } if (missing_delim) { for (; lin[j] != EOS; j++) ; j--; /* j now at newline */ lin[j] = lin[i]; /* delim */ lin[++j] = '\n'; lin[++j] = EOS; Peekc = SKIP_RIGHT; /* rest of routines will continue to fix up */ } } if (optpat (lin, &i) == OK && getrhs (lin, &i, sub, &gflag) == OK && ckp (lin, i + 1, &pflag, status) == OK) { defalt (Curln, Curln); *status = subst (sub, gflag, glob); } break; case TLITCOM: case UCTLITCOM: i++; if (lin[i] == '\n') { /* turn "y\n" into "y//%/\n" */ lin[i+0] = '/'; lin[i+1] = '/'; lin[i+2] = '%'; lin[i+3] = '/'; lin[i+4] = '\n'; lin[i+5] = EOS; Peekc = SKIP_RIGHT; } else { /* try to handle "y/stuff\n" */ int j, missing_delim; missing_delim = YES; for (j = i + 1; lin[j] != '\n'; j++) if (lin[j] == ESCAPE && lin[j+1] == lin[i]) j++; /* skip esc, loop continues */ else if (lin[j] == lin[i]) { missing_delim = NO; break; /* for */ } if (missing_delim) { for (; lin[j] != EOS; j++) ; j--; /* j now at newline */ lin[j] = lin[i]; /* delim */ lin[++j] = '\n'; lin[++j] = EOS; Peekc = SKIP_RIGHT; /* rest of routines will continue to fix up */ } } if (getrange (lin, &i, Tlpat, MAXPAT, &allbut) == OK && makset (lin, &i, sub, MAXPAT) == OK && ckp (lin, i + 1, &pflag, status) == OK) { defalt (Curln, Curln); *status = dotlit (sub, allbut); } break; case JOINCOM: case UCJOINCOM: i++; if (getstr (lin, &i, sub, MAXPAT) == OK && ckp (lin, i + 1, &pflag, status) == OK) { defalt (prevln (Curln), Curln); *status = join (sub); } break; case UNDOCOM: case UCUNDOCOM: i++; defalt (Curln, Curln); if (ckchar (UCDELCOM, DELCOM, lin, &i, &flag, status) == OK && ckp (lin, i, &pflag, status) == OK) *status = doundo (flag, status); break; case ENTER: case UCENTER: i++; if (Nlines != 0) Errcode = EBADLNR; else if (ckupd (lin, &i, ENTER, status) == OK && ckchar ('x', 'X', lin, &i, &tflag, status) == OK) if (getfn (lin, i - 1, file) == OK) { strcpy (Savfil, expand_env (file)); mesg (Savfil, FILE_MSG); clrbuf (); mkbuf (); dfltsopt (file); *status = doread (0, file, tflag); First_affected = 0; Curln = min (1, Lastln); Buffer_changed = NO; } else *status = ERR; break; case PRINTFIL: case UCPRINTFIL: if (Nlines != 0) Errcode = EBADLNR; else if (getfn (lin, i, file) == OK) { strcpy (Savfil, expand_env (file)); mesg (Savfil, FILE_MSG); *status = OK; } break; case READCOM: case UCREADCOM: i++; if (ckchar ('x', 'X', lin, &i, &tflag, status) == OK) if (getfn (lin, i - 1, file) == OK) { defalt (Curln, Curln); *status = doread (Line2, file, tflag); } break; case WRITECOM: case UCWRITECOM: i++; flag = NO; fflag = NO; junk = ckchar ('>', '+', lin, &i, &flag, &junk); if (flag == NO) junk = ckchar ('!', '!', lin, &i, &fflag, &junk); junk = ckchar ('x', 'X', lin, &i, &tflag, &junk); if (getfn (lin, i - 1, file) == OK) { defalt (1, Lastln); *status = dowrit (Line1, Line2, file, flag, fflag, tflag); } break; case PRINT: case UCPRINT: if (lin[i + 1] == '\n') { defalt (1, Topln); *status = doprnt (Line1, Line2); } break; case PAGECOM: defalt (1, min (Lastln, Botrow - Toprow + Topln)); if (Line1 <= 0) Errcode = EORANGE; else if (lin[i + 1] == '\n') { Topln = Line2; Curln = Line2; First_affected = Line2; *status = OK; } break; case NAMECOM: case UCNAMECOM: i++; if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR && lin[i] == '\n') uniquely_name (kname, status); break; case MARKCOM: case UCMARKCOM: i++; if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR && lin[i] == '\n') { defalt (Curln, Curln); *status = domark (kname); } break; case '\n': line3 = nextln (Curln); defalt (line3, line3); *status = doprnt (Line2, Line2); break; case LOCATECMD: case UCLOCATECMD: if (lin[i+1] == '\n') { char *sysname (); remark (sysname ()); *status = OK; } break; case OPTCOM: case UCOPTCOM: if (Nlines == 0) *status = doopt (lin, &i); else Errcode = EBADLNR; break; case QUIT: case UCQUIT: i++; if (Nlines != 0) Errcode = EBADLNR; else if (ckupd (lin, &i, QUIT, status) == OK) if (lin[i] == '\n') *status = EOF; else *status = ERR; break; case HELP: case UCHELP: i++; if (Nlines == 0) dohelp (lin, &i, status); else Errcode = EBADLNR; break; case MISCCOM: /* miscellanious features */ case UCMISCCOM: i++; switch (lin[i]) { case 'b': /* draw box */ case 'B': defalt (Curln, Curln); i++; *status = draw_box (lin, &i); break; default: Errcode = EWHATZAT; break; } break; case SHELLCOM: i++; defalt (Curln, Curln); *status = doshell (lin, &i); break; default: Errcode = EWHATZAT; /* command not recognized */ break; } if (*status == OK) Probation = NO; return (*status); } /* dohelp --- display documentation about editor */ dohelp (lin, i, status) char lin[]; int *i, *status; { char filename[MAXLINE]; char swt_filename[MAXLINE]; static char helpdir[] = "/usr/local/lib/se_h"; /* help scripts */ int j; FILE *fp, *fopen (); SKIPBL (lin, *i); if (lin[*i] == NEWLINE) sprintf (filename, "%s/elp", helpdir); else { /* build filename from text after "h" */ sprintf (filename, "%s/%s", helpdir, &lin[*i]); j = strlen (filename); filename[j-1] = EOS; /* lop off newline */ } /* map to lower case */ for (j = 0; filename[j] != EOS; j++) if (isupper (filename[j])) filename[j] = tolower (filename[j]); *status = OK; if ((fp = fopen (filename, "r")) == NULL) { *status = ERR; Errcode = ENOHELP; } else { #ifdef u3b2 /* 3B2 seems to have problems with stdio and malloc... */ char buf[BUFSIZ]; setbuf (fp, buf); #endif /* status is OK */ display_message (fp); /* display the help script */ fclose (fp); } } /* doopt --- interpret option command */ int doopt (lin, i) char lin[]; int *i; { int temp, line, stat; char tempstr[4]; int ret; int dosopt (); int ctoi (); (*i)++; ret = ERR; switch (lin[*i]) { case 'g': /* substitutes in a global can(not) fail */ case 'G': if (lin[*i + 1] == '\n') { ret = OK; Globals = ! Globals; /* toggle */ if (Globals == YES) remark ("failed global substitutes continue"); else remark ("failed global substitutes stop"); } break; case 'h': case 'H': /* do/don't use hardware insert/delete */ if (lin[*i + 1] == '\n') { ret = OK; No_hardware = ! No_hardware; if (No_hardware == YES) remark ("no line insert/delete"); else remark ("line insert/delete"); } break; case 'k': /* tell user if buffer saved or not */ case 'K': if (lin[*i + 1] == '\n') { ret = OK; if (Buffer_changed == YES) remark ("not saved"); else remark ("saved"); } break; case 'z': /* suspend the editor process */ case 'Z': if (lin[*i + 1] == '\n') { ret = OK; #ifdef BSD if (Catching_stops) { if (Buffer_changed == YES) fprintf (stderr, "WARNING: buffer not saved\r\n"); kill (getpid(), SIGTSTP); /* stop_hdlr() will do all the work for us */ } #else remark ("process suspension not available"); #endif } break; case 't': /* set or display tab stops for expanding tabs */ case 'T': ++(*i); if (lin[*i] == '\n') { remark (Tabstr); ret = OK; } else { ret = settab (&lin[*i]); if (ret == OK) strcpy (Tabstr, &lin[*i]); else /* defaults were set */ strcpy (Tabstr, "+4"); } break; case 'w': /* set or display warning column */ case 'W': ++(*i); if (lin[*i] == '\n') ret = OK; else { temp = ctoi (lin, i); if (lin[*i] == '\n') if (temp > 0 && temp < MAXLINE - 3) { ret = OK; Warncol = temp; } else Errcode = ENONSENSE; } if (ret == OK) saynum (Warncol); break; case '-': /* fix window in place on screen, or erase it */ ++(*i); if (getnum (lin, i, &line, &stat) == EOF) { mesg ("", HELP_MSG); if (Toprow > 0) { Topln = max (1, Topln - Toprow); Toprow = 0; First_affected = Topln; } ret = OK; } else if (stat != ERR && lin[*i] == '\n') if (Toprow + (line - Topln + 1) < Cmdrow) { Toprow += line - Topln + 1; Topln = line + 1; for (temp = 0; temp < Ncols; temp++) load ('-', Toprow - 1, temp); if (Topln > Lastln) adjust_window (1, Lastln); if (Curln < Topln) Curln = min (Topln, Lastln); ret = OK; } else Errcode = EORANGE; break; case 'a': /* toggle absolute line numbering */ case 'A': if (lin[*i + 1] == '\n') { Absnos = ! Absnos; ret = OK; } break; case 'c': /* toggle case option */ case 'C': if (lin[*i + 1] == '\n') { ret = OK; Invert_case = ! Invert_case; if (Rel_a == 'A') { Rel_a = 'a'; Rel_z = 'z'; } else { Rel_a = 'A'; Rel_z = 'Z'; } } mesg (Invert_case ? "CASE" : "", CASE_MSG); break; case 'd': /* set or display placement of "." after a delete */ case 'D': if (lin[*i + 1] == '\n') { if (Ddir == FORWARD) remark (">"); else remark ("<"); ret = OK; } else if (lin[*i + 2] != '\n') Errcode = EODLSSGTR; else if (lin[*i + 1] == '>') { ret = OK; Ddir = FORWARD; } else if (lin[*i + 1] == '<') { ret = OK; Ddir = BACKWARD; } else Errcode = EODLSSGTR; break; case 'v': /* set or display overlay column */ case 'V': ++(*i); if (lin[*i] == '\n') { if (Overlay_col == 0) remark ("$"); else saynum (Overlay_col); ret = OK; } else { if (lin[*i] == '$' && lin[*i + 1] == '\n') { Overlay_col = 0; ret = OK; } else { temp = ctoi (lin, i); if (lin[*i] == '\n') { Overlay_col = temp; ret = OK; } else Errcode = ENONSENSE; } } break; case 'u': /* set or display character for unprintable chars */ case 'U': if (lin[*i + 1] == '\n') { ret = OK; tempstr[0] = tempstr[2] = '"'; tempstr[1] = Unprintable; tempstr[3] = EOS; remark (tempstr); } else if (lin[*i + 2] == '\n') { if (lin[*i + 1] < ' ' || lin[*i + 1] >= DEL) Errcode = ENONSENSE; else { ret = OK; if (Unprintable != lin[*i + 1]) { Unprintable = lin[*i + 1]; First_affected = Topln; } } } break; case 'l': /* set or display line number display option */ case 'L': if (lin[*i+1] == '\n') { Nchoise = EOS; ret = OK; } else if (lin[*i + 2] == '\n' && (lin[*i + 1] == CURLINE || lin[*i + 1] == LASTLINE || lin[*i + 1] == TOPLINE)) { Nchoise = lin[*i + 1]; ret = OK; } else if (lin[*i + 1] == 'm' || lin[*i + 1] == 'M') { /* set or display the left margin */ (*i)++; if (lin[*i + 1] == '\n') { saynum (Firstcol + 1); ret = OK; } else { (*i)++; temp = ctoi (lin, i); if (lin[*i] == '\n') if (temp > 0 && temp < MAXLINE) { First_affected = Topln; Firstcol = temp - 1; ret = OK; } else Errcode = ENONSENSE; } } break; case 'f': /* fortran (ugh, yick, gross) options */ case 'F': if (lin[*i + 1] == '\n') ret = dosopt ("f"); break; case 's': /* set source options */ case 'S': ret = dosopt (&lin[*i + 1]); break; case 'i': /* set or display indent option */ case 'I': ++(*i); if (lin[*i] == '\n') ret = OK; else if ((lin[*i] == 'a' || lin[*i] == 'A') && lin[*i + 1] == '\n') { Indent = 0; ret = OK; } else { temp = ctoi (lin, i); if (lin[*i] == '\n') if (temp > 0 && temp < MAXLINE - 3) { ret = OK; Indent = temp; } else Errcode = ENONSENSE; } if (ret == OK) if (Indent > 0) saynum (Indent); else remark ("auto"); break; case 'm': /* toggle mail notification */ case 'M': if (lin[*i + 1] == '\n') { Notify = ! Notify; /* toggle notification */ remark (Notify ? "notify on" : "notify off"); ret = OK; } break; case 'x': case 'X': /* toggle tab compression */ if (lin[*i + 1] == '\n') { ret = OK; Compress = ! Compress; mesg (Compress ? "XTABS" : "", COMPRESS_MSG); } break; case 'y': /* encrypt files */ case 'Y': if (lin[*i + 1] == '\n') { crypt_toggle: ret = OK; Crypting = ! Crypting; if (Crypting ) do { getkey (); if (Key[0] == EOS) remark ("Empty keys are not allowed.\n"); } while (Key[0] == EOS); else Key[0] = EOS; } else { register int j; ret = OK; (*i)++; /* *i was the 'y' */ while (isspace (lin[*i]) && lin[*i] != '\n') (*i)++; if (lin[*i] != '\n' && lin[*i] != EOS) { for (j = 0; lin[*i] != '\n' && lin[*i] != EOS; j++, (*i)++) Key[j] = lin[*i]; Key[j] = EOS; Crypting = YES; } else goto crypt_toggle; } mesg (Crypting ? "ENCRYPT" : "", CRYPT_MSG); break; default: Errcode = EOWHAT; } return (ret); } /* domark --- name lines line1 through line2 as kname */ int domark (kname) char kname; { int line; int ret; register LINEDESC *k; LINEDESC *getind (); if (Line1 <= 0) { Errcode = EORANGE; ret = ERR; } else { k = getind (Line1); for (line = Line1; line <= Line2; line++) { if (intrpt()) return (ERR); k -> Markname = kname; k = NEXTLINE(k); } ret = OK; } return (ret); } /* doprnt --- set curln, locate window */ int doprnt (from, to) int from, to; { if (from <= 0) { Errcode = EORANGE; return (ERR); } adjust_window (from, to); Curln = to; return (OK); } /* doread --- read "file" after "line" */ int doread (line, file, tflag) int line; char *file; int tflag; { register int count, len, i; int ret; int strlen (); FILE *fd; FILE *fopen (), *crypt_open (); char lin1[MAXLINE], lin2[MAXLINE]; char *fgets (); register LINEDESC *ptr; LINEDESC *sp_inject (); LINEDESC *getind (); char *expand_env (); file = expand_env (file); /* expand $HOME, etc. */ if (Savfil[0] == EOS) { strcpy (Savfil, file); mesg (Savfil, FILE_MSG); } if (Crypting) fd = crypt_open (file, "r"); else fd = fopen (file, "r"); if (fd == NULL) { ret = ERR; Errcode = ECANTREAD; } else { First_affected = min (First_affected, line + 1); ptr = getind (line); ret = OK; #ifndef OLD_SCRATCH Curln = line; #endif remark ("reading"); for (count = 0; fgets (lin1, MAXLINE, fd) != NULL; count++) { if (intrpt ()) { ret = ERR; break; } if (Compress == NO && tflag == NO) ptr = sp_inject (lin1, strlen (lin1), ptr); else { len = 0; for (i = 0; lin1[i] != EOS && len < MAXLINE - 1; i++) if (lin1[i] != '\t') lin2[len++] = lin1[i]; else do lin2[len++] = ' '; while (len % 8 != 0 && len < MAXLINE - 1); lin2[len] = EOS; if (len >= MAXLINE) { ret = ERR; Errcode = ETRUNC; } ptr = sp_inject (lin2, len, ptr); } if (ptr == NOMORE) { ret = ERR; break; } } if (Crypting) crypt_close (fd); else fclose (fd); saynum (count); Curln = line + count; svins (line, count); } return (ret); } /* dosopt --- set source language-related options */ int dosopt (lin) char lin[]; { char lang[8]; int i; int strbsr (); static struct { char *txt; int val; } ltxt[] = { "", 1, "as", 2, "c", 3, "d", 1, "data", 1, "f", 4, "h", 3, "n", 1, "nr", 1, "nroff",1, "p", 3, "r", 3, "s", 2, }; i = 0; getwrd (lin, &i, lang, 8); strmap (lang, 'a'); i = strbsr ((char *)ltxt, sizeof (ltxt), sizeof (ltxt[0]), lang); if (i == EOF) { Errcode = ENOLANG; return (ERR); } /* * these are all the same under Unix, so factor * them out of the switch. */ Rel_a = 'A'; Rel_z = 'Z'; Invert_case = NO; Compress = NO; switch (ltxt[i].val) { case 1: Warncol = 74; strcpy (Tabstr, "+4"); break; case 2: Warncol = 72; strcpy (Tabstr, "17+8"); Compress = YES; /* except this one */ break; case 3: Warncol = 74; strcpy (Tabstr, "+8"); break; case 4: Warncol = 72; strcpy (Tabstr, "7+3"); break; } settab (Tabstr); mesg (Invert_case == YES ? "CASE" : "", CASE_MSG); mesg (Compress == YES ? "XTABS" : "", COMPRESS_MSG); return (OK); } /* dotlit --- transliterate characters */ int dotlit (sub, allbut) char sub[]; int allbut; { char new[MAXLINE]; char kname; int collap, x, i, j, line, lastsub, status; int ret; LINEDESC *inx; LINEDESC *gettxt (), *getind (); ret = ERR; if (Line1 <= 0) { Errcode = EORANGE; return (ret); } if (First_affected > Line1) First_affected = Line1; lastsub = strlen (sub) - 1; if ((strlen (Tlpat) - 1) > lastsub || allbut == YES) collap = YES; else collap = NO; for (line = Line1; line <= Line2; line++) { if (intrpt ()) /* check for interrupts */ return (ERR); inx = gettxt (line); /* get text of line into txt, return index */ j = 0; for (i = 0; Txt[i] != EOS && Txt[i] != '\n'; i++) { x = xindex (Tlpat, Txt[i], allbut, lastsub); if (collap == YES && x >= lastsub && lastsub >= 0) /* collapse */ { new[j] = sub[lastsub]; j++; for (i++; Txt[i] != EOS && Txt[i] != '\n'; i++) { x = xindex (Tlpat, Txt[i], allbut, lastsub); if (x < lastsub) break; } } if (Txt[i] == EOS || Txt[i] == '\n') break; if (x >= 0 && lastsub >= 0) /* transliterate */ { new[j] = sub[x]; j++; } else if (x < 0) /* copy */ { new[j] = Txt[i]; j++; } /* else delete */ } if (Txt[i] == '\n') /* add a newline, if necessary */ { new[j] = '\n'; j++; } new[j] = EOS; /* add the EOS */ kname = inx -> Markname; /* save the markname */ delete (line, line, &status); ret = inject (new); if (ret == ERR) break; inx = getind (Curln); inx -> Markname = kname; /* set markname */ ret = OK; Buffer_changed = YES; } return (ret); } /* doundo --- restore last set of lines deleted */ int doundo (dflg, status) int dflg; int *status; { LINEDESC *l1, *l2, *k1, *k2; LINEDESC *getind (); int oldcnt; int nextln (), prevln (); *status = ERR; if (dflg == NO && Line1 <= 0) Errcode = EORANGE; else if (Limbo == NOMORE) Errcode = ENOLIMBO; else if (Line1 > Line2) Errcode = EBACKWARD; else if (Line2 > Lastln) Errcode = ELINE2; else { *status = OK; Curln = Line2; #ifdef OLD_SCRATCH k1 = getind (Line2); k2 = getind (nextln (Line2)); l1 = Limbo; l2 = l1 -> Prevline; relink (k1, l1, l2, k2); relink (l2, k2, k1, l1); #else blkmove (Limbo - Buf, MAXBUF - 1, Line2); #endif svins (Line2, Limcnt); oldcnt = Limcnt; Limcnt = 0; Limbo = NOMORE; Lastln += oldcnt; if (dflg == NO) delete (Line1, Line2, status); Curln += oldcnt; if (First_affected > Line1) First_affected = Line1; } return (*status); } /* dowrit --- write "from" through "to" into file */ int dowrit (from, to, file, aflag, fflag, tflag) int from, to, aflag, fflag, tflag; char *file; { FILE *fd; FILE *fopen (), *crypt_open (); register int line, ret, i, j; int strcmp (), access (); char tabs[MAXLINE]; register LINEDESC *k; LINEDESC *getind (); char *expand_env (); ret = ERR; if (from <= 0) Errcode = EORANGE; else { file = expand_env (file); /* expand $HOME, etc. */ if (aflag == YES) { if (Crypting) fd = crypt_open (file, "a"); else fd = fopen (file, "a"); } else if (strcmp (file, Savfil) == 0 || fflag == YES || Probation == WRITECOM || access (file, 0) == -1) { if (Crypting) fd = crypt_open (file, "w"); else fd = fopen (file, "w"); } else { Errcode = EFEXISTS; Probation = WRITECOM; return (ret); } if (fd == NULL) Errcode = ECANTWRITE; else { ret = OK; remark ("writing"); k = getind (from); for (line = from; line <= to; line++) { if (intrpt ()) return (ERR); gtxt (k); if (Compress == NO && tflag == NO) fputs (Txt, fd); else { for (i = 0; Txt[i] == ' '; i++) ; for (j = 0; j < i / 8; j++) tabs[j] = '\t'; tabs[j] = EOS; fputs (tabs, fd); fputs (&Txt[j * 8], fd); } k = NEXTLINE(k); } if (Crypting) crypt_close (fd); else fclose (fd); sync (); /* just in case the system crashes */ saynum (line - from); if (from == 1 && line - 1 == Lastln) Buffer_changed = NO; } } return (ret); } /* expand_env --- expand environment variables in file names */ char *expand_env (file) register char *file; { register int i, j, k; /* indices */ char *getenv (); char var[MAXLINE]; /* variable name */ char *val; /* value of environment variable */ static char buf[MAXLINE * 2]; /* expanded file name, static to not go away */ i = j = k = 0; while (file[i] != EOS) { if (file[i] == ESCAPE) { if (file[i+1] == '$') { buf[j++] = file[++i]; /* the actual $ */ i++; /* for next time around the loop */ } else buf[j++] = file[i++]; /* the \ */ } else if (file[i] != '$') /* normal char */ buf[j++] = file[i++]; else /* environment var */ { i++; /* skip $ */ k = 0; while (file[i] != '/' && file[i] != EOS) var[k++] = file[i++]; /* get var name */ var[k] = EOS; if ((val = getenv (var)) != NULL) for (k = 0; val[k] != EOS; k++) buf[j++] = val[k]; /* copy val into file name */ else if (file[i] == '/') i++; /* var not in enviroment; strip */ /* extra slash */ } } buf[j] = EOS; return (buf); } /* crypt_open -- run files through crypt */ FILE *crypt_open (file, mode) char *file, *mode; { char buf[MAXLINE]; FILE *fp, *popen (); if (! Crypting) return (NULL); while (Key[0] == EOS) { getkey (); if (Key[0] == EOS) fprintf (stderr, "The key must be non-empty!\r\n"); } switch (mode[0]) { case 'r': sprintf (buf, "crypt %s < %s", Key, file); fp = popen (buf, "r"); return (fp); /* caller checks for NULL or not */ break; case 'w': sprintf (buf, "crypt %s > %s", Key, file); fp = popen (buf, "w"); return (fp); /* caller checks for NULL or not */ break; case 'a': sprintf (buf, "crypt %s >> %s", Key, file); fp = popen (buf, "w"); return (fp); /* caller checks for NULL or not */ break; default: return (NULL); } } crypt_close (fp) FILE *fp; { pclose (fp); } /* getkey -- get an encryption key from the user */ #define repeat do #define until(cond) while(!(cond)) getkey () { char *getpass (); /* get input w/out echoing on screen */ clrscreen (); /* does NOT wipe out Screen_image */ tflush (); ttynormal (); repeat { strcpy (Key, getpass ("Enter encryption key: ")); if (strcmp (Key, getpass ("Again: ")) != 0) { Key[0] = EOS; fprintf (stderr, "didn't work. try again.\n"); } /* else all ok */ } until (Key[0] != EOS); ttyedit (); restore_screen (); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'docmd2.c'" '(18109 characters)' if test -f 'docmd2.c' then echo shar: will not over-write existing file "'docmd2.c'" else cat << \SHAR_EOF > 'docmd2.c' #ifndef lint static char RCSid[] = "$Header: docmd2.c,v 1.3 86/07/17 17:20:29 arnold Exp $"; #endif /* * $Log: docmd2.c,v $ * Revision 1.3 86/07/17 17:20:29 arnold * Some general code cleaning up. * * Revision 1.2 86/07/11 15:11:04 osadr * Removed Georgia Tech specific code. * * Revision 1.1 86/05/06 13:36:57 osadr * Initial revision * * */ /* ** docmd2.c ** ** routines to actually execute commands */ #include "se.h" #include "extern.h" /* append --- append lines after "line" */ append (line, str) int line; char str[]; { char lin[MAXLINE]; char term; int ret; int len, i, dpos, dotseen; int inject (); Curln = line; if (str[0] == ':') /* text to be added is in the command line */ ret = inject (&str[1]); else { Cmdrow = Toprow + (Curln - Topln) + 1; /* 1 below Curln */ lin[0] = EOS; if (Indent > 0 || line <= 0) len = max (0, Indent - 1); else /* do auto indent */ { LINEDESC *k, *gettxt (); k = gettxt (line); for (len = 0; Txt[len] == ' '; len++) ; } dpos = len; /* position for terminating '.' */ for (ret = NOSTATUS; ret == NOSTATUS; ) { if (! hwinsdel()) /* do it the old, slow way */ { if (Cmdrow > Botrow) { Cmdrow = Toprow + 1; cprow (Botrow, Toprow); adjust_window (Curln, Curln); if (First_affected > Topln) First_affected = Topln; } clrrow (Cmdrow); if (Cmdrow < Botrow) clrrow (Cmdrow + 1); } else /* try to be smart about it */ { if (Cmdrow > Botrow) { Cmdrow--; dellines (Toprow, 1); inslines (Cmdrow, 1); Topln++; } else { dellines (Botrow, 1); inslines (Cmdrow, 1); } } prompt ("apd>"); do getcmd (lin, Firstcol, &len, &term); while (term == CURSOR_UP || term == CURSOR_DOWN || term == CURSOR_SAME); dotseen = 0; if (lin[0] == '.' && lin[1] == '\n' && lin[2] == EOS) dotseen = 1; for (i = 0; i < dpos && lin[i] == ' '; i++) ; if (i == dpos && lin[dpos] == '.' && lin[dpos + 1] == '\n' && lin[dpos+2] == EOS) dotseen = 1; if (dotseen) { if (hwinsdel()) { dellines (Cmdrow, 1); inslines (Botrow, 1); } ret = OK; } else if (inject (lin) == ERR) ret = ERR; else /* inject occured */ prompt (""); /* erase prompt */ Cmdrow++; if (term != FUNNY) { if (Indent > 0) len = Indent - 1; else /* do auto indent */ for (len = 0; lin[len] == ' '; len++) ; dpos = len; lin[0] = EOS; } } Cmdrow = Botrow + 1; if (hwinsdel()) /* since we take control */ { /* of the screen, we're sure */ Sctop = Topln; /* it's still OK */ for (i = 0; i < Sclen; i++) Scline[i] = Sctop + i <= Lastln ? i : -1; } } if (Curln == 0 && Lastln > 0) /* for 0a or 1i followed by "." */ Curln = 1; if (First_affected > line) First_affected = line; tflush (); return (ret); } /* copy --- copy line1 through line2 after line3 */ int copy (line3) int line3; { register int i; int ret; register LINEDESC *ptr3, *after3, *k; LINEDESC *getind (); ret = ERR; #ifdef OLD_SCRATCH ptr3 = getind (line3); after3 = ptr3 -> Nextline; #endif if (Line1 <= 0) Errcode = EORANGE; else { ret = OK; Curln = line3; k = getind (Line1); for (i = Line1; i <= Line2; i++) { gtxt (k); if (inject (Txt) == ERR || intrpt ()) { ret = ERR; break; } #ifdef OLD_SCRATCH if (k == ptr3) /* make sure we don't copy stuff */ k = after3; /* that's already been copied */ else k = k -> Nextline; #else if (Line1 < line3) k++; else k += 2; /* * inject calls blkmove, which will shift the * lines down one in the array, so we add two * instead of one to get to the next line. */ #endif } First_affected = min (First_affected, line3 + 1); } return (ret); } /* delete --- delete lines from through to */ int delete (from, to, status) int from, to, *status; { int nextln (), prevln (); LINEDESC *k1, *k2, *j1, *j2, *l1; LINEDESC *getind (); if (from <= 0) /* can't delete line 0 */ { *status = ERR; Errcode = EORANGE; } else { if (First_affected > from) First_affected = from; #ifdef OLD_SCRATCH k1 = getind (prevln (from)); j1 = k1 -> Nextline; j2 = getind (to); k2 = j2 -> Nextline; relink (k1, k2, k1, k2); /* close chain around deletion */ #else blkmove (from, to, MAXBUF - 1); /* stick at end of buffer */ #endif Lastln -= to - from + 1; /* adjust number of last line */ Curln = prevln (from); #ifdef OLD_SCRATCH if (Limbo != NOMORE) /* discard lines in limbo */ { l1 = Limbo -> Prevline; Limbo -> Prevline = Free; Free = l1; } #endif Lost_lines += Limcnt; Limcnt = to - from + 1; /* number of lines "deleted" */ #ifdef OLD_SCRATCH Limbo = j1; /* put what we just deleted in limbo */ relink (j2, j1, j2, j1); /* close the ring */ #else /* point at first deleted */ Limbo = &Buf[MAXBUF - (to - from + 1)]; #endif *status = OK; svdel (from, to - from + 1); Buffer_changed = YES; } return (*status); } /* join --- join a group of lines into a single line */ int join (sub) char sub[]; { char new[MAXLINE]; register int l, line, sublen; int ret; int inject (), delete (), prevln (), strlen (); register LINEDESC *k; LINEDESC *getind (); ret = OK; if (Line1 <= 0) { Errcode = EORANGE; return (ERR); } sublen = strlen (sub) + 1; /* length of separator & EOS */ line = Line1; k = getind (line); gtxt (k); move_ (Txt, new, (int) k -> Lineleng); /* move in first chunk */ l = k -> Lineleng; for (line++; line <= Line2; line++) { if (intrpt ()) return (ERR); if (new[l - 2] == '\n') /* zap the NEWLINE */ l--; k = NEXTLINE(k); /* get the next line */ gtxt (k); if (l + sublen - 1 + k -> Lineleng - 1 > MAXLINE) /* won't fit */ { Errcode = E2LONG; return (ERR); } move_ (sub, &new[l - 1], sublen); /* insert separator string */ l += sublen - 1; move_ (Txt, &new[l - 1], (int) k -> Lineleng); /* move next line */ l += k -> Lineleng - 1; } Curln = Line2; /* all this will replace line1 through line2 */ ret = inject (new); /* inject the new line */ if (ret == OK) ret = delete (Line1, Line2, &ret); /* delete old lines */ Curln++; if (First_affected > Curln) First_affected = Curln; return (ret); } /* move --- move line1 through line2 after line3 */ int move (line3) int line3; { int nextln (), prevln (); LINEDESC *k0, *k1, *k2, *k3, *k4, *k5; LINEDESC *getind (); if (Line1 <= 0) { Errcode = EORANGE; return (ERR); } if (Line1 <= line3 && line3 <= Line2) { Errcode = EINSIDEOUT; return (ERR); } #ifdef OLD_SCRATCH k0 = getind (prevln (Line1)); k1 = k0 -> Nextline; k2 = getind (Line2); k3 = k2 -> Nextline; relink (k0, k3, k0, k3); #else blkmove (Line1, Line2, line3); #endif if (line3 > Line1) { Curln = line3; #ifdef OLD_SCRATCH line3 -= Line2 - Line1 + 1; #endif } else Curln = line3 + (Line2 - Line1 + 1); #ifdef OLD_SCRATCH k4 = getind (line3); k5 = k4 -> Nextline; relink (k4, k1, k2, k5); relink (k2, k5, k4, k1); #endif Buffer_changed = YES; First_affected = min (First_affected, min (Line1, line3)); return (OK); } /* overlay --- let user edit lines directly */ overlay (status) int *status; { char savtxt[MAXLINE], term, kname; static char empty[] = "\n"; int lng, vcol, lcurln, scurln; int inject (), nextln (), prevln (), strcmp (); LINEDESC *indx; LINEDESC *getind (), *gettxt (); *status = OK; if (Line1 == 0) { Curln = 0; *status = inject (empty); if (*status == ERR) return; First_affected = 1; Line1 = 1; Line2++; } for (lcurln = Line1; lcurln <= Line2; lcurln++) { Curln = lcurln; vcol = Overlay_col - 1; do { adjust_window (Curln, Curln); updscreen (); Cmdrow = Curln - Topln + Toprow; indx = gettxt (Curln); lng = indx -> Lineleng; if (Txt[lng - 2] == '\n') /* clobber newline */ lng--; if (vcol < 0) vcol = lng - 1; while (lng - 1 < vcol) { Txt[lng - 1] = ' '; lng++; } Txt[lng - 1] = '\n'; Txt[lng] = EOS; move_ (Txt, savtxt, lng + 1); /* make a copy of the line */ getcmd (Txt, Firstcol, &vcol, &term); if (term == FUNNY) { if (First_affected > Curln) First_affected = Curln; Cmdrow = Botrow + 1; return; } if (strcmp (Txt, savtxt) != 0) /* was line changed? */ { kname = indx -> Markname; delete (Curln, Curln, status); scurln = Curln; if (*status == OK) *status = inject (Txt); if (*status == ERR) { Cmdrow = Botrow + 1; return; } indx = getind (nextln (scurln)); indx -> Markname = kname; } else { /* in case end-of-line is moved */ if (First_affected > Curln) First_affected = Curln; } switch (term) { case CURSOR_UP: if (Curln > 1) Curln--; else Curln = Lastln; break; case CURSOR_DOWN: if (Curln < Lastln) Curln++; else Curln = min (1, Lastln); break; case CURSOR_SAME: vcol = 0; break; } } while (term == CURSOR_UP || term == CURSOR_DOWN || term == CURSOR_SAME); } Cmdrow = Botrow + 1; return; } /* subst --- substitute "sub" for occurrences of pattern */ int subst (sub, gflag, glob) char sub[]; int gflag, glob; { char new[MAXLINE], kname; register int line, m, k, lastm; int j, junk, status, subbed, ret; int tagbeg[10], tagend[10]; int amatch (), addset (), inject (); register LINEDESC *inx; LINEDESC *gettxt (), *getind (); if (Globals && glob) ret = OK; else ret = ERR; if (Line1 <= 0) { Errcode = EORANGE; return (ERR); } /* the following code has been removed for your protection index() occasionally grabs newlines out of the character class counter in a pattern. for example [0-9] doesn't work due to this if (index (Pat, '\n') != -1) # never delete NEWLINE { Errcode = EBADPAT; return (ERR); } */ for (line = Line1; line <= Line2; line++) { if (intrpt ()) break; j = 0; subbed = NO; inx = gettxt (line); lastm = -1; for (k = 0; Txt[k] != EOS; ) { for (m = 1; m <= 9; m++) { tagbeg[m] = -1; tagend[m] = -1; } if (gflag == YES || subbed == NO) m = amatch (Txt, k, Pat, &tagbeg[1], &tagend[1]); else m = -1; if (m > -1 && lastm != m) /* replace matched text */ { subbed = YES; tagbeg[0] = k; tagend[0] = m; catsub (Txt, tagbeg, tagend, sub, new, &j, MAXLINE); lastm = m; } if (m == -1 || m == k) /* no match or null match */ { junk = addset (Txt[k], new, &j, MAXLINE); k++; } else k = m; /* skip matched text */ } if (subbed == YES) { if (addset (EOS, new, &j, MAXLINE) == NO) { ret = ERR; Errcode = E2LONG; break; } kname = inx -> Markname; delete (line, line, &status); /* remembers dot */ ret = inject (new); if (First_affected > Curln) First_affected = Curln; if (ret == ERR) break; inx = getind (Curln); inx -> Markname = kname; ret = OK; Buffer_changed = YES; } else /* subbed == NO */ Errcode = ENOMATCH; } return (ret); } /* uniquely_name --- mark-name line; make sure no other line has same name */ uniquely_name (kname, status) char kname; int *status; { register int line; register LINEDESC *k; defalt (Curln, Curln); if (Line1 <= 0) { *status = ERR; Errcode = EORANGE; return; } *status = OK; line = 0; k = Line0; do { line++; k = NEXTLINE(k); if (line == Line2) k -> Markname = kname; else if (k -> Markname == kname) k -> Markname = DEFAULTNAME; } while (line < Lastln); return; } /* draw_box --- draw or erase a box at coordinates in command line */ int draw_box (lin, i) char lin[]; int *i; { register int left, right, col, len; int junk; int ctoi (), strcmp (), inject (), delete (); register LINEDESC *k; LINEDESC *getind (), *gettxt (); char text[MAXLINE]; char kname, ch; left = ctoi (lin, i); if (left <= 0 || left > MAXLINE) { Errcode = EBADCOL; return (ERR); } if (lin[*i] == ',') { (*i)++; SKIPBL (lin, *i); right = ctoi (lin, i); if (right <= 0 || right >= MAXLINE || left > right) { Errcode = EBADCOL; return (ERR); } } else right = left; SKIPBL (lin, *i); if (lin[*i] == '\n') ch = ' '; else ch = lin[(*i)++]; if (lin[*i] != '\n') { Errcode = EEGARB; return (ERR); } if (Line1 <= 0) { Errcode = EORANGE; return (ERR); } for (Curln = Line1; Curln <= Line2; Curln++) { k = gettxt (Curln); len = k -> Lineleng; move_ (Txt, text, len); if (text[len - 2] == '\n') col = len - 1; else col = len; while (col <= right) { text[col - 1] = ' '; col++; } text[col - 1] = '\n'; text[col] = EOS; if (Curln == Line1 || Curln == Line2) for (col = left; col <= right; col++) text[col - 1] = ch; else { text[left - 1] = ch; text[right - 1] = ch; } if (strcmp (text, Txt) != 0) { kname = k -> Markname; if (delete (Curln, Curln, &junk) == ERR || inject (text) == ERR) return (ERR); k = getind (Curln); k -> Markname = kname; Buffer_changed = YES; } } Curln = Line1; /* move to top of box */ if (First_affected > Curln) First_affected = Curln; adjust_window (Curln, Curln); updscreen (); return (OK); } /* dfltsopt --- set the 's' option to the extension on the file name */ dfltsopt (name) char name[]; { int i; int strlen (), dosopt (); for (i = strlen (name) - 1; i >= 0; i--) if (name[i] == '.') { dosopt (&name[i + 1]); break; } if (i < 0) dosopt (""); } /* doshell --- escape to the Shell to run one or more Unix commands */ /* ** emulate vi: if running just a shell, redraw the screen as ** soon as the shell exits. if running a program, let the user ** redraw the screen when he/she is ready. ** ** also emulate USG Unix 5.0 ed: a ! as the first character is ** replaced by the previous shell command; an unescaped % is replaced ** by the saved file name. The expanded command is echoed. */ #ifdef BSD #define DEFAULT_PATH "/bin/csh" #define DEF_SHELL "csh" #else #define DEFAULT_PATH "/bin/sh" #define DEF_SHELL "sh" #endif int doshell (lin, pi) char lin[]; int *pi; { int forkstatus, childstatus; int (*save_quit)(), (*save_int)(); int int_hdlr (); int (*signal())(); int i, auto_redraw; char *path, *name, *p, *getenv (); char new_command[MAXLINE]; int j, k; static char sav_com[MAXLINE] = ""; int expanded = NO; if (Nlines == 0) /* use normal 'ed' behavior */ { tflush (); /* flush out the terminal output */ position_cursor (Nrows - 1, 0); /* bottom left corner */ if ((p = getenv ("SHELL")) == NULL || strcmp (p, DEFAULT_PATH) == 0) { path = DEFAULT_PATH; name = DEF_SHELL; /* default */ } #ifdef BSD /* on Berkeley systems, check the other shell */ else if (strcmp (p, "/bin/sh") == 0) { path = "/bin/sh"; name = "sh"; } #endif else { if (p[0] == '/') /* full pathname there */ { /* work backwards to find just name */ path = p; i = strlen (p); while (p[i] != '/') i--; i++; /* skip '/' */ name = &p[i]; } else { char buf[MAXLINE]; sprintf (buf, "unknown shell, using %s", DEF_SHELL); remark (buf); path = DEFAULT_PATH; name = DEF_SHELL; } } auto_redraw = (lin[*pi] == '\n') ? YES : NO; /* build command, checking for leading !, and % anywhere */ if (lin[*pi] == '!') { if (sav_com[0] != EOS) { for (j = 0; sav_com[j] != EOS; j++) new_command[j] = sav_com[j]; if (new_command[j-1] == '\n') j--; (*pi)++; expanded = YES; } else { Errcode = ENOCMD; return (ERR); } } else j = 0; for (i = *pi; lin[i] != EOS; i++) { if (lin[i] == ESCAPE) { if (lin[i+1] != '%') { new_command[j++] = ESCAPE; new_command[j++] = lin[++i]; } else new_command[j++] = lin[++i]; } else if (lin[i] == '%') { for (k = 0; Savfil[k] != EOS; k++) new_command[j++] = Savfil[k]; expanded = YES; } else new_command[j++] = lin[i]; } if (new_command[j-1] == '\n') j--; new_command[j] = EOS; strcpy (sav_com, new_command); /* save it */ ttynormal (); #ifndef HARD_TERMS t_exit (); #endif write (1, "\n\n", 2); /* clear out a line */ forkstatus = fork(); if (forkstatus == -1) /* the fork failed */ { ttyedit (); #ifndef HARD_TERMS t_init (); #endif Errcode = ECANTFORK; return ERR; } if (forkstatus == 0) /* we're in the child process */ { signal (SIGINT, SIG_DFL); signal (SIGQUIT, SIG_DFL); #ifdef BSD if (strcmp (name, "sh") != 0) /* not /bin/sh */ signal (SIGTSTP, SIG_DFL); else signal (SIGTSTP, SIG_IGN); #endif if (auto_redraw) /* no params; run a shell */ { execl (path, name, 0); _exit (RETERR); /* exec failed, notify parent */ } else { if (expanded) /* echo it */ printf ("%s\n", new_command); execl (path, name, "-c", new_command, 0); _exit (RETERR); } } /* we're in the parent process here */ save_int = signal (SIGINT, SIG_IGN); /* ignore interrupts */ save_quit = signal (SIGQUIT, SIG_IGN); while (wait (&childstatus) != forkstatus) ; save_int = signal (SIGINT, save_int); /* catch interupts */ save_quit = signal (SIGQUIT, save_quit); write (1, "\n\n", 2); /* clear out some message space */ Currow = Nrows - 1; Curcol = 0; if ((childstatus >> 8) != 0) { ttyedit (); #ifndef HARD_TERMS t_init (); #endif Errcode = ENOSHELL; return ERR; } /* a la vi: */ if (! auto_redraw) { int c; printf ("type return to continue: "); while ((c = getchar()) != '\n' && c != EOF) ; } ttyedit (); #ifndef HARD_TERMS t_init (); #endif restore_screen (); return OK; } else remark ("Not implemented yet"); return OK; } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0