home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume4 / se / part2 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  14.5 KB  |  661 lines

  1. /*
  2. ** main.c
  3. **
  4. ** main program and lots of other routines
  5. ** for the se screen editor.
  6. */
  7.  
  8. #include "se.h"
  9.  
  10. /* declare global variables */
  11.  
  12. /* Concerning line numbers: */
  13. int Line1;        /* first line number on command */
  14. int Line2;        /* second line number on command */
  15. int Nlines;        /* number of line numbers specified */
  16. int Curln;        /* current line; value of dot */
  17. int Lastln;        /* last line; value of dollar */
  18.  
  19.  
  20. /* Concerning patterns: */
  21. char Pat[MAXPAT] = "";    /* saved pattern */
  22.  
  23.  
  24. /* Concerning the text of lines: */
  25. char Txt[MAXLINE];    /* text of current line */
  26.  
  27.  
  28. /* Concerning file names: */
  29. char Savfil[MAXLINE] = "";    /* remembered file name */
  30.  
  31.  
  32. /* Concerning line descriptors: */
  33. LINEDESC Buf[MAXBUF];
  34. #ifdef OLD_SCRATCH
  35. LINEDESC *Lastbf;    /* last pointer used in Buf */
  36. LINEDESC *Free;        /* head of free list */
  37. #endif
  38. LINEDESC *Line0;    /* head of list of line descriptors */
  39.  
  40.  
  41. /* Concerning the 'undo' command: */
  42. LINEDESC *Limbo;    /* head of limbo list for undo */
  43. int Limcnt;        /* number of lines in limbo list */
  44.  
  45.  
  46. /* Concerning the scratch file: */
  47. filedes Scr;        /* scratch file descriptor */
  48. unsigned Scrend;    /* end of info on scratch file */
  49. char Scrname[MAXLINE];    /* name of scratch file */
  50. int Lost_lines;        /* number of garbage lines in scratch file */
  51.  
  52.  
  53. /* Concerning miscellaneous variables */
  54. int Buffer_changed = NO;/* YES if buffer changed since last write */
  55. int Errcode = ENOERR;    /* cause of most recent error */
  56. int Saverrcode = ENOERR;/* cause of previous error */
  57. int Probation = NO;    /* YES if unsaved buffer can be destroyed */
  58. int Argno;        /* command line argument pointer */
  59. char Last_char_scanned = 0;    /* last char scanned w/ctl-[sl], init illegal  */
  60. #ifdef HARD_TERMS
  61. int Tspeed;        /* terminal speed in characters/second */
  62. #endif
  63. char Peekc = EOS;    /* push a SKIP_RIGHT if adding delimiters */
  64. #ifdef BSD4_2
  65. int Reading = NO;    /* are we doing terminal input? */
  66. #endif
  67.  
  68.  
  69. /* Concerning options: */
  70. int Tabstops[MAXLINE];    /* array of tab stops */
  71. char Unprintable = ' ';    /* char to print for unprintable chars */
  72. int Absnos = NO;    /* use absolute numbers in margin */
  73. int Nchoise = EOS;    /* choice of line number for cont. display */
  74. int Overlay_col = 0;    /* initial cursor column for 'v' command */
  75. int Warncol;        /* where to turn on column warning, set in dosopt() */
  76. int Firstcol = 0;    /* leftmost column to display */
  77. int Indent = 1;        /* indent col; 0=same as previous line */
  78. int Notify = YES;    /* notify user if he has mail in mail file */
  79. int Globals = NO;    /* substitutes in a global don't fail */
  80. int No_hardware;    /* never use hardware insert/delete */
  81.  
  82.  
  83. #ifdef HARD_TERMS
  84. /* Concerning the terminal type */
  85. int Term_type;        /* terminal type */
  86. #endif
  87.  
  88.  
  89. /* Concerning the screen format: */
  90. char Screen_image[MAXROWS][MAXCOLS];
  91. char Msgalloc[MAXCOLS];    /* column allocation of status line */
  92. int Nrows;        /* number of rows on screen */
  93. int Ncols;        /* number of columns on screen */
  94. int Currow;        /* vertical cursor coordinate */
  95. int Curcol;        /* horizontal cursor coordinate */
  96. int Toprow;        /* top row of window field on screen */
  97. int Botrow;        /* bottom row of window field on screen */
  98. int Cmdrow;        /* row number of command line */
  99. int Topln;        /* line number of first line on screen */
  100. int Insert_mode;    /* flag to specify character insertion */
  101. int Invert_case;    /* flag to specify case mapping on input */
  102. int First_affected;    /* number of first line affected by cmd */
  103. int Rel_a;        /* char to use for first alpha line number */
  104. int Rel_z;        /* char to use for last alpha line number */
  105. int Scline[MAXROWS];    /* lines currently on screen (rel to Sctop) */
  106. int Sctop;        /* first line currently on screen */
  107. int Sclen;        /* number of lines currently on screen */
  108. char Blanks[MAXCOLS];    /* all blanks for filling in lines on screen */
  109. char Tobuf[MAXTOBUF];    /* buffer for collecting terminal output */
  110. char *Tobp = Tobuf - 1;    /* pointer to last used part of Tobuf */
  111.  
  112.  
  113. /* Concerning interrupts: */
  114. int Int_caught = 0;    /* caught a SIGINT from user */
  115. int Hup_caught = 0;    /* caught a SIGHUP when phone line dropped */
  116. #ifdef BSD
  117. int Catching_stops;    /* catching or ignoring SIGTSTP's? */
  118. #endif
  119.  
  120. /* Concerning Unix and SWT compatiblity: */
  121. int Unix_mode = YES;    /* behaving like Unix editors? */
  122. char BACKSCAN = '?';    /* back scan character */
  123. char NOTINCCL = '^';    /* class negation character */
  124. char XMARK = '~';    /* global exclude on mark name */
  125. char ESCAPE = '\\';    /* escape character */
  126.  
  127. /* Concering Georgia Tech specific code: */
  128. int At_gtics = NO;    /* are we running at Georgia Tech ICS? */
  129.  
  130. /* Concerning file encryption: */
  131. int Crypting = NO;    /* doing file encryption? */
  132. char Key[KEYSIZE] = "";    /* saved encryption key */
  133.  
  134.  
  135. /* main --- main program for screen editor */
  136.  
  137. main (argc, argv)
  138. int argc;
  139. char *argv[];
  140. {
  141.     char *basename ();
  142.     int int_hdlr (), hup_hdlr ();
  143.     int (*old_int)(), (*old_quit)();
  144. #ifdef BSD
  145.     int stop_hdlr (), (*old_stop)();
  146. #endif
  147.     /* catch quit and hangup signals */
  148.     /*
  149.      * In the terminal driver munging routines, we set Control-P
  150.      * to generate an interrupt, and turn off generating Quits from
  151.      * the terminal.  Now we just ignore them if sent from elsewhere.
  152.      */
  153.  
  154.     signal (SIGHUP, hup_hdlr);
  155.  
  156.     old_int = signal (SIGINT, int_hdlr);
  157.     old_quit = signal (SIGQUIT, SIG_IGN);
  158.  
  159. #ifdef notdef
  160. /*
  161.  * This is commented out so that se can be run from the news
  162.  * software.  Commenting it out will also allow you to put it
  163.  * in the background, which could give you trouble. So beware.
  164.  */
  165.  
  166.     if (old_int == SIG_IGN || old_quit == SIG_IGN)
  167.     {
  168.         /* fired off into the background, refuse to run */
  169.         if (isatty (fileno (stdin)))
  170.         {
  171.             fprintf (stderr, "%s: I refuse to run in the background.\n",
  172.                 basename (argv[0]));
  173.             exit (2);
  174.         }
  175.         /* else
  176.             assume input is a script */
  177.     }
  178. #endif
  179.  
  180. #ifdef BSD
  181.     old_stop = signal (SIGTSTP, stop_hdlr);
  182.  
  183.     if (old_stop == SIG_IGN)    /* running bourne shell */
  184.     {
  185.         signal (SIGTSTP, SIG_IGN);    /* restore it */
  186.         Catching_stops = NO;
  187.     }
  188.     else
  189.         Catching_stops = YES;
  190.         /* running C-shell or BRL sh, catch Control-Z's */
  191. #endif
  192.  
  193.     /* set terminal to no echo, no output processing, break enabled */
  194.     ttyedit ();
  195.  
  196. #ifdef HARD_TERMS
  197.     Tspeed = getspeed (1);        /* speed of stdout */
  198. #endif
  199.  
  200.     initialize (argc, argv);
  201.  
  202.     edit (argc, argv);
  203.  
  204. #ifndef HARD_TERMS
  205.     t_exit ();
  206. #endif
  207.  
  208.     /* reset the terminal mode */
  209.     ttynormal ();
  210. }
  211.  
  212.  
  213. #ifdef HARD_TERMS
  214. /* decode_mnemonic --- decode a terminal type mnemonic */
  215.  
  216. int decode_mnemonic (str)
  217. char str[];
  218. {
  219.     int i;
  220.     int strbsr ();
  221.  
  222.     static struct {
  223.         char *s;
  224.         int t;
  225.     } stab[] = {
  226.         "950",          TVI950,
  227.         "adm31",        ADM31,  
  228.         "adm3a",        ADM3A,  
  229.         "anp",          ANP,    
  230.         "b150",         BEE150,   
  231.         "b200",         BEE200,   
  232.         "cg",           CG,     
  233.         "consul",       ADDS980,
  234.         "esprit",       ESPRIT,
  235.         "fox",          FOX,    
  236.         "gt40",         GT40,   
  237.         "h19",          H19,    
  238.         "haz",          HAZ1510,
  239.         "hp21",         HP21,   
  240.         "hz1510",       HAZ1510,
  241.         "ibm",          IBM,    
  242.         "isc",          ISC8001,
  243.         "netron",       NETRON, 
  244.         "regent",       ADDS100,
  245.         "regent40",     ADDS100,    /* kludge */
  246.         "sbee",         SBEE,   
  247.         "sol",          SOL,    
  248.         "trs80",        TRS80,  
  249.         "ts1",          TS1,
  250.         "tvt",          TVT,    
  251.         "vc4404",       VC4404,
  252.         "vi200",        VI200,
  253.         "vi300",    VI300,
  254.         "vi50",         VI50,
  255.     };
  256.  
  257.     i = strbsr ((char *)stab, sizeof (stab), sizeof (stab[0]), str);
  258.     if (i == EOF)
  259.         return (ERR);
  260.     else
  261.         return (stab[i].t);
  262. }
  263. #endif
  264.  
  265.  
  266.  
  267. /* error --- print error message and die semi-gracefully */
  268.  
  269. error (msg)
  270. char *msg;
  271. {
  272.     /*
  273.      * You might think we want to try and save the buffer,
  274.      * BUT, fatal errors can be caused by buffer problems,
  275.      * which would end up putting us into a non-ending recursion.
  276.      */
  277.  
  278.     ttynormal ();
  279.     fprintf (stderr, "%s\n", msg);
  280.     signal (SIGQUIT, SIG_DFL);    /* restore normal quit handling */
  281.     kill (getpid(), SIGQUIT);    /* dump memory */
  282. }
  283.  
  284.  
  285. /* get_term_type --- force user to divulge terminal type */
  286.  
  287. #ifndef HARD_TERMS
  288. get_term_type ()
  289. {
  290.     int setcaps ();
  291. #else
  292. get_term_type (term_type)
  293. int *term_type;
  294. {
  295.     int decode_mnemonic ();
  296. #endif
  297.  
  298.     char *p;
  299.     char *getenv ();
  300.  
  301.     if ((p = getenv ("TERM")) == NULL)
  302.     {
  303.         ttynormal ();
  304.         fprintf (stderr, "You must set your terminal type with 'TERM=<type>'\n");
  305.         exit (1);
  306.     }
  307.  
  308. #ifdef HARD_TERMS
  309.     if ((*term_type =  decode_mnemonic()) == ERR)
  310. #else
  311.     if (setcaps (p) == ERR)
  312. #endif
  313.     {
  314.         ttynormal ();
  315.         fprintf (stderr, "I'm sorry, but I can't support %s terminals.\n", p);
  316.         exit (1);
  317.     }
  318. }
  319.  
  320.  
  321. /* initialize --- set up global data areas, get terminal type */
  322.  
  323. initialize (argc, argv)
  324. int argc;
  325. char *argv[];
  326. {
  327.     int i, dosopt ();
  328.  
  329. #ifdef HARD_TERMS
  330.     int strcmp ();
  331.     int decode_mnemonic ();
  332.     char lin[MAXLINE];
  333.  
  334.     /* Determine what type of terminal we're on */
  335.     Argno = 1;
  336.     strcpy (lin, &argv[Argno][0]);
  337.     if (Argno < argc && lin[0] == '-' && lin[2] == EOS
  338.         && (lin[1] == 't' || lin[1] == 'T'))
  339.     {
  340.         Argno = 2;
  341.         if (Argno < argc)
  342.         {
  343.             strcpy (lin, argv[Argno]);
  344.             strmap (lin, 'l');
  345.             Term_type = decode_mnemonic (lin);
  346.             if (Term_type == ERR)
  347.                 usage ();
  348.             else
  349.                 Argno++;
  350.         }
  351.         else
  352.             usage ();
  353.     }
  354.     else
  355.         get_term_type (&Term_type);
  356. #else
  357.     Argno = 1;
  358.     get_term_type ();
  359. #endif
  360.  
  361.     /* Initialize the scratch file: */
  362.     mkbuf ();
  363.  
  364.     /* Initialize screen format parameters: */
  365.     setscreen ();
  366.  
  367.     /* Initialize the array of blanks to blanks */
  368.     for (i = 0; i < Ncols; i++)
  369.         Blanks[i] = ' ';
  370.     Blanks[i] = '\0';
  371.  
  372.     if (dosopt ("") == ERR)
  373.         error ("in initialize: can't happen");
  374.  
  375.     return;
  376. }
  377.  
  378.  
  379.  
  380.  
  381. /* intrpt --- see if there has been an interrupt or hangup */
  382.  
  383. int intrpt ()
  384. {
  385.     if (Int_caught)
  386.     {
  387.         Errcode = EBREAK;
  388.         Int_caught = 0;
  389.         return (1);
  390.     }
  391.     else if (Hup_caught)
  392.     {
  393.         Errcode = EHANGUP;
  394.         Hup_caught = 0;
  395.         return 1;
  396.     }
  397.     return (0);
  398. }
  399.  
  400.  
  401. /* int_hdlr --- handle an interrupt signal */
  402.  
  403. int_hdlr ()
  404. {
  405. #ifndef BSD4_2
  406.     signal (SIGINT, int_hdlr);
  407. #endif
  408.     Int_caught = 1;
  409. }
  410.  
  411. /* hup_hdlr --- handle a hangup signal */
  412.  
  413. hup_hdlr ()
  414. {
  415. #ifndef BSD4_2
  416.     signal (SIGHUP, hup_hdlr);
  417.     Hup_caught = 1;
  418. #else
  419.     /* do things different cause of 4.2 (sigh) */
  420.     Hup_caught = 1;
  421.     if (Reading)    /* doing tty i/o, and that is where hup came from */
  422.         hangup ();
  423. #endif
  424. }
  425.  
  426. #ifdef BSD
  427. /* stop_hdlr --- handle the berkeley stop/suspend signal */
  428.  
  429. int stop_hdlr ()
  430. {
  431.     clrscreen ();
  432.     tflush ();
  433.     ttynormal ();
  434. #ifdef BSD4_2
  435.     /* this handler remains in effect, use uncatchable signal */
  436.     kill (getpid(), SIGSTOP);
  437. #else
  438.     /* action was reset to default when we caught it */
  439.     kill (getpid(), SIGTSTP);
  440. #endif
  441.     /*
  442.      * user does a "fg"
  443.      */
  444. #ifndef BSD4_2
  445.     signal (SIGTSTP, stop_hdlr);    /* reset stop catching */
  446. #endif
  447.     ttyedit ();
  448.     restore_screen ();
  449. }
  450. #endif
  451.  
  452.  
  453. /* hangup --- dump contents of edit buffer if SIGHUP occurs */
  454.  
  455. hangup ()
  456. {
  457.     /* close terminal to avoid hanging on any accidental I/O: */
  458.     close (0);
  459.     close (1);
  460.     close (2);
  461.  
  462.     signal (SIGHUP, SIG_IGN);
  463.     signal (SIGINT, SIG_IGN);
  464.     signal (SIGQUIT, SIG_IGN);
  465.     Hup_caught = 0;
  466.     Crypting = NO;        /* force buffer to be clear text */
  467.     dowrit (1, Lastln, "se.hangup", NO, YES, NO);
  468.     clrbuf ();
  469.     exit (1);
  470. }
  471.  
  472.  
  473. /* mswait --- message waiting subroutine */
  474.  
  475. /* if the user wants to be notified, and the mail file is readable, */
  476. /* and there is something in it, then he is given the message. */
  477. /* the om command toggles Notify, controlling notification. */
  478.  
  479. #include <sys/types.h>
  480. #include <sys/stat.h>
  481.  
  482. mswait ()
  483. {
  484.     int access ();
  485.     char *getenv ();
  486.     struct stat buf;
  487.     static char *mbox = NULL;
  488.     static int first = YES;
  489.     static unsigned long mtime = 0L;
  490.  
  491.     if (! Notify)
  492.         return;
  493.  
  494.     if (first) 
  495.     {
  496.         first = NO;
  497.         if ((mbox = getenv ("MAIL")) != NULL && access (mbox, 4) == 0)
  498.         {
  499.             if (stat (mbox, &buf) >= 0)
  500.             {
  501.                 mtime = buf.st_mtime;
  502.                 if (buf.st_size > 0)
  503.                     remark ("You have mail");
  504.             }
  505.         }
  506.     }
  507.     else if (mbox && stat (mbox, &buf) >= 0 && buf.st_mtime > mtime)
  508.     {
  509.         mtime = buf.st_mtime;
  510.         remark ("You have new mail");
  511.         twrite (1, "\007", 1);    /* Bell */
  512.     }
  513. }
  514.  
  515.  
  516. /* printverboseerrormessage --- print verbose error message */
  517.  
  518. printverboseerrormessage ()
  519. {
  520.     switch (Errcode) {
  521.     case EBACKWARD:
  522.         remark ("Line numbers in backward order"); 
  523.         break;
  524.     case ENOPAT:
  525.         remark ("No saved pattern -- sorry"); 
  526.         break;
  527.     case EBADPAT:
  528.         remark ("Bad syntax in pattern"); 
  529.         break;
  530.     case EBADSTR:
  531.         remark ("Bad syntax in string parameter"); 
  532.         break;
  533.     case EBADSUB:
  534.         remark ("Bad syntax in substitution string"); 
  535.         break;
  536.     case ECANTREAD:
  537.         remark ("File is not readable"); 
  538.         break;
  539.     case EEGARB:
  540.         remark ("Garbage after your command"); 
  541.         break;
  542.     case EFILEN:
  543.         remark ("Bad syntax in file name"); 
  544.         break;
  545.     case EBADTABS:
  546.         remark ("Bad tabstop syntax"); 
  547.         break;
  548.     case EINSIDEOUT:
  549.         remark ("Can't move a group into itself"); 
  550.         break;
  551.     case EKNOTFND:
  552.         remark ("No line has that mark name"); 
  553.         break;
  554.     case ELINE1:
  555.         remark (""); 
  556.         break;
  557.     case E2LONG:
  558.         remark ("Resultant line too long to handle"); 
  559.         break;
  560.     case ENOERR:
  561.         remark ("No error to report"); 
  562.         break;
  563.     case ENOLIMBO:
  564.         remark ("No lines in limbo"); 
  565.         break;
  566.     case EODLSSGTR:
  567.         remark ("Expected '<', '>', or nothing after 'od'"); 
  568.         break;
  569.     case EORANGE:
  570.         remark ("Line number out of range"); 
  571.         break;
  572.     case EOWHAT:
  573.         remark ("Can't recognize option"); 
  574.         break;
  575.     case EPNOTFND:
  576.         remark ("No line contains that pattern"); 
  577.         break;
  578.     case ESTUPID:
  579.         remark ("Buffer hasn't been saved"); 
  580.         break;
  581.     case EWHATZAT:
  582.         remark ("No command recognized"); 
  583.         break;
  584.     case EBREAK:
  585.         remark ("You interrupted me"); 
  586.         break;
  587.     case ELINE2:
  588.         remark ("Last line number beyond end of file"); 
  589.         break;
  590.     case ECANTWRITE:
  591.         remark ("File is not writeable"); 
  592.         break;
  593.     case ECANTINJECT:
  594.         remark ("No room for any more lines!"); 
  595.         break;
  596.     case ENOMATCH:
  597.         remark ("No match for pattern"); 
  598.         break;
  599.     case ENOFN:
  600.         remark ("No saved filename"); 
  601.         break;
  602.     case EBADLIST:
  603.         remark ("Bad syntax in character list"); 
  604.         break;
  605.     case ENOLIST:
  606.         remark ("No saved character list -- sorry"); 
  607.         break;
  608.     case ENONSENSE:
  609.         remark ("Unreasonable value"); 
  610.         break;
  611.     case ENOHELP:
  612.         remark ("No help available"); 
  613.         break;
  614.     case EBADLNR:
  615.         remark ("Line numbers not allowed"); 
  616.         break;
  617.     case EFEXISTS:
  618.         remark ("File already exists"); 
  619.         break;
  620.     case EBADCOL:
  621.         remark ("Improper column number specification"); 
  622.         break;
  623.     case ENOLANG:
  624.         remark ("Unknown source language"); 
  625.         break;
  626.     case ETRUNC:
  627.         remark ("Lines were truncated"); 
  628.         break;
  629.     case ENOSHELL:
  630.         remark ("Type control-q to rebuild screen"); 
  631.         break;
  632.     case ECANTFORK:
  633.         remark ("Can't fork --- get help!"); 
  634.         break;
  635.     case ENOSUB:
  636.         remark ("No saved replacement --- sorry"); 
  637.         break;
  638.     case ENOCMD:
  639.         remark ("No saved shell command --- sorry");
  640.         break;
  641.     default:
  642.         remark ("?"); 
  643.         break;
  644.     }
  645.     Errcode = ENOERR;
  646. }
  647.  
  648.  
  649. /* usage --- print usage diagnostic and die */
  650.  
  651. usage ()
  652. {
  653.     ttynormal ();
  654. #ifdef HARD_TERMS
  655.     fprintf (stderr, "Usage: se [-t <terminal>] { <pathname | -<opt> }\n");
  656. #else
  657.     fprintf (stderr, "Usage: se { <pathname> | -<option> }\n");
  658. #endif
  659.     exit (1);
  660. }
  661.