home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / se / part02 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-01-25  |  12.9 KB  |  568 lines

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