home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / mg2a / part09 < prev    next >
Text File  |  1989-02-03  |  58KB  |  2,443 lines

  1. Path: xanth!mcnc!ncsuvx!gatech!bloom-beacon!husc6!necntc!ncoast!allbery
  2. From: BLARSON@ECLA.USC.EDU (Bob Larson)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i033: mg 2a part 9 of 15
  5. Message-ID: <12401300795.47.BLARSON@ECLA.USC.EDU>
  6. Date: 26 May 88 04:59:51 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: BLARSON@ECLA.USC.EDU (Bob Larson)
  9. Lines: 2431
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. comp.sources.misc: Volume 3, Issue 33
  13. Submitted-By: "Bob Larson" <BLARSON@ECLA.USC.EDU>
  14. Archive-Name: mg2a/Part9
  15.  
  16. #    This is a shell archive.
  17. #    Remove everything above and including the cut line.
  18. #    Then run the rest of the file through sh.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar:    Shell Archiver
  22. #    Run the following text with /bin/sh to create:
  23. #    match.c
  24. #    dir.c
  25. #    re_search.c
  26. #    sys/bsd/README
  27. #    sys/bsd/Makefile
  28. #    sys/bsd/spawn.c
  29. #    sys/bsd/sysdef.h
  30. #    sys/bsd/ttyio.c
  31. #    sys/sysv/Makefile
  32. #    sys/sysv/fileio.c
  33. #    sys/sysv/spawn.c
  34. #    sys/sysv/sysdef.h
  35. #    sys/sysv/ttyio.c
  36. # This archive created: Thu May 19 00:10:20 1988
  37. # By:    blarson
  38. if test -d sys
  39. then true
  40. else mkdir sys
  41. fi
  42. if test -d sys/bsd
  43. then true
  44. else mkdir sys/bsd
  45. fi
  46. if test -d sys/sysv
  47. then true
  48. else mkdir sys/sysv
  49. fi
  50. cat << \SHAR_EOF > match.c
  51. /*
  52.  * Name:    MicroEMACS
  53.  *        Limited parenthesis matching routines
  54.  *
  55.  * The hacks in this file implement automatic matching
  56.  * of (), [], {}, and other characters.     It would be
  57.  * better to have a full-blown syntax table, but there's
  58.  * enough overhead in the editor as it is.
  59.  *
  60.  * Since I often edit Scribe code, I've made it possible to
  61.  * blink arbitrary characters -- just bind delimiter characters
  62.  * to "blink-matching-paren-hack"
  63.  */
  64. #include    "def.h"
  65. #include    "key.h"
  66.  
  67. static int    balance();
  68. static VOID    displaymatch();
  69.  
  70. /* Balance table. When balance() encounters a character
  71.  * that is to be matched, it first searches this table
  72.  * for a balancing left-side character.     If the character
  73.  * is not in the table, the character is balanced by itself.
  74.  * This is to allow delimiters in Scribe documents to be matched.
  75.  */
  76.  
  77. static struct balance {
  78.     char left, right;
  79. } bal[] = {
  80.     { '(', ')' },
  81.     { '[', ']' },
  82.     { '{', '}' },
  83.     { '<', '>' },
  84.     { '\0','\0'}
  85. };
  86.  
  87. /*
  88.  * Self-insert character, then show matching character,
  89.  * if any.  Bound to "blink-matching-paren-command".
  90.  */
  91.  
  92. showmatch(f, n)
  93. {
  94.     register int  i, s;
  95.  
  96.     if (f & FFRAND) return FALSE;
  97.     for (i = 0; i < n; i++) {
  98.         if ((s = selfinsert(FFRAND, 1)) != TRUE)
  99.             return s;
  100.         if (balance() != TRUE) /* unbalanced -- warn user */
  101.             ttbeep();
  102.     }
  103.     return TRUE;
  104. }
  105.  
  106. /*
  107.  * Search for and display a matching character.
  108.  *
  109.  * This routine does the real work of searching backward
  110.  * for a balancing character.  If such a balancing character
  111.  * is found, it uses displaymatch() to display the match.
  112.  */
  113.  
  114. static balance()
  115. {
  116.     register LINE    *clp;
  117.     register int    cbo;
  118.     int    c;
  119.     int    i;
  120.     int    rbal, lbal;
  121.     int    depth;
  122.  
  123.     rbal = key.k_chars[key.k_count-1];
  124.  
  125.     /* See if there is a matching character -- default to the same */
  126.  
  127.     lbal = rbal;
  128.     for (i = 0; bal[i].right != '\0'; i++)
  129.         if (bal[i].right == rbal) {
  130.             lbal = bal[i].left;
  131.             break;
  132.         }
  133.  
  134.     /* Move behind the inserted character.    We are always guaranteed    */
  135.     /* that there is at least one character on the line, since one was  */
  136.     /* just self-inserted by blinkparen.                    */
  137.  
  138.     clp = curwp->w_dotp;
  139.     cbo = curwp->w_doto - 1;
  140.  
  141.     depth = 0;            /* init nesting depth        */
  142.  
  143.     for (;;) {
  144.         if (cbo == 0) {            /* beginning of line    */
  145.             clp = lback(clp);
  146.             if (clp == curbp->b_linep)
  147.                 return (FALSE);
  148.             cbo = llength(clp)+1;
  149.         }
  150.         if (--cbo == llength(clp))    /* end of line        */
  151.             c = '\n';
  152.         else
  153.             c = lgetc(clp,cbo);    /* somewhere in middle    */
  154.  
  155.         /* Check for a matching character.  If still in a nested */
  156.         /* level, pop out of it and continue search.  This check */
  157.         /* is done before the nesting check so single-character     */
  158.         /* matches will work too.                 */
  159.         if (c == lbal) {
  160.             if (depth == 0) {
  161.                 displaymatch(clp,cbo);
  162.                 return (TRUE);
  163.             }
  164.             else
  165.                 depth--;
  166.         }
  167.         /* Check for another level of nesting.    */
  168.         if (c == rbal)
  169.             depth++;
  170.     }
  171.     /*NOTREACHED*/
  172. }
  173.  
  174.  
  175. /*
  176.  * Display matching character.
  177.  * Matching characters that are not in the current window
  178.  * are displayed in the echo line. If in the current
  179.  * window, move dot to the matching character,
  180.  * sit there a while, then move back.
  181.  */
  182.  
  183. static VOID displaymatch(clp, cbo)
  184. register LINE *clp;
  185. register int  cbo;
  186. {
  187.     register LINE    *tlp;
  188.     register int    tbo;
  189.     register int    cp;
  190.     register int    bufo;
  191.     register int    c;
  192.     int        inwindow;
  193.     char        buf[NLINE];
  194.  
  195.     /* Figure out if matching char is in current window by    */
  196.     /* searching from the top of the window to dot.        */
  197.  
  198.     inwindow = FALSE;
  199.     for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
  200.         if (tlp == clp)
  201.             inwindow = TRUE;
  202.  
  203.     if (inwindow == TRUE) {
  204.         tlp = curwp->w_dotp;    /* save current position */
  205.         tbo = curwp->w_doto;
  206.  
  207.         curwp->w_dotp  = clp;    /* move to new position */
  208.         curwp->w_doto  = cbo;
  209.         curwp->w_flag |= WFMOVE;
  210.  
  211.         update();        /* show match */
  212.         sleep(1);        /* wait a bit */
  213.  
  214.         curwp->w_dotp    = tlp;    /* return to old position */
  215.         curwp->w_doto    = tbo;
  216.         curwp->w_flag  |= WFMOVE;
  217.         update();
  218.     }
  219.     else {    /* match not in this window so display line in echo area */
  220.         bufo = 0;
  221.         for (cp = 0; cp < llength(clp); cp++) { /* expand tabs    */
  222.             c = lgetc(clp,cp);
  223.             if (c != '\t'
  224. #ifdef    NOTAB
  225.                 || (curbp->b_flag & BFNOTAB)
  226. #endif
  227.                 ) if(ISCTRL(c)) {
  228.                     buf[bufo++] = '^';
  229.                     buf[bufo++] = CCHR(c);
  230.                 } else buf[bufo++] = c;
  231.             else
  232.                 do {
  233.                     buf[bufo++] = ' ';
  234.                 } while (bufo & 7);
  235.         }
  236.         buf[bufo++] = '\0';
  237.         ewprintf("Matches %s",buf);
  238.     }
  239. }
  240. SHAR_EOF
  241. cat << \SHAR_EOF > dir.c
  242. /*
  243.  * Name:    MG 2a
  244.  *        Directory management functions
  245.  * Created:    Ron Flax (ron@vsedev.vse.com)
  246.  *        Modified for MG 2a by Mic Kaczmarczik 03-Aug-1987
  247.  */
  248.  
  249. #include "def.h"
  250.  
  251. #ifndef NO_DIR
  252. #ifndef    getwd            /* may be a #define */
  253. char    *getwd();
  254. #endif
  255. char    *wdir;
  256. static char cwd[NFILEN];
  257.  
  258. /*
  259.  * Initialize anything the directory management routines need
  260.  */
  261. dirinit()
  262. {
  263.     if (!(wdir = getwd(cwd)))
  264.         panic("Can't get current directory!");
  265. }
  266.  
  267. /*
  268.  * Change current working directory
  269.  */
  270. /*ARGSUSED*/
  271. changedir(f, n)
  272. {
  273.     register int s;
  274.     char bufc[NPAT];
  275.  
  276.     if ((s=ereply("Change default directory: ", bufc, NPAT)) != TRUE)
  277.         return(s);
  278.     if (bufc[0] == '\0')
  279.         (VOID) strcpy(bufc, wdir);
  280.     if (chdir(bufc) == -1) {
  281.         ewprintf("Can't change dir to %s", bufc);
  282.         return(FALSE);
  283.     } else {
  284.         if (!(wdir = getwd(cwd)))
  285.             panic("Can't get current directory!");
  286.         ewprintf("Current directory is now %s", wdir);
  287.         return(TRUE);
  288.     }
  289. }
  290.  
  291. /*
  292.  * Show current directory
  293.  */
  294. /*ARGSUSED*/
  295. showcwdir(f, n)
  296. {
  297.     ewprintf("Current directory: %s", wdir);
  298.     return(TRUE);
  299. }
  300. #endif
  301. SHAR_EOF
  302. cat << \SHAR_EOF > re_search.c
  303. /*
  304.  *        regular expression search commands for
  305.  *               MicroGnuEmacs
  306.  *
  307.  * This file contains functions to implement several of gnuemacs'
  308.  * regular expression functions for MicroGnuEmacs.  Several of
  309.  * the routines below are just minor rearrangements of the MicroGnuEmacs
  310.  * non-regular expression search functions.  Hence some of them date back
  311.  * in essential structure to the original MicroEMACS; others are modifications
  312.  * of Rich Ellison's code.  I, Peter Newton, wrote about half from scratch.
  313.  *
  314.  * Although I have nothing to do with the GNU project, these functions
  315.  * require the GNU project's regular expression package (files regex.c and
  316.  * regex.h).  Hence, this file comes under the same copyright notice
  317.  * as the GNU project's code.  As far as I know, the rest of MicroGnuEmacs
  318.  * need not since it may be used independently of any GNU project code.     In
  319.  * any case, I certainly do not warrant either the correctness or utility
  320.  * of this code.  The GNU project copyright notice follows.  Don't you
  321.  * wish they would make it a bit shorter!
  322.  */
  323.  
  324. /*
  325. GNU Emacs copying permission notice Copyright (C) 1985 Richard M. Stallman
  326.      Verbatim copies of this document, including its copyright notice,
  327.      may be distributed by anyone in any manner.
  328.      Distribution with modifications is not permitted.
  329.  
  330. GNU Emacs is distributed in the hope that it will be useful,
  331. but without any warranty.  No author or distributor
  332. accepts responsibility to anyone for the consequences of using it
  333. or for whether it serves any particular purpose or works at all,
  334. unless he says so in writing.
  335.  
  336. Everyone is granted permission to copy, modify and redistribute
  337. GNU Emacs under the following conditions:
  338.  
  339.    Permission is granted to anyone to make or distribute verbatim copies
  340.    of GNU Emacs source code as received, in any medium, provided that all
  341.    copyright notices and permission and nonwarranty notices are preserved,
  342.    and that the distributor grants the recipient permission
  343.    for further redistribution as permitted by this document,
  344.    and gives him and points out to him an exact copy of this document
  345.    to inform him of his rights.
  346.  
  347.    Permission is granted to distribute modified versions
  348.    of GNU Emacs source code, or of portions of it,
  349.    under the above conditions, provided also that all
  350.    changed files carry prominent notices stating who last changed them
  351.    and that all the GNU-Emacs-derived material, including everything
  352.    packaged together with it and not independently usable, is
  353.    distributed under the conditions stated in this document.
  354.  
  355.    Permission is granted to distribute GNU Emacs in
  356.    compiled or executable form under the same conditions applying
  357.    for source code, provided that either
  358.     A.    it is accompanied by the corresponding machine-readable
  359.       source code, or
  360.     B.    it is accompanied by a written offer, with no time limit,
  361.       to give anyone a machine-readable copy of the corresponding
  362.       source code in return for reimbursement of the cost of distribution.
  363.       This written offer must permit verbatim duplication by anyone.
  364.     C.    it is distributed by someone who received only the
  365.       executable form, and is accompanied by a copy of the
  366.       written offer of source code which he received along with it.
  367.  
  368. In other words, you are welcome to use, share and improve GNU Emacs
  369. You are forbidden to forbid anyone else to use, share and improve
  370. what you give them.   Help stamp out software-hoarding!
  371. */
  372.  
  373. #ifdef    REGEX
  374. #include    "def.h"
  375. #include    "macro.h"
  376.  
  377. #define SRCH_BEGIN    (0)            /* Search sub-codes.    */
  378. #define SRCH_FORW    (-1)
  379. #define SRCH_BACK    (-2)
  380. #define SRCH_NOPR    (-3)
  381. #define SRCH_ACCM    (-4)
  382. #define SRCH_MARK    (-5)
  383.  
  384. char    re_pat[NPAT];            /* Regex pattern        */
  385. int    re_srch_lastdir = SRCH_NOPR;     /* Last search flags. */
  386. int    casefoldsearch = TRUE;         /* Does search ignore case ? */
  387.  
  388. /* Indexed by a character, gives the upper case equivalent of the character */
  389.  
  390. static char upcase[0400] =
  391.   { 000, 001, 002, 003, 004, 005, 006, 007,
  392.     010, 011, 012, 013, 014, 015, 016, 017,
  393.     020, 021, 022, 023, 024, 025, 026, 027,
  394.     030, 031, 032, 033, 034, 035, 036, 037,
  395.     040, 041, 042, 043, 044, 045, 046, 047,
  396.     050, 051, 052, 053, 054, 055, 056, 057,
  397.     060, 061, 062, 063, 064, 065, 066, 067,
  398.     070, 071, 072, 073, 074, 075, 076, 077,
  399.     0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  400.     0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  401.     0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  402.     0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
  403.     0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  404.     0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  405.     0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  406.     0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
  407.     0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  408.     0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
  409.     0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
  410.     0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
  411.     0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
  412.     0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
  413.     0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  414.     0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  415.     0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  416.     0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
  417.     0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
  418.     0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
  419.     0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
  420.     0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
  421.     0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  422.     0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
  423.   };
  424.  
  425. /*
  426.  * Search forward.
  427.  * Get a search string from the user, and search for it,
  428.  * starting at ".". If found, "." gets moved to just after the
  429.  * matched characters, and display does all the hard stuff.
  430.  * If not found, it just prints a message.
  431.  */
  432. /*ARGSUSED*/
  433. re_forwsearch(f, n) {
  434.     register int    s;
  435.  
  436.     if ((s=re_readpattern("RE Search")) != TRUE)
  437.         return (s);
  438.     if (re_forwsrch() == FALSE) {
  439.         ewprintf("Search failed: \"%s\"", re_pat);
  440.         return (FALSE);
  441.     }
  442.     re_srch_lastdir = SRCH_FORW;
  443.     return (TRUE);
  444. }
  445.  
  446. /*
  447.  * Reverse search.
  448.  * Get a search string from the     user, and search, starting at "."
  449.  * and proceeding toward the front of the buffer. If found "." is left
  450.  * pointing at the first character of the pattern [the last character that
  451.  * was matched].
  452.  */
  453. /*ARGSUSED*/
  454. re_backsearch(f, n) {
  455.     register int    s;
  456.  
  457.     if ((s=re_readpattern("RE Search backward")) != TRUE)
  458.         return (s);
  459.     if (re_backsrch() == FALSE) {
  460.         ewprintf("Search failed: \"%s\"", re_pat);
  461.         return (FALSE);
  462.     }
  463.     re_srch_lastdir = SRCH_BACK;
  464.     return (TRUE);
  465. }
  466.  
  467.  
  468.  
  469. /*
  470.  * Search again, using the same search string
  471.  * and direction as the last search command. The direction
  472.  * has been saved in "srch_lastdir", so you know which way
  473.  * to go.
  474.  */
  475. /*ARGSUSED*/
  476. /*  This code has problems-- some incompatibility(?) with
  477.     extend.c causes match to fail when it should not.
  478.  */
  479. re_searchagain(f, n) {
  480.  
  481.   if (re_srch_lastdir == SRCH_NOPR) {
  482.     ewprintf("No last search");
  483.     return (FALSE);
  484.   }
  485.  
  486.   if (re_srch_lastdir == SRCH_FORW) {
  487.     if (re_forwsrch() == FALSE) {
  488.       ewprintf("Search failed: \"%s\"", re_pat);
  489.       return (FALSE);
  490.     }
  491.     return (TRUE);
  492.   }
  493.   if (re_srch_lastdir == SRCH_BACK) {
  494.     if (re_backsrch() == FALSE) {
  495.       ewprintf("Search failed: \"%s\"", re_pat);
  496.       return (FALSE);
  497.     }
  498.     return (TRUE);
  499.   }
  500. }
  501.  
  502.  
  503. #include "regex.h"
  504. #define BYTEWIDTH 8
  505.  
  506. /* Compiled regex goes here-- changed only when new pattern read */
  507. static struct re_pattern_buffer re_buff;
  508. static char fastmap[(1 << BYTEWIDTH)];
  509.  
  510. /* regs holds boundaries of matched text */
  511. static struct re_registers regs;
  512.  
  513. /*
  514.  * Re-Query Replace.
  515.  *    Replace strings selectively.  Does a search and replace operation.
  516.  */
  517. /*ARGSUSED*/
  518. re_queryrepl(f, n) {
  519.     register int    s;
  520.     register int    rcnt = 0;    /* Replacements made so far    */
  521.     register int    plen;        /* length of found string    */
  522.     char        news[NPAT];    /* replacement string        */
  523.  
  524.     /* Casefold check */
  525.     if (!casefoldsearch) f = TRUE;
  526.  
  527.     if ((s=re_readpattern("RE Query replace")) != TRUE)
  528.         return (s);
  529.     if ((s=ereply("Query replace %s with: ",news, NPAT, re_pat)) == ABORT)
  530.         return (s);
  531.     if (s == FALSE)
  532.         news[0] = '\0';
  533.     ewprintf("Query replacing %s with %s:", re_pat, news);
  534.  
  535.     /*
  536.      * Search forward repeatedly, checking each time whether to insert
  537.      * or not.  The "!" case makes the check always true, so it gets put
  538.      * into a tighter loop for efficiency.
  539.      */
  540.  
  541.     while (re_forwsrch() == TRUE) {
  542.     retry:
  543.         update();
  544.         switch (getkey(FALSE)) {
  545.         case ' ':
  546.             plen = regs.end[0] - regs.start[0];
  547.             if (re_doreplace((RSIZE) plen, news, f) == FALSE)
  548.                 return (FALSE);
  549.             rcnt++;
  550.             break;
  551.  
  552.         case '.':
  553.             plen = regs.end[0] - regs.start[0];
  554.             if (re_doreplace((RSIZE) plen, news, f) == FALSE)
  555.                 return (FALSE);
  556.             rcnt++;
  557.             goto stopsearch;
  558.  
  559.         case CCHR('G'): /* ^G */
  560.             (VOID) ctrlg(FFRAND, 0);
  561.         case CCHR('['): /* ESC */
  562.         case '`':
  563.             goto stopsearch;
  564.  
  565.         case '!':
  566.             do {
  567.                 plen = regs.end[0] - regs.start[0];
  568.                 if (re_doreplace((RSIZE) plen, news, f) == FALSE)
  569.                     return (FALSE);
  570.                 rcnt++;
  571.             } while (re_forwsrch() == TRUE);
  572.             goto stopsearch;
  573.  
  574.         case CCHR('?'):        /* To not replace */
  575.             break;
  576.  
  577.         default:
  578. ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
  579.             goto retry;
  580.         }
  581.     }
  582. stopsearch:
  583.     curwp->w_flag |= WFHARD;
  584.     update();
  585.     if (!inmacro) {
  586.         if (rcnt == 0)
  587.             ewprintf("(No replacements done)");
  588.         else if (rcnt == 1)
  589.             ewprintf("(1 replacement done)");
  590.         else
  591.             ewprintf("(%d replacements done)", rcnt);
  592.     }
  593.     return TRUE;
  594. }
  595.  
  596.  
  597.  
  598. /* Routine re_doreplace calls lreplace to make replacements needed by
  599.  * re_query replace.  Its reason for existence is to deal with \1,
  600.  * \2. etc.
  601.  */
  602.  
  603. /* Maximum length of replacement string */
  604. #define REPLEN 256
  605.  
  606. re_doreplace(plen, st, f)
  607.      register RSIZE  plen;             /* length to remove         */
  608.      char         *st;             /* replacement string         */
  609.      int         f;                 /* case hack disable         */
  610. {
  611.   int s;
  612.   int num, k;
  613.   register int j;
  614.   int more, state;
  615.   LINE *clp;
  616.   char repstr[REPLEN];
  617.  
  618.   clp = curwp->w_dotp;
  619.   more = TRUE;
  620.   j = 0;
  621.   state = 0;
  622.  
  623.   /* The following FSA parses the replacement string */
  624.   while (more) {
  625.     switch (state) {
  626.  
  627.     case 0: if (*st == '\\') {
  628.           st++;
  629.           state = 1;
  630.         }
  631.         else if (*st == '\0')
  632.           more = FALSE;
  633.         else {
  634.           repstr[j] = *st;
  635.           j++; if (j >= REPLEN) return(FALSE);
  636.           st++;
  637.         }
  638.         break;
  639.     case 1: if (*st >= '0' && *st <= '9') {
  640.           num = *st - '0';
  641.           st++;
  642.           state = 2;
  643.         }
  644.         else if (*st == '\0')
  645.           more = FALSE;
  646.         else {
  647.           repstr[j] = *st;
  648.           j++; if (j >= REPLEN) return(FALSE);
  649.           st++;
  650.           state = 0;
  651.         }
  652.         break;
  653.     case 2: if (*st >= '0' && *st <= '9') {
  654.           num = 10*num + *st - '0';
  655.           st++;
  656.         }
  657.         else {
  658.           if (num >= RE_NREGS) return(FALSE);
  659.           k = regs.end[num] - regs.start[num];
  660.           if (j+k >= REPLEN) return(FALSE);
  661.           bcopy(&(clp->l_text[regs.start[num]]), &repstr[j], k);
  662.           j += k;
  663.           if (*st == '\0')
  664.         more = FALSE;
  665.           if (*st == '\\') {
  666.         st++;
  667.         state = 1;
  668.           }
  669.           else {
  670.         repstr[j] = *st;
  671.         j++; if (j >= REPLEN) return(FALSE);
  672.         st++;
  673.         state = 0;
  674.           }
  675.         }
  676.         break;
  677.       } /* end case */
  678.   } /* end while */
  679.  
  680.   repstr[j] = '\0';
  681.  
  682.   s = lreplace(plen, repstr, f);
  683.  
  684.   return(s);
  685. }
  686.  
  687.  
  688.  
  689. /*
  690.  * This routine does the real work of a
  691.  * forward search. The pattern is sitting in the external
  692.  * variable "pat". If found, dot is updated, the window system
  693.  * is notified of the change, and TRUE is returned. If the
  694.  * string isn't found, FALSE is returned.
  695.  */
  696. re_forwsrch() {
  697.  
  698.   register LINE *clp;
  699.   register int tbo;
  700.   int ntries;
  701.   int i, plen;
  702.  
  703.   clp = curwp->w_dotp;
  704.   tbo = curwp->w_doto;
  705.  
  706.   if (tbo == clp->l_used)
  707.     /* Don't start matching off end of line-- must
  708.      * move to beginning of next line, unless at end
  709.      */
  710.     if (clp != curbp->b_linep) {
  711.       clp = lforw(clp);
  712.       tbo = 0;
  713.     }
  714.  
  715.  
  716.   /* Note this loop does not process the last line, but this editor
  717.      always makes the last line empty so this is good.
  718.    */
  719.  
  720.   while (clp != (curbp->b_linep)) {
  721.  
  722.      ntries = llength(clp) - tbo;
  723.      i = re_search (&re_buff, ltext(clp), llength(clp), tbo, ntries, ®s);
  724.  
  725.      if (i == -1) {
  726.        clp = lforw(clp);
  727.        tbo = 0;
  728.      }
  729.      else {
  730.        curwp->w_doto = regs.end[0];
  731.        curwp->w_dotp = clp;
  732.        curwp->w_flag |= WFMOVE;
  733.        return (TRUE);
  734.      }
  735.  
  736.    }
  737.  
  738.   return(FALSE);
  739.  
  740. }
  741.  
  742.  
  743. /*
  744.  * This routine does the real work of a
  745.  * backward search. The pattern is sitting in the external
  746.  * variable "re_pat". If found, dot is updated, the window system
  747.  * is notified of the change, and TRUE is returned. If the
  748.  * string isn't found, FALSE is returned.
  749.  */
  750. re_backsrch() {
  751.  
  752.   register LINE *clp;
  753.   register int tbo;
  754.   int ntries;
  755.   int i, startpos;
  756. char m[1];
  757.  
  758.   clp = curwp->w_dotp;
  759.   tbo = curwp->w_doto;
  760.  
  761.   /* Start search one position to the left of dot */
  762.   tbo = tbo - 1;
  763.   if (tbo < 0) {
  764.     /* must move up one line */
  765.     clp = lback(clp);
  766.     tbo = llength(clp);
  767.   }
  768.  
  769.   /* Note this loop does not process the last line, but this editor
  770.      always makes the last line empty so this is good.
  771.    */
  772.  
  773.   while (clp != (curbp->b_linep)) {
  774.  
  775.      ntries = tbo;
  776.      i = re_search (&re_buff, ltext(clp), llength(clp), tbo, -ntries, ®s);
  777.  
  778.      if (i == -1) {
  779.        clp = lback(clp);
  780.        tbo = llength(clp);
  781.      }
  782.      else {
  783.        curwp->w_doto = regs.start[0];
  784.        curwp->w_dotp = clp;
  785.        curwp->w_flag |= WFMOVE;
  786.        return (TRUE);
  787.      }
  788.  
  789.    }
  790.  
  791.   return(FALSE);
  792.  
  793. }
  794.  
  795.  
  796. /*
  797.  * Read a pattern.
  798.  * Stash it in the external variable "re_pat". The "pat" is
  799.  * not updated if the user types in an empty line. If the user typed
  800.  * an empty line, and there is no old pattern, it is an error.
  801.  * Display the old pattern, in the style of Jeff Lomicka. There is
  802.  * some do-it-yourself control expansion.
  803.  */
  804. re_readpattern(prompt) char *prompt; {
  805.     register int s;
  806.     char tpat[NPAT];
  807.     char *message;
  808.  
  809.     if (re_pat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
  810.     else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, re_pat);
  811.  
  812.     if (s == TRUE) {
  813.       /* New pattern given */
  814.       (VOID) strcpy(re_pat, tpat);
  815.       re_buff.allocated = 40;
  816.       re_buff.buffer = (char *) malloc (re_buff.allocated);
  817.       re_buff.fastmap = fastmap;
  818.       if (casefoldsearch)
  819.         re_buff.translate = upcase;
  820.       else
  821.         re_buff.translate = '\0';
  822.       message = re_compile_pattern (re_pat, strlen(re_pat), &re_buff);
  823.       if (message != '\0') {
  824.         ewprintf("Regex Error: %s", message);
  825.         re_pat[0] = '\0';
  826.         return(FALSE);
  827.       }
  828.       re_compile_fastmap (&re_buff);
  829.     }
  830.     else if (s==FALSE && re_pat[0]!='\0')
  831.       /* Just using old pattern */
  832.       s = TRUE;
  833.     return (s);
  834. }
  835.  
  836.  
  837.  
  838. /* Cause case to not matter in searches.  This is the default.    If
  839.  * called with argument cause case to matter.
  840.  */
  841. setcasefold(f, n) {
  842.  
  843.   if (f & FFARG) {
  844.     casefoldsearch = FALSE;
  845.     ewprintf("Case-fold-search unset");
  846.   }
  847.   else {
  848.     casefoldsearch = TRUE;
  849.     ewprintf("Case-fold-search set");
  850.   }
  851.  
  852.   /* Invalidate the regular expression pattern since I'm too lazy
  853.    * to recompile it.
  854.    */
  855.  
  856.   re_pat[0] = '\0';
  857.  
  858.   return(TRUE);
  859.  
  860. } /* end setcasefold */
  861.  
  862.  
  863. /* Delete all lines after dot that contain a string matching regex
  864.  */
  865. delmatchlines(f, n) {
  866.   int s;
  867.  
  868.   if ((s=re_readpattern("Flush lines (containing match for regexp)")) != TRUE)
  869.     return (s);
  870.  
  871.   s = killmatches(TRUE);
  872.  
  873.   return(s);
  874. }
  875.  
  876.  
  877.  
  878. /* Delete all lines after dot that don't contain a string matching regex
  879.  */
  880. delnonmatchlines(f, n) {
  881.   int s;
  882.  
  883.  
  884.   if ((s=re_readpattern("Keep lines (containing match for regexp)")) != TRUE)
  885.     return (s);
  886.  
  887.   s = killmatches(FALSE);
  888.  
  889.   return(s);
  890. }
  891.  
  892.  
  893.  
  894. /* This function does the work of deleting matching lines */
  895. killmatches(cond)
  896.    int cond;
  897. {
  898.   int s, i;
  899.   int count = 0;
  900.   LINE    *clp;
  901.  
  902.   clp = curwp->w_dotp;
  903.   if (curwp->w_doto == llength(clp))
  904.     /* Consider dot on next line */
  905.     clp = lforw(clp);
  906.  
  907.   while (clp != (curbp->b_linep)) {
  908.  
  909.      /* see if line matches */
  910.      i = re_search (&re_buff, ltext(clp), llength(clp), 0, llength(clp),
  911.             ®s);
  912.      /* Delete line when appropriate */
  913.      if ((cond == FALSE && i == -1) || (cond == TRUE && i != -1)) {
  914.        curwp->w_doto = 0;
  915.        curwp->w_dotp = clp;
  916.        count++;
  917.        s = ldelete(llength(clp)+1, KNONE);
  918.        clp = curwp->w_dotp;
  919.        curwp->w_flag |= WFMOVE;
  920.        if (s == FALSE) return(FALSE);
  921.      }
  922.      else
  923.        clp = lforw(clp);
  924.    }
  925.  
  926.   ewprintf("%d line(s) deleted", count);
  927.   if (count > 0) curwp->w_flag |= WFMOVE;
  928.  
  929.   return(TRUE);
  930. }
  931.  
  932.  
  933. petersfunc(f, n) {
  934.  
  935.   int s;
  936.   LINE    *clp;
  937.   char c;
  938.  
  939.   curwp->w_doto = 0;
  940.   s = ldelete(llength(curwp->w_dotp)+1, KNONE);
  941.   curwp->w_flag |= WFMOVE;
  942.   return(s);
  943.  
  944. }
  945.  
  946.  
  947. /* Count lines matching regex
  948.  */
  949. cntmatchlines(f, n) {
  950.   int s;
  951.  
  952.   if ((s=re_readpattern("Count lines (matching regexp)")) != TRUE)
  953.     return (s);
  954.  
  955.   s = countmatches(TRUE);
  956.  
  957.   return(s);
  958. }
  959.  
  960.  
  961.  
  962. /* Count lines that fail to match regex
  963.  */
  964. cntnonmatchlines(f, n) {
  965.   int s;
  966.  
  967.  
  968.   if ((s=re_readpattern("Count lines (not matching regexp)")) != TRUE)
  969.     return (s);
  970.  
  971.   s = countmatches(FALSE);
  972.  
  973.   return(s);
  974. }
  975.  
  976.  
  977.  
  978. /* This function does the work of counting matching lines */
  979. countmatches(cond)
  980.    int cond;
  981. {
  982.   int s, i;
  983.   int count = 0;
  984.   LINE    *clp;
  985.  
  986.   clp = curwp->w_dotp;
  987.   if (curwp->w_doto == llength(clp))
  988.     /* Consider dot on next line */
  989.     clp = lforw(clp);
  990.  
  991.   while (clp != (curbp->b_linep)) {
  992.  
  993.      /* see if line matches */
  994.      i = re_search (&re_buff, ltext(clp), llength(clp), 0, llength(clp),
  995.             ®s);
  996.      /*     Count line when appropriate */
  997.      if ((cond == FALSE && i == -1) || (cond == TRUE && i != -1)) count++;
  998.      clp = lforw(clp);
  999.    }
  1000.  
  1001.   if (cond)
  1002.      ewprintf("Number of lines matching: %d", count);
  1003.   else
  1004.      ewprintf("Number of lines not matching: %d", count);
  1005.  
  1006.   return(TRUE);
  1007. }
  1008. #endif
  1009. SHAR_EOF
  1010. cat << \SHAR_EOF > sys/bsd/README
  1011. Not much here; contributions welcome.
  1012.  
  1013. Two important things to note:
  1014.  
  1015. 1) The editor supports the notion that "~" is your home directory.
  1016.  
  1017. 2) Startup files are either ~/.mg, or (optionaly) a system default.
  1018. Only one is used.
  1019.  
  1020. SHAR_EOF
  1021. cat << \SHAR_EOF > sys/bsd/Makefile
  1022. # Makefile for Mg 2a
  1023.  
  1024. SYS    = bsd
  1025. LIBS    = -ltermcap
  1026. # CDEFS gets defines, and gets passed to lint. CFLAGS gets flags, and doesn't
  1027. # get passed to lint.
  1028. #
  1029. # (Common) compile-time options:
  1030. #
  1031. #    DO_METAKEY    -- if bit 7 is set for a key, treat like a META key
  1032. #    STARTUP        -- look for and handle initialization file
  1033. #    SYMBLINK    -- follow symbolic links the same as the BSD kernel
  1034. #    XKEYS        -- use termcap function key definitions. Warning -
  1035. #                XKEYS and bsmap mode do _not_ get along.
  1036. #    BACKUP        -- enable "make-backup-files"
  1037. #    PREFIXREGION    -- enable function "prefix-region"
  1038. #    REGEX        -- create regular expression functions
  1039. #
  1040. #CDEFS    =  -DDO_METAKEY
  1041. CDEFS    =  -DDO_METAKEY -DPREFIXREGION
  1042. CFLAGS    = -g $(CDEFS)
  1043.  
  1044. # Objects which only depend on the "standard" includes
  1045. OBJS    = basic.o dir.o dired.o file.o line.o match.o paragraph.o \
  1046.       random.o region.o search.o version.o window.o word.o
  1047.  
  1048. # Those with unique requirements
  1049. IND    = buffer.o display.o echo.o extend.o help.o kbd.o keymap.o \
  1050.       macro.o main.o modes.o regex.o re_search.o
  1051.  
  1052. # System dependent objects
  1053. OOBJS = cinfo.o spawn.o ttyio.o tty.o ttykbd.o
  1054.  
  1055. OBJ = $(OBJS) $(IND) $(OOBJS) fileio.o
  1056.  
  1057. OSRCS    = cinfo.c fileio.c spawn.c ttyio.c tty.c ttykbd.c
  1058. SRCS    = basic.c dir.c dired.c file.c line.c match.c paragraph.c \
  1059.       random.c region.c search.c version.c window.c word.c \
  1060.       buffer.c display.c echo.c extend.c help.c kbd.c keymap.c \
  1061.       macro.c main.c modes.c regex.c re_search.c
  1062.  
  1063. OINCS =    ttydef.h sysdef.h chrdef.h
  1064. INCS =    def.h
  1065.  
  1066. mg:    $(OBJ)
  1067.     cc $(CFLAGS) -o mg $(OBJ) $(LIBS)
  1068.  
  1069. # strip mg once you're satisfied it'll run -- makes it much smaller
  1070. strip:
  1071.     strip mg
  1072.  
  1073. lint: $(SRCS) $(OSRCS) $(INCS) $(OINCS)
  1074.     lint -ahbz $(CDEFS) $(SRCS) $(OSRCS)
  1075.  
  1076. $(OBJ):        $(INCS) $(OINCS)
  1077.  
  1078.  
  1079. dir.r search.o:    $(INCS) $(OINCS)
  1080.  
  1081. regex.o re_search.o:    $(INCS) $(OINCS) regex.h
  1082.  
  1083. kbd.o:    $(INCS) $(OINCS) macro.h kbd.h key.h
  1084.  
  1085. macro.o main.o:    $(INCS) $(OINCS) macro.h
  1086.  
  1087. buffer.o display.o keymap.o help.o modes.o dired.o fileio.o: \
  1088.     $(INCS) $(OINCS) kbd.h
  1089.  
  1090. extend.o:    $(INCS) $(OINCS) kbd.h macro.h key.h
  1091.  
  1092. help.o:    $(INCS) $(OINCS) kbd.h key.h macro.h
  1093.  
  1094. echo.o:    $(INCS) $(OINCS) key.h macro.h
  1095.  
  1096. $(OOBJS):    $(INCS) $(OINCS)
  1097.  
  1098. sysdef.h:    sys/$(SYS)/sysdef.h    # Update links, if needed.
  1099.     rm -f sysdef.h
  1100.     ln sys/$(SYS)/sysdef.h .
  1101.  
  1102. ttydef.h:    sys/default/ttydef.h
  1103.     rm -f ttydef.h
  1104.     ln sys/default/ttydef.h .
  1105.  
  1106. chrdef.h:    sys/default/chrdef.h
  1107.     rm -f chrdef.h
  1108.     ln sys/default/chrdef.h .
  1109.  
  1110. fileio.c:    sys/$(SYS)/fileio.c
  1111.     rm -f fileio.c
  1112.     ln sys/$(SYS)/fileio.c .
  1113.  
  1114. spawn.c:    sys/$(SYS)/spawn.c
  1115.     rm -f spawn.c
  1116.     ln sys/$(SYS)/spawn.c .
  1117.  
  1118. tty.c:        sys/default/tty.c
  1119.     rm -f tty.c
  1120.     ln sys/default/tty.c .
  1121.  
  1122. ttyio.c:    sys/$(SYS)/ttyio.c
  1123.     rm -f ttyio.c
  1124.     ln sys/$(SYS)/ttyio.c .
  1125.  
  1126. ttykbd.c:    sys/default/ttykbd.c
  1127.     rm -f ttykbd.c
  1128.     ln sys/default/ttykbd.c .
  1129.  
  1130. cinfo.c:    sys/default/cinfo.c
  1131.     rm -f cinfo.c
  1132.     ln sys/default/cinfo.c .
  1133.  
  1134. port: $(SRCS) $(INCS)
  1135.     rm -f port
  1136.     tar cfb port 1 $?
  1137.  
  1138. clean:;    rm -f $(OBJ) $(OSRCS) $(OINCS)
  1139.  
  1140. SHAR_EOF
  1141. cat << \SHAR_EOF > sys/bsd/spawn.c
  1142. /*
  1143.  * Spawn. New version, which
  1144.  * interracts with the job control stuff
  1145.  * in the 4.X BSD C shell.
  1146.  * Last edit:  Wed Aug 27 11:16:07 PDT 1986
  1147.  * By:           rtech!daveb, to use stop for ksh.
  1148.  */
  1149. #include    "def.h"
  1150.  
  1151. #include    <sgtty.h>
  1152. #include    <signal.h>
  1153. #include    <sys/wait.h>
  1154.  
  1155. char    *shellp = NULL;            /* Saved "SHELL" name.        */
  1156.  
  1157. extern    struct    sgttyb    oldtty;        /* There really should be a    */
  1158. extern    struct    sgttyb    newtty;        /* nicer way of doing this, so    */
  1159. extern    struct    sgttyb    oldtchars;    /* spawn does not need to know    */
  1160. extern    struct    sgttyb    newtchars;    /* about the insides of the    */
  1161. extern    struct    sgttyb    oldltchars;    /* terminal I/O code.        */
  1162. extern    struct    sgttyb    newltchars;
  1163.  
  1164. extern    char    *getenv();
  1165.  
  1166. /*
  1167.  * This code does a one of 2 different
  1168.  * things, depending on what version of the shell
  1169.  * you are using. If you are using the C shell, which
  1170.  * implies that you are using job control, then MicroEMACS
  1171.  * moves the cursor to a nice place and sends itself a
  1172.  * stop signal. If you are using the Bourne shell it runs
  1173.  * a subshell using fork/exec. Bound to "C-C", and used
  1174.  * as a subcommand by "C-Z".
  1175.  *
  1176.  * Daveb -- changed sense of test so that we only spawn if you
  1177.  *        are explicitly using /bin/sh.  This makes it stop
  1178.  *        work with the ksh.
  1179.  */
  1180. /*ARGSUSED*/
  1181. spawncli(f, n) {
  1182.     register int    pid, wpid, (*oqsig)(), (*oisig)(), omask;
  1183.     union wait    status;
  1184.  
  1185.     if (shellp == NULL) {
  1186.         shellp = getenv("SHELL");
  1187.         if (shellp == NULL)
  1188.             shellp = getenv("shell");
  1189.         if (shellp == NULL)
  1190.             shellp = "/bin/sh";    /* Safer.        */
  1191.     }
  1192.     ttcolor(CTEXT);
  1193.     ttnowindow();
  1194.     if (strcmp(shellp, "/bin/csh") == 0) {
  1195.         if (epresf != FALSE) {
  1196.             ttmove(nrow-1, 0);
  1197.             tteeol();
  1198.             epresf = FALSE;
  1199.         }                /* Csh types a "\n"    */
  1200.         ttmove(nrow-2, 0);        /* before "Stopped".    */
  1201.     } else {
  1202.         ttmove(nrow-1, 0);
  1203.         if (epresf != FALSE) {
  1204.             tteeol();
  1205.             epresf = FALSE;
  1206.         }
  1207.     }
  1208.     if (ttcooked() == FALSE)
  1209.         return (FALSE);
  1210.     if (strcmp(shellp, "/bin/sh") != 0) {    /* C shell, ksh        */
  1211.         omask = sigsetmask(0);
  1212.         (void) kill(0, SIGTSTP);
  1213.         (void) sigsetmask(omask);
  1214.     } else {                /* Bourne shell.    */
  1215.         oqsig = signal(SIGQUIT, SIG_IGN);
  1216.         oisig = signal(SIGINT,    SIG_IGN);
  1217.         if ((pid=fork()) < 0) {
  1218.             (void) signal(SIGQUIT, oqsig);
  1219.             (void) signal(SIGINT,  oisig);
  1220.             ewprintf("Failed to create process");
  1221.             return (FALSE);
  1222.         }
  1223.         if (pid == 0) {
  1224.             execl(shellp, "sh", "-i", NULL);
  1225.             _exit(0);        /* Should do better!    */
  1226.         }
  1227.         while ((wpid=wait(&status))>=0 && wpid!=pid)
  1228.             ;
  1229.         (void) signal(SIGQUIT, oqsig);
  1230.         (void) signal(SIGINT,  oisig);
  1231.     }
  1232.     sgarbf = TRUE;                /* Force repaint.    */
  1233.     return ttraw();
  1234. }
  1235. SHAR_EOF
  1236. cat << \SHAR_EOF > sys/bsd/sysdef.h
  1237. /*
  1238.  *        BSD unix based systems (sunos, ultrix)
  1239.  */
  1240. #include <stdio.h>
  1241.  
  1242. #define    KBLOCK    8192            /* Kill grow.            */
  1243. #define    GOOD    0            /* Good exit status.        */
  1244. #define    SYMBLINK    1        /* Handle symbolic links    */
  1245. #define    MAXPATH    256            /* Maximum length of path for chdir */
  1246.  
  1247. typedef int    RSIZE;            /* Type for file/region sizes    */
  1248. typedef short    KCHAR;            /* Type for internal keystrokes    */
  1249.  
  1250. /*
  1251.  * Macros used by the buffer name making code.
  1252.  * Start at the end of the file name, scan to the left
  1253.  * until BDC1 (or BDC2, if defined) is reached. The buffer
  1254.  * name starts just to the right of that location, and
  1255.  * stops at end of string (or at the next BDC3 character,
  1256.  * if defined). BDC2 and BDC3 are mainly for VMS.
  1257.  */
  1258. #define    BDC1    '/'            /* Buffer names.        */
  1259.  
  1260. #define MALLOCROUND(m)    (m+=7,m&=~7)    /* round up to 8 byte boundry    */
  1261.  
  1262. #define    fncmp        strcmp        /* file name comparison        */
  1263. #define    unlinkdir(fn)    rmdir(fn)    /* unlink directory        */
  1264. char *getenv();
  1265. #define    gettermtype()    getenv("TERM")    /* determine terminal type    */
  1266. SHAR_EOF
  1267. cat << \SHAR_EOF > sys/bsd/ttyio.c
  1268. /*
  1269.  *        Ultrix-32 and Unix terminal I/O.
  1270.  * The functions in this file
  1271.  * negotiate with the operating system for
  1272.  * keyboard characters, and write characters to
  1273.  * the display in a barely buffered fashion.
  1274.  */
  1275. #include    "def.h"
  1276.  
  1277. #include    <sgtty.h>
  1278.  
  1279. #define NOBUF    512            /* Output buffer size.        */
  1280.  
  1281. char    obuf[NOBUF];            /* Output buffer.        */
  1282. int    nobuf;
  1283. struct    sgttyb    oldtty;            /* V6/V7 stty data.        */
  1284. struct    sgttyb    newtty;
  1285. struct    tchars    oldtchars;        /* V7 editing.            */
  1286. struct    tchars    newtchars;
  1287. struct    ltchars oldltchars;        /* 4.2 BSD editing.        */
  1288. struct    ltchars newltchars;
  1289. #ifdef    TIOCGWINSZ
  1290. struct    winsize winsize;        /* 4.3 BSD window sizing    */
  1291. #endif
  1292. int    nrow;                /* Terminal size, rows.        */
  1293. int    ncol;                /* Terminal size, columns.    */
  1294.  
  1295. /*
  1296.  * This function gets called once, to set up
  1297.  * the terminal channel. On Ultrix is's tricky, since
  1298.  * we want flow control, but we don't want any characters
  1299.  * stolen to send signals. Use CBREAK mode, and set all
  1300.  * characters but start and stop to 0xFF.
  1301.  */
  1302. ttopen() {
  1303.     register char *tv_stype;
  1304.     char *getenv(), *tgetstr(), tcbuf[1024], err_str[72];
  1305.     char *sprintf();
  1306.  
  1307. /* do this the REAL way */
  1308.     if ((tv_stype = getenv("TERM")) == NULL)
  1309.     {
  1310.         puts("Environment variable TERM not defined!");
  1311.         exit(1);
  1312.     }
  1313.  
  1314.     if((tgetent(tcbuf, tv_stype)) != 1)
  1315.     {
  1316.         (void) sprintf(err_str, "Unknown terminal type %s!", tv_stype);
  1317.         puts(err_str);
  1318.         exit(1);
  1319.     }
  1320.     if (ttraw() == FALSE)
  1321.         panic("aborting due to terminal initialize failure");
  1322. }
  1323.  
  1324. /*
  1325.  * This function sets the terminal to RAW mode, as defined for the current
  1326.  * shell.  This is called both by ttopen() above and by spawncli() to
  1327.  * get the current terminal settings and then change them to what
  1328.  * mg expects.    Thus, stty changes done while spawncli() is in effect
  1329.  * will be reflected in mg.
  1330.  */
  1331. ttraw() {
  1332.     extern short ospeed;
  1333.  
  1334.     if (ioctl(0, TIOCGETP, (char *) &oldtty) < 0) {
  1335.         ewprintf("ttopen can't get sgtty");
  1336.         return(FALSE);
  1337.     }
  1338.     newtty.sg_ospeed = ospeed = oldtty.sg_ospeed;
  1339.     newtty.sg_ispeed = oldtty.sg_ispeed;
  1340.     newtty.sg_erase     = oldtty.sg_erase;
  1341.     newtty.sg_kill     = oldtty.sg_kill;
  1342.     newtty.sg_flags     = oldtty.sg_flags;
  1343.     newtty.sg_flags &= ~(ECHO|CRMOD);    /* Kill echo, CR=>NL.    */
  1344. #ifdef FLOWCONTROL
  1345.     newtty.sg_flags |= CBREAK;        /* Half-cooked mode.    */
  1346. #else
  1347.     newtty.sg_flags |= RAW|ANYP;        /* raw mode for 8 bit path.*/
  1348. #endif
  1349.     if (ioctl(0, TIOCSETP, (char *) &newtty) < 0) {
  1350.         ewprintf("ttopen can't set sgtty");
  1351.         return(FALSE);
  1352.     }
  1353.     if (ioctl(0, TIOCGETC, (char *) &oldtchars) < 0) {
  1354.         ewprintf("ttopen can't get chars");
  1355.         return(FALSE);
  1356.     }
  1357.     newtchars.t_intrc  = 0xFF;        /* Interrupt.        */
  1358.     newtchars.t_quitc  = 0xFF;        /* Quit.        */
  1359. #if FLOWCONTROL
  1360.     newtchars.t_startc = 0x11;        /* ^Q, for terminal.    */
  1361.     newtchars.t_stopc  = 0x13;        /* ^S, for terminal.    */
  1362. #else
  1363.     newtchars.t_startc = 0xFF;        /* ^Q, for terminal.    */
  1364.     newtchars.t_stopc  = 0xFF;        /* ^S, for terminal.    */
  1365. #endif
  1366.     newtchars.t_eofc   = 0xFF;
  1367.     newtchars.t_brkc   = 0xFF;
  1368.     if (ioctl(0, TIOCSETC, (char *) &newtchars) < 0) {
  1369.         ewprintf("ttraw can't set chars");
  1370.         return(FALSE);
  1371.     }
  1372.     if (ioctl(0, TIOCGLTC, (char *) &oldltchars) < 0) {
  1373.         panic("ttraw can't get ltchars");
  1374.         return(FALSE);
  1375.     }
  1376.     newltchars.t_suspc  = 0xFF;        /* Suspend #1.        */
  1377.     newltchars.t_dsuspc = 0xFF;        /* Suspend #2.        */
  1378.     newltchars.t_rprntc = 0xFF;
  1379.     newltchars.t_flushc = 0xFF;        /* Output flush.    */
  1380.     newltchars.t_werasc = 0xFF;
  1381.     newltchars.t_lnextc = 0xFF;        /* Literal next.    */
  1382.     if (ioctl(0, TIOCSLTC, (char *) &newltchars) < 0) {
  1383.         ewprintf("ttraw can't set ltchars");
  1384.         return(FALSE);
  1385.     }
  1386.     setttysize() ;
  1387.     return(TRUE);
  1388. }
  1389.  
  1390. /*
  1391.  * This function gets called just
  1392.  * before we go back home to the shell. Put all of
  1393.  * the terminal parameters back.
  1394.  *    Under UN*X this just calls ttcooked(), but the ttclose() hook is in
  1395.  * because vttidy() in display.c expects it for portability reasons.
  1396.  */
  1397. ttclose() {
  1398.     if (ttcooked() == FALSE)
  1399.         panic("");        /* ttcooked() already printf'd */
  1400. }
  1401.  
  1402. /*
  1403.  * This function restores all terminal settings to their default values,
  1404.  * in anticipation of exiting or suspending the editor.
  1405.  */
  1406.  
  1407. ttcooked() {
  1408.     ttflush();
  1409.     if (ioctl(0, TIOCSLTC, (char *) &oldltchars) < 0) {
  1410.         ewprintf("ttclose can't set ltchars");
  1411.         return(FALSE);
  1412.     }
  1413.     if (ioctl(0, TIOCSETC, (char *) &oldtchars) < 0) {
  1414.         ewprintf("ttclose can't set chars");
  1415.         return(FALSE);
  1416.     }
  1417.     if (ioctl(0, TIOCSETP, (char *) &oldtty) < 0) {
  1418.         ewprintf("ttclose can't set sgtty");
  1419.         return(FALSE);
  1420.     }
  1421.     return(TRUE);
  1422. }
  1423.  
  1424. /*
  1425.  * Write character to the display.
  1426.  * Characters are buffered up, to make things
  1427.  * a little bit more efficient.
  1428.  */
  1429. ttputc(c)
  1430. int c;
  1431. {
  1432.     if (nobuf >= NOBUF)
  1433.         ttflush();
  1434.     obuf[nobuf++] = c;
  1435. }
  1436.  
  1437. /*
  1438.  * Flush output.
  1439.  */
  1440. ttflush() {
  1441.     if (nobuf != 0) {
  1442.         if (write(1, obuf, nobuf) != nobuf)
  1443.             panic("ttflush write failed");
  1444.         nobuf = 0;
  1445.     }
  1446. }
  1447.  
  1448. /*
  1449.  * Read character from terminal.
  1450.  * All 8 bits are returned, so that you can use
  1451.  * a multi-national terminal.
  1452.  */
  1453. ttgetc() {
  1454.     char    buf[1];
  1455.  
  1456.     while (read(0, &buf[0], 1) != 1)
  1457.         ;
  1458.     return (buf[0] & 0xFF);
  1459. }
  1460. /*
  1461.  * set the tty size. Functionized for 43BSD.
  1462.  */
  1463. setttysize() {
  1464.  
  1465. #ifdef    TIOCGWINSZ
  1466.     if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
  1467.         nrow = winsize . ws_row;
  1468.         ncol = winsize . ws_col;
  1469.     } else nrow = 0;
  1470.     if(nrow<=0 || ncol<=0)
  1471. #endif
  1472.     if ((nrow=tgetnum ("li")) <= 0
  1473.     || (ncol=tgetnum ("co")) <= 0) {
  1474.         nrow = 24;
  1475.         ncol = 80;
  1476.     }
  1477.     if (nrow > NROW)            /* Don't crash if the    */
  1478.         nrow = NROW;            /* termcap entry is    */
  1479.     if (ncol > NCOL)            /* too big.        */
  1480.         ncol = NCOL;
  1481. }
  1482.  
  1483. /*
  1484.  * typeahead returns TRUE if there are characters available to be read
  1485.  * in.
  1486.  */
  1487. typeahead() {
  1488.     int    x;
  1489.  
  1490.     return((ioctl(0, FIONREAD, (char *) &x) < 0) ? 0 : x);
  1491. }
  1492.  
  1493. /*
  1494.  * panic - just exit, as quickly as we can.
  1495.  */
  1496. panic(s) char *s; {
  1497.     (void) fputs("panic: ", stderr);
  1498.     (void) fputs(s, stderr);
  1499.     (void) fputc('\n', stderr);
  1500.     (void) fflush(stderr);
  1501.     abort();        /* To leave a core image. */
  1502. }
  1503. #ifndef NO_DPROMPT
  1504. #include <sys/time.h>
  1505. /*
  1506.  * A program to return TRUE if we wait for 2 seconds without anything
  1507.  * happening, else return FALSE.  Cribbed from mod.sources xmodem.
  1508.  */
  1509. int ttwait() {
  1510.     int readfd;
  1511.     struct timeval tmout;
  1512.  
  1513.     tmout.tv_sec = 2;
  1514.     tmout.tv_usec = 0;
  1515.  
  1516.     readfd = 1;
  1517.  
  1518.     if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
  1519.         return(TRUE);
  1520.     return(FALSE);
  1521. }
  1522. #endif
  1523. SHAR_EOF
  1524. cat << \SHAR_EOF > sys/sysv/Makefile
  1525. # Makefile for MicroEMACS.
  1526. # Is there a better way to do the rebuilds, other than using
  1527. # the links?
  1528.  
  1529. SYS    = sysv
  1530. LIBS    = -lcurses
  1531. # CDEFS gets defines, and gets passed to lint. CFLAGS gets flags, and doesn't
  1532. # get passed to lint.
  1533. #
  1534. # (Common) compile-time options:
  1535. #
  1536. #    DO_METAKEY    -- if bit 7 is set for a key, treat like a META key
  1537. #    STARTUP        -- look for and handle initialization file
  1538. #    XKEYS        -- use termcap function key definitions. Warning -
  1539. #                XKEYS and bsmap mode do _not_ get along.
  1540. #    BACKUP        -- enable "make-backup-files"
  1541. #    PREFIXREGION    -- enable function "prefix-region"
  1542. #    REGEX        -- create regular expression functions
  1543. #
  1544. #CDEFS    =  -DDO_METAKEY
  1545. CDEFS    =  -DDO_METAKEY -DPREFIXREGION
  1546. CFLAGS    = -g $(CDEFS)
  1547.  
  1548. # Objects which only depend on the "standard" includes
  1549. OBJS    = basic.o dir.o dired.o file.o line.o match.o paragraph.o \
  1550.       random.o region.o search.o version.o window.o word.o
  1551.  
  1552. # Those with unique requirements
  1553. IND    = buffer.o display.o echo.o extend.o help.o kbd.o keymap.o \
  1554.       macro.o main.o modes.o regex.o re_search.o
  1555.  
  1556. # System dependent objects
  1557. OOBJS = cinfo.o spawn.o ttyio.o tty.o ttykbd.o
  1558.  
  1559. OBJ = $(OBJS) $(IND) $(OOBJS) fileio.o
  1560.  
  1561. OSRCS    = cinfo.c fileio.c spawn.c ttyio.c tty.c ttykbd.c
  1562. SRCS    = basic.c dir.c dired.c file.c line.c match.c paragraph.c \
  1563.       random.c region.c search.c version.c window.c word.c \
  1564.       buffer.c display.c echo.c extend.c help.c kbd.c keymap.c \
  1565.       macro.c main.c modes.c regex.c re_search.c
  1566.  
  1567. OINCS =    ttydef.h sysdef.h chrdef.h
  1568. INCS =    def.h
  1569.  
  1570. mg:    $(OBJ)
  1571.     cc $(CFLAGS) -o mg $(OBJ) $(LIBS)
  1572.  
  1573. # strip mg once you're satisfied it'll run -- makes it much smaller
  1574. strip:
  1575.     strip mg
  1576.  
  1577. lint: $(SRCS) $(OSRCS) $(INCS) $(OINCS)
  1578.     lint -ahbz $(CDEFS) $(SRCS) $(OSRCS)
  1579.  
  1580. $(OBJ):        $(INCS) $(OINCS)
  1581.  
  1582.  
  1583. dir.r search.o:    $(INCS) $(OINCS)
  1584.  
  1585. regex.o re_search.o:    $(INCS) $(OINCS) regex.h
  1586.  
  1587. kbd.o:    $(INCS) $(OINCS) macro.h kbd.h key.h
  1588.  
  1589. macro.o main.o:    $(INCS) $(OINCS) macro.h
  1590.  
  1591. buffer.o display.o keymap.o help.o modes.o dired.o fileio.o: \
  1592.     $(INCS) $(OINCS) kbd.h
  1593.  
  1594. extend.o:    $(INCS) $(OINCS) kbd.h macro.h key.h
  1595.  
  1596. help.o:    $(INCS) $(OINCS) kbd.h key.h macro.h
  1597.  
  1598. echo.o:    $(INCS) $(OINCS) key.h macro.h
  1599.  
  1600. $(OOBJS):    $(INCS) $(OINCS)
  1601.  
  1602. sysdef.h:    sys/$(SYS)/sysdef.h    # Update links, if needed.
  1603.     rm -f sysdef.h
  1604.     ln sys/$(SYS)/sysdef.h .
  1605.  
  1606. ttydef.h:    sys/default/ttydef.h
  1607.     rm -f ttydef.h
  1608.     ln sys/default/ttydef.h .
  1609.  
  1610. chrdef.h:    sys/default/chrdef.h
  1611.     rm -f chrdef.h
  1612.     ln sys/default/chrdef.h .
  1613.  
  1614. fileio.c:    sys/$(SYS)/fileio.c
  1615.     rm -f fileio.c
  1616.     ln sys/$(SYS)/fileio.c .
  1617.  
  1618. spawn.c:    sys/$(SYS)/spawn.c
  1619.     rm -f spawn.c
  1620.     ln sys/$(SYS)/spawn.c .
  1621.  
  1622. tty.c:        sys/default/tty.c
  1623.     rm -f tty.c
  1624.     ln sys/default/tty.c .
  1625.  
  1626. ttyio.c:    sys/$(SYS)/ttyio.c
  1627.     rm -f ttyio.c
  1628.     ln sys/$(SYS)/ttyio.c .
  1629.  
  1630. ttykbd.c:    sys/default/ttykbd.c
  1631.     rm -f ttykbd.c
  1632.     ln sys/default/ttykbd.c .
  1633.  
  1634. cinfo.c:    sys/default/cinfo.c
  1635.     rm -f cinfo.c
  1636.     ln sys/default/cinfo.c .
  1637.  
  1638. port: $(SRCS) $(INCS)
  1639.     rm -f port
  1640.     tar cfb port 1 $?
  1641.  
  1642. clean:;    rm -f $(OBJ) $(OSRCS) $(OINCS)
  1643. SHAR_EOF
  1644. cat << \SHAR_EOF > sys/sysv/fileio.c
  1645. /*
  1646.  *        sys V fileio.c
  1647.  */
  1648. #include    "def.h"
  1649.  
  1650. static    FILE    *ffp;
  1651. extern    char    *getenv();
  1652. char    *adjustname();
  1653.  
  1654. #include <sys/types.h>
  1655.  
  1656. /*
  1657.  * Open a file for reading.
  1658.  */
  1659. ffropen(fn) char *fn; {
  1660.     if ((ffp=fopen(fn, "r")) == NULL)
  1661.         return (FIOFNF);
  1662.     return (FIOSUC);
  1663. }
  1664.  
  1665. /*
  1666.  * Open a file for writing.
  1667.  * Return TRUE if all is well, and
  1668.  * FALSE on error (cannot create).
  1669.  */
  1670. ffwopen(fn) char *fn; {
  1671.     if ((ffp=fopen(fn, "w")) == NULL) {
  1672.         ewprintf("Cannot open file for writing");
  1673.         return (FIOERR);
  1674.     }
  1675.     return (FIOSUC);
  1676. }
  1677.  
  1678. /*
  1679.  * Close a file.
  1680.  * Should look at the status.
  1681.  */
  1682. ffclose() {
  1683.     (VOID) fclose(ffp);
  1684.     return (FIOSUC);
  1685. }
  1686.  
  1687. /*
  1688.  * Write a buffer to the already
  1689.  * opened file. bp points to the
  1690.  * buffer. Return the status.
  1691.  * Check only at the newline and
  1692.  * end of buffer.
  1693.  */
  1694. ffputbuf(bp)
  1695. BUFFER *bp;
  1696. {
  1697.     register char *cp;
  1698.     register char *cpend;
  1699.     register LINE *lp;
  1700.     register LINE *lpend;
  1701.  
  1702.     lpend = bp->b_linep;
  1703.     lp = lforw(lpend);
  1704.     do {
  1705.     cp = <ext(lp)[0];        /* begining of line    */
  1706.     cpend = &cp[llength(lp)];    /* end of line        */
  1707.     while(cp != cpend) {
  1708.         putc(*cp, ffp);
  1709.         cp++;    /* putc may evalualte arguments more than once */
  1710.     }
  1711.     lp = lforw(lp);
  1712.     if(lp == lpend) break;        /* no implied newline on last line */
  1713.     putc('\n', ffp);
  1714.     } while(!ferror(ffp));
  1715.     if(ferror(ffp)) {
  1716.     ewprintf("Write I/O error");
  1717.     return FIOERR;
  1718.     }
  1719.     return FIOSUC;
  1720. }
  1721.  
  1722. /*
  1723.  * Read a line from a file, and store the bytes
  1724.  * in the supplied buffer. Stop on end of file or end of
  1725.  * line.  When FIOEOF is returned, there is a valid line
  1726.  * of data without the normally implied \n.
  1727.  */
  1728. ffgetline(buf, nbuf, nbytes)
  1729. register char    *buf;
  1730. register int    nbuf;
  1731. register int    *nbytes;
  1732. {
  1733.     register int    c;
  1734.     register int    i;
  1735.  
  1736.     i = 0;
  1737.     while((c = getc(ffp))!=EOF && c!='\n') {
  1738.         buf[i++] = c;
  1739.         if (i >= nbuf) return FIOLONG;
  1740.     }
  1741.     if (c == EOF  && ferror(ffp) != FALSE) {
  1742.         ewprintf("File read error");
  1743.         return FIOERR;
  1744.     }
  1745.     *nbytes = i;
  1746.     return c==EOF ? FIOEOF : FIOSUC;
  1747. }
  1748.  
  1749. #ifndef NO_BACKUP
  1750. /*
  1751.  * Rename the file "fname" into a backup
  1752.  * copy. On Unix the backup has the same name as the
  1753.  * original file, with a "~" on the end; this seems to
  1754.  * be newest of the new-speak. The error handling is
  1755.  * all in "file.c". The "unlink" is perhaps not the
  1756.  * right thing here; I don't care that much as
  1757.  * I don't enable backups myself.
  1758.  */
  1759. fbackupfile(fn) char *fn; {
  1760.     register char    *nname;
  1761.     char        *malloc();
  1762.  
  1763.     if ((nname=malloc((unsigned)(strlen(fn)+1+1))) == NULL) {
  1764.         ewprintf("Can't get %d bytes", strlen(fn) + 1);
  1765.         return (ABORT);
  1766.     }
  1767.     (void) strcpy(nname, fn);
  1768.     (void) strcat(nname, "~");
  1769.     (void) unlink(nname);            /* Ignore errors.    */
  1770.     if (rename(fn, nname) < 0) {
  1771.         free(nname);
  1772.         return (FALSE);
  1773.     }
  1774.     free(nname);
  1775.     return (TRUE);
  1776. }
  1777. #endif
  1778.  
  1779. /*
  1780.  * The string "fn" is a file name.
  1781.  * Perform any required appending of directory name or case adjustments.
  1782.  * If NO_DIR is not defined, the same file should be refered to even if the
  1783.  * working directory changes.
  1784.  */
  1785. #ifdef SYMBLINK
  1786. #include <sys/types.h>
  1787. #include <sys/stat.h>
  1788. #ifndef MAXLINK
  1789. #define MAXLINK 8        /* maximum symbolic links to follow */
  1790. #endif
  1791. #endif
  1792. #include <pwd.h>
  1793. #ifndef NO_DIR
  1794. extern char *wdir;
  1795. #endif
  1796.  
  1797. char *adjustname(fn)
  1798. register char *fn;
  1799. {
  1800.     register char *cp;
  1801.     static char fnb[NFILEN];
  1802.     struct passwd *pwent;
  1803. #ifdef    SYMBLINK
  1804.     struct stat statbuf;
  1805.     int i, j;
  1806.     char linkbuf[NFILEN];
  1807. #endif
  1808.  
  1809.     switch(*fn) {
  1810.         case '/':
  1811.         cp = fnb;
  1812.         *cp++ = *fn++;
  1813.         break;
  1814.     case '~':
  1815.         fn++;
  1816.         if(*fn == '/' || *fn == '\0') {
  1817.         (VOID) strcpy(fnb, getenv("HOME"));
  1818.         cp = fnb + strlen(fnb);
  1819.             if(*fn) fn++;
  1820.         break;
  1821.         } else {
  1822.         cp = fnb;
  1823.         while(*fn && *fn != '/') *cp++ = *fn++;
  1824.         *cp = '\0';
  1825.         if((pwent = getpwnam(fnb)) != NULL) {
  1826.             (VOID) strcpy(fnb, pwent->pw_dir);
  1827.             cp = fnb + strlen(fnb);
  1828.             break;
  1829.         } else {
  1830.             fn -= strlen(fnb) + 1;
  1831.             /* can't find ~user, continue to default case */
  1832.         }
  1833.         }
  1834.     default:
  1835. #ifndef    NODIR
  1836.         strcpy(fnb, wdir);
  1837.         cp = fnb + strlen(fnb);
  1838.         break;
  1839. #else
  1840.         return fn;                /* punt */
  1841. #endif
  1842.     }
  1843.     if(cp != fnb && cp[-1] != '/') *cp++ = '/';
  1844.     while(*fn) {
  1845.         switch(*fn) {
  1846.         case '.':
  1847.         switch(fn[1]) {
  1848.                 case '\0':
  1849.                 *--cp = '\0';
  1850.                 return fnb;
  1851.                 case '/':
  1852.                     fn += 2;
  1853.                 continue;
  1854.             case '.':
  1855.                 if(fn[2]=='/' || fn[2] == '\0') {
  1856. #ifdef SYMBLINK
  1857.                 cp[-1] = '\0';
  1858.                 for(j = MAXLINK; j-- && 
  1859.                         lstat(fnb, &statbuf) != -1 && 
  1860.                         (statbuf.st_mode&S_IFMT) == S_IFLNK &&
  1861.                         (i = readlink(fnb, linkbuf, sizeof linkbuf))
  1862.                     != -1 ;) {
  1863.                 if(linkbuf[0] != '/') {
  1864.                     --cp;
  1865.                     while(cp > fnb && *--cp != '/') {}
  1866.                     ++cp;
  1867.                     (VOID) strncpy(cp, linkbuf, i);
  1868.                     cp += i;
  1869.                 } else {
  1870.                     (VOID) strncpy(fnb, linkbuf, i);
  1871.                     cp = fnb + i;
  1872.                 }
  1873.                 if(cp[-1]!='/') *cp++ = '\0';
  1874.                 else cp[-1] = '\0';
  1875.                 }
  1876.                 cp[-1] = '/';
  1877. #endif
  1878.                 --cp;
  1879.                 while(cp > fnb && *--cp != '/') {}
  1880.                 ++cp;
  1881.                 if(fn[2]=='\0') {
  1882.                     *--cp = '\0';
  1883.                     return fnb;
  1884.                 }
  1885.                     fn += 3;
  1886.                     continue;
  1887.                 }
  1888.                 break;
  1889.             default:
  1890.                 break;
  1891.             }
  1892.         break;
  1893.         case '/':
  1894.             fn++;
  1895.             continue;
  1896.         default:
  1897.             break;
  1898.     }
  1899.     while(*fn && (*cp++ = *fn++) != '/') {}
  1900.     }
  1901.     if(cp[-1]=='/') --cp;
  1902.     *cp = '\0';
  1903.     return fnb;
  1904. }
  1905.  
  1906. #ifndef NO_STARTUP
  1907. #include <sys/file.h>
  1908. #define F_OK 04            /* for stupid Sys V        */
  1909.  
  1910. /*
  1911.  * Find a startup file for the user and return its name. As a service
  1912.  * to other pieces of code that may want to find a startup file (like
  1913.  * the terminal driver in particular), accepts a suffix to be appended
  1914.  * to the startup file name.
  1915.  */
  1916. char *
  1917. startupfile(suffix)
  1918. char *suffix;
  1919. {
  1920.     register char    *file;
  1921.     static char    home[NFILEN];
  1922.     char        *getenv();
  1923.  
  1924.     if ((file = getenv("HOME")) == NULL) goto notfound;
  1925.     if (strlen(file)+7 >= NFILEN - 1) goto notfound;
  1926.     (VOID) strcpy(home, file);
  1927.     (VOID) strcat(home, "/.mg");
  1928.     if (suffix != NULL) {
  1929.         (VOID) strcat(home, "-");
  1930.         (VOID) strcat(home, suffix);
  1931.     }
  1932.     if (access(home, F_OK) == 0) return home;
  1933.  
  1934. notfound:
  1935. #ifdef    STARTUPFILE
  1936.     file = STARTUPFILE;
  1937.     if (suffix != NULL) {
  1938.         (VOID) strcpy(home, file);
  1939.         (VOID) strcat(home, "-");
  1940.         (VOID) strcat(home, suffix);
  1941.         file = home;
  1942.     }
  1943.     if (access(file, F_OK ) == 0) return file;
  1944. #endif
  1945.  
  1946.     return NULL;
  1947. }
  1948. #endif
  1949.  
  1950. #ifndef NO_DIRED
  1951. #include "kbd.h"
  1952.  
  1953. copy(frname, toname)
  1954. char *frname, *toname;
  1955. {
  1956.     int pid;
  1957.     int status;
  1958.  
  1959.     if(pid = fork()) {
  1960.     if(pid == -1)    return    -1;
  1961.     execl("/bin/cp", "cp", frname, toname, (char *)NULL);
  1962.     _exit(1);    /* shouldn't happen */
  1963.     }
  1964.     while(wait(&status) != pid)
  1965.     ;
  1966.     return status == 0;
  1967. }
  1968.  
  1969. BUFFER *dired_(dirname)
  1970. char *dirname;
  1971. {
  1972.     register BUFFER *bp;
  1973.     char line[256];
  1974.     BUFFER *findbuffer();
  1975.     FILE *dirpipe;
  1976.     FILE *popen();
  1977.     char *strncpy();
  1978.  
  1979.     if((dirname = adjustname(dirname)) == NULL) {
  1980.     ewprintf("Bad directory name");
  1981.     return NULL;
  1982.     }
  1983.     if((bp = findbuffer(dirname)) == NULL) {
  1984.     ewprintf("Could not create buffer");
  1985.     return NULL;
  1986.     }
  1987.     if(bclear(bp) != TRUE) return FALSE;
  1988.     (VOID) strcpy(line, "ls -al ");
  1989.     (VOID) strcpy(&line[7], dirname);
  1990.     if((dirpipe = popen(line, "r")) == NULL) {
  1991.     ewprintf("Problem opening pipe to ls");
  1992.     return NULL;
  1993.     }
  1994.     line[0] = line[1] = ' ';
  1995.     while(fgets(&line[2], 254, dirpipe) != NULL) {
  1996.     line[strlen(line) - 1] = '\0';        /* remove ^J    */
  1997.     (VOID) addline(bp, line);
  1998.     }
  1999.     if(pclose(dirpipe) == -1) {
  2000.     ewprintf("Problem closing pipe to ls");
  2001.     return NULL;
  2002.     }
  2003.     bp->b_dotp = lforw(bp->b_linep);        /* go to first line */
  2004.     (VOID) strncpy(bp->b_fname, dirname, NFILEN);
  2005.     if((bp->b_modes[0] = name_mode("dired")) == NULL) {
  2006.     bp->b_modes[0] = &map_table[0];
  2007.     ewprintf("Could not find mode dired");
  2008.     return NULL;
  2009.     }
  2010.     bp->b_nmodes = 0;
  2011.     return bp;
  2012. }
  2013.  
  2014. d_makename(lp, fn)
  2015. register LINE *lp;
  2016. register char *fn;
  2017. {
  2018.     register char *cp;
  2019.  
  2020.     if(llength(lp) <= 56) return ABORT;
  2021.     (VOID) strcpy(fn, curbp->b_fname);
  2022.     cp = fn + strlen(fn);
  2023.     bcopy(&lp->l_text[56], cp, llength(lp) - 56);
  2024.     cp[llength(lp) - 56] = '\0';
  2025.     return lgetc(lp, 2) == 'd';
  2026. }
  2027.  
  2028. /*
  2029.  * I, a System V novice, could only figure out how to do unlinkdir()
  2030.  * and rename() as exec's of the appropriate functions.  So sue me.
  2031.  * --Stephen Walton, December 1987
  2032.  */
  2033.  
  2034. unlinkdir(f)
  2035. char *f;
  2036. {
  2037.     int status, pid, wpid;
  2038.  
  2039.     if ((pid = fork()) == 0)
  2040.         execl("/bin/rmdir", "rmdir", f, (char *)NULL);
  2041.     else if (pid > 0)
  2042.         while ((wpid = wait(&status)) && wpid != pid)
  2043.             ;
  2044.     else
  2045.         return FALSE;
  2046.     return status == 0;
  2047. }
  2048.  
  2049. rename(f1, f2)
  2050. char *f1, *f2;
  2051. {
  2052.  
  2053.     int status, pid, wpid;
  2054.  
  2055.     if ((pid = fork()) == 0)
  2056.         execl("/bin/mv", "mv", f1, f2, (char *)NULL);
  2057.     else if (pid > 0)
  2058.         while ((wpid = wait(&status)) && wpid != pid)
  2059.             ;
  2060.     else
  2061.         return FALSE;
  2062.     return status == 0;
  2063. }
  2064. #endif NO_DIRED
  2065. SHAR_EOF
  2066. cat << \SHAR_EOF > sys/sysv/spawn.c
  2067. /*
  2068.  * Name:    MicroGnuEmacs
  2069.  *        Spawn CLI for System V.
  2070.  *
  2071.  * Spawn for System V.
  2072.  */
  2073. #include    "def.h"
  2074.  
  2075. #include    <signal.h>
  2076.  
  2077. char    *shellp    = NULL;            /* Saved "SHELL" program.    */
  2078. char    *shname = NULL;            /* Saved shell name        */
  2079.  
  2080. extern    char    *getenv();
  2081.  
  2082. /*
  2083.  * On System V, we no gots job control, so always run
  2084.  * a subshell using fork/exec. Bound to "C-C", and used
  2085.  * as a subcommand by "C-Z". (daveb)
  2086.  *
  2087.  * Returns 0 if the shell executed OK, something else if
  2088.  * we couldn't start shell or it exited badly.
  2089.  */
  2090. spawncli(f, n)
  2091. {
  2092.     extern char    *strrchr();
  2093.     register int    pid;
  2094.     register int    wpid;
  2095.     register int    (*oqsig)();
  2096.     register int    (*oisig)();
  2097.     int        status;
  2098.     int        errp = FALSE;
  2099.  
  2100.     if (shellp == NULL) {
  2101.         shellp = getenv("SHELL");
  2102.         if (shellp == NULL)
  2103.             shellp = getenv("shell");
  2104.         if (shellp == NULL)
  2105.             shellp = "/bin/sh";    /* Safer.        */
  2106.         shname = strrchr( shellp, '/' ); 
  2107.         shname = shname ? shname++ : shellp;
  2108.         
  2109.     }
  2110.     ttcolor(CTEXT);
  2111.     ttnowindow();
  2112.     ttmove(nrow-1, 0);
  2113.     if (epresf != FALSE) {
  2114.         tteeol();
  2115.         epresf = FALSE;
  2116.     }
  2117.     ttclose();
  2118.     sgarbf = TRUE;                /* Force repaint.    */
  2119.     oqsig = signal(SIGQUIT, SIG_IGN);
  2120.     oisig = signal(SIGINT,  SIG_IGN);
  2121.     if ((pid=fork()) == 0) {
  2122.         (void) signal(SIGINT, oisig);
  2123.         (void) signal(SIGQUIT, oqsig);
  2124.         execlp(shellp, shname, "-i", (char *)NULL);
  2125.         _exit(1);            /* Should do better!    */
  2126.     }
  2127.     else if (pid > 0) {
  2128.         while ((wpid=wait(&status))>=0 && wpid!=pid)
  2129.             ;
  2130.     }
  2131.     else errp = TRUE;
  2132.  
  2133.     signal(SIGINT,  oisig);
  2134.     signal(SIGQUIT, oqsig);
  2135.     ttopen();
  2136.     if(errp)
  2137.         ewprintf("Failed to create process");
  2138.  
  2139.     return ( errp | status );
  2140. }
  2141. SHAR_EOF
  2142. cat << \SHAR_EOF > sys/sysv/sysdef.h
  2143. /*
  2144.  *        System V system header file
  2145.  */
  2146. #include <stdio.h>
  2147.  
  2148. #define    KBLOCK    8192            /* Kill grow.            */
  2149. #define    GOOD    0            /* Good exit status.        */
  2150. #define    MAXPATH    256            /* Maximum length of path for chdir */
  2151.  
  2152. typedef long    RSIZE;            /* Type for file/region sizes    */
  2153. typedef short    KCHAR;            /* Type for internal keystrokes    */
  2154.  
  2155. /*
  2156.  * Macros used by the buffer name making code.
  2157.  * Start at the end of the file name, scan to the left
  2158.  * until BDC1 (or BDC2, if defined) is reached. The buffer
  2159.  * name starts just to the right of that location, and
  2160.  * stops at end of string (or at the next BDC3 character,
  2161.  * if defined). BDC2 and BDC3 are mainly for VMS.
  2162.  */
  2163. #define    BDC1    '/'            /* Buffer names.        */
  2164.  
  2165. #define MALLOCROUND(m)    (m+=7,m&=~7)    /* round up to 8 byte boundry    */
  2166.  
  2167. #define    fncmp        strcmp        /* file name comparison        */
  2168. #define bcopy(s,d,n)    memcpy(d,s,n)    /* memory-to-memory copy    */
  2169. char *getenv();
  2170. #define    gettermtype()    getenv("TERM")    /* determine terminal type    */
  2171. char *getcwd();
  2172. #define getwd(cwd)    getcwd(cwd,NFILEN) /* get current working dir    */
  2173. SHAR_EOF
  2174. cat << \SHAR_EOF > sys/sysv/ttyio.c
  2175. /*
  2176.  * Name:    MicroEMACS
  2177.  *        System V terminal I/O.
  2178.  * Version:    0
  2179.  * Last edit:    Tue Aug 26 23:57:57 PDT 1986
  2180.  * By:        gonzo!daveb
  2181.  *        {sun, amdahl, mtxinu}!rtech!gonzo!daveb
  2182.  *
  2183.  * The functions in this file
  2184.  * negotiate with the operating system for
  2185.  * keyboard characters, and write characters to
  2186.  * the display in a barely buffered fashion.
  2187.  *
  2188.  * This version goes along with tty/termcap/tty.c.
  2189.  * Terminal size is determined there, rather than here, and
  2190.  * this does not open the termcap file
  2191.  */
  2192. #include    "def.h"
  2193.  
  2194. #include    <sys/types.h>
  2195. #include    <fcntl.h>
  2196. #include    <termio.h>
  2197.  
  2198. #define    NOBUF    512            /* Output buffer size.        */
  2199.  
  2200. char    obuf[NOBUF];            /* Output buffer.        */
  2201. int    nobuf;                /* buffer count            */
  2202.  
  2203. static struct termio    ot;        /* entry state of the terminal    */
  2204. static struct termio    nt;        /* editor's terminal state    */
  2205.  
  2206. static int ttyactivep = FALSE;        /* terminal in editor mode?    */
  2207. static int ttysavedp = FALSE;        /* terminal state saved?    */
  2208.  
  2209. int    nrow;                /* Terminal size, rows.        */
  2210. int    ncol;                /* Terminal size, columns.    */
  2211.  
  2212. /* These are used to implement typeahead on System V */
  2213.  
  2214. int kbdflgs;            /* saved keyboard fd flags    */
  2215. int kbdpoll;            /* in O_NDELAY mode            */
  2216. int kbdqp;            /* there is a char in kbdq    */
  2217. char kbdq;            /* char we've already read    */
  2218.  
  2219. /*
  2220.  * This function gets called once, to set up
  2221.  * the terminal channel.  This version turns off flow
  2222.  * control.  This may be wrong for your system, but no
  2223.  * good solution has really been found (daveb).
  2224.  */
  2225. ttopen()
  2226. {
  2227.     register char    *cp;
  2228.     extern char    *getenv();
  2229.  
  2230.     if (ttyactivep)
  2231.         return;
  2232.  
  2233.     if( !ttysavedp )
  2234.     {
  2235.         if (ioctl(0, TCGETA, &ot) < 0)
  2236.             abort();
  2237.         nt = ot;        /* save entry state        */
  2238.         nt.c_cc[VMIN] = 1;    /* one character read is OK    */
  2239.         nt.c_cc[VTIME] = 0;    /* Never time out.        */
  2240.         nt.c_iflag |= IGNBRK;
  2241.         nt.c_iflag &= ~( ICRNL | INLCR | ISTRIP | IXON | IXOFF );
  2242.         nt.c_oflag &= ~OPOST;
  2243.         nt.c_cflag |= CS8;    /* allow 8th bit on input    */
  2244.         nt.c_cflag &= ~PARENB;    /* Don't check parity        */
  2245.         nt.c_lflag &= ~( ECHO | ICANON | ISIG );
  2246.  
  2247.         kbdpoll = (((kbdflgs = fcntl(0, F_GETFL, 0)) & O_NDELAY) != 0);
  2248.     
  2249.         ttysavedp = TRUE;
  2250.     }
  2251.     
  2252.     if (ioctl(0, TCSETAF, &nt) < 0)
  2253.         abort();
  2254.  
  2255.     /* This really belongs in tty/termcap... */
  2256.  
  2257.     if ((cp=getenv("TERMCAP")) == NULL
  2258.     || (nrow=getvalue(cp, "li")) <= 0
  2259.     || (ncol=getvalue(cp, "co")) <= 0) {
  2260.         nrow = 24;
  2261.         ncol = 80;
  2262.     }
  2263.     if (nrow > NROW)            /* Don't crash if the    */
  2264.         nrow = NROW;            /* termcap entry is    */
  2265.     if (ncol > NCOL)            /* too big.        */
  2266.         ncol = NCOL;
  2267.  
  2268.     ttyactivep = TRUE;
  2269. }
  2270.  
  2271. /*
  2272.  * This routine scans a string, which is
  2273.  * actually the return value of a getenv call for the TERMCAP
  2274.  * variable, looking for numeric parameter "name". Return the value
  2275.  * if found. Return -1 if not there. Assume that "name" is 2
  2276.  * characters long. This limited use of the TERMCAP lets us find
  2277.  * out the size of a window on the X display.
  2278.  */
  2279. getvalue(cp, name)
  2280. register char    *cp;
  2281. register char    *name;
  2282. {
  2283.     for (;;) {
  2284.         while (*cp!=0 && *cp!=':')
  2285.             ++cp;
  2286.         if (*cp++ == 0)            /* Not found.        */
  2287.             return (-1);
  2288.         if (cp[0]==name[0] && cp[1]==name[1] && cp[2]=='#')
  2289.             return (atoi(cp+3));    /* Stops on ":".    */
  2290.     }
  2291. }
  2292.  
  2293. /*
  2294.  * This function gets called just
  2295.  * before we go back home to the shell. Put all of
  2296.  * the terminal parameters back.
  2297.  */
  2298. ttclose()
  2299. {
  2300.     if(!ttysavedp || !ttyactivep)
  2301.         return;
  2302.     ttflush();
  2303.     if (ioctl(0, TCSETAF, &ot) < 0 || fcntl( 0, F_SETFL, kbdflgs ) < 0)
  2304.         abort();
  2305.     ttyactivep = FALSE;
  2306. }
  2307.  
  2308. /*
  2309.  * Write character to the display.
  2310.  * Characters are buffered up, to make things
  2311.  * a little bit more efficient.
  2312.  */
  2313. ttputc(c)
  2314. {
  2315.     if (nobuf >= NOBUF)
  2316.         ttflush();
  2317.     obuf[nobuf++] = c;
  2318. }
  2319.  
  2320. /*
  2321.  * Flush output.
  2322.  */
  2323. ttflush()
  2324. {
  2325.     if (nobuf != 0) {
  2326.         write(1, obuf, nobuf);
  2327.         nobuf = 0;
  2328.     }
  2329. }
  2330.  
  2331. /*
  2332.  * Read character from terminal.
  2333.  * All 8 bits are returned, so that you can use
  2334.  * a multi-national terminal.
  2335.  *
  2336.  * If keyboard 'queue' already has typeahead from a typeahead() call,
  2337.  * just return it.  Otherwise, make sure we are in blocking i/o mode
  2338.  * and read a character.
  2339.  */
  2340. ttgetc()
  2341. {
  2342.     if( kbdqp )
  2343.         kbdqp = FALSE;
  2344.     else
  2345.     {
  2346.         if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
  2347.             abort();
  2348.         kbdpoll = FALSE;
  2349.         while (read(0, &kbdq, 1) != 1)
  2350.             ;
  2351.     }
  2352.     return ( kbdq & 0xff );
  2353. }
  2354.  
  2355. /*
  2356.  * Return non-FALSE if typeahead is pending.
  2357.  *
  2358.  * If already got unread typeahead, do nothing.
  2359.  * Otherwise, set keyboard to O_NDELAY if not already, and try
  2360.  * a one character read.
  2361.  */
  2362. typeahead()
  2363. {
  2364.     if( !kbdqp )
  2365.     {
  2366.         if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
  2367.             abort();
  2368.         kbdpoll = TRUE;
  2369.         kbdqp = (1 == read( 0, &kbdq, 1 ));
  2370.     }
  2371.     return ( kbdqp );
  2372. }
  2373.  
  2374.  
  2375. /*
  2376.  * panic:  print error and die, leaving core file.
  2377.  * Don't know why this is needed (daveb).
  2378.  */
  2379. panic(s)
  2380. char *s;
  2381. {
  2382.     fprintf(stderr, "%s\r\n", s);
  2383.     abort();
  2384. }
  2385.  
  2386.  
  2387. /*
  2388. ** This should check the size of the window, and reset if needed.
  2389. */
  2390.  
  2391. setttysize()
  2392. {
  2393. #ifdef    TIOCGWINSZ
  2394.     if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
  2395.         nrow = winsize . ws_row;
  2396.         ncol = winsize . ws_col;
  2397.     } else
  2398. #endif
  2399.     if ((nrow=tgetnum ("li")) <= 0
  2400.     || (ncol=tgetnum ("co")) <= 0) {
  2401.         nrow = 24;
  2402.         ncol = 80;
  2403.     }
  2404.     if (nrow > NROW)            /* Don't crash if the    */
  2405.         nrow = NROW;            /* termcap entry is    */
  2406.     if (ncol > NCOL)            /* too big.        */
  2407.         ncol = NCOL;
  2408. }
  2409.  
  2410. #ifndef NO_DPROMPT
  2411. #include <signal.h>
  2412. #include <setjmp.h>
  2413.  
  2414. static jmp_buf tohere;
  2415.  
  2416. static alrm()
  2417. {
  2418.     longjmp(tohere, -1);
  2419. }
  2420.  
  2421. /*
  2422.  * Return TRUE if we wait without doing anything, else return FALSE.
  2423.  */
  2424.  
  2425. ttwait()
  2426. {
  2427.     int alrm();
  2428.  
  2429.     if (kbdqp)
  2430.         return FALSE;        /* already pending input    */
  2431.     if (setjmp(tohere))
  2432.         return TRUE;        /* timeout on read if here    */
  2433.     signal(SIGALRM, alrm); alarm(2);
  2434.     kbdqp = (1 == read(0, &kbdq, 1));
  2435.     alarm(0);
  2436.     return FALSE;            /* successful read if here    */
  2437. }
  2438. #endif NO_DPROMPT
  2439. SHAR_EOF
  2440. #    End of shell archive
  2441. exit 0
  2442. -------
  2443.