home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / uemacs3.7 / part10 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  36.0 KB

  1. Subject: v06i080:  MicroEmacs, Version 3.7 (uEmacs3.7), Part10/12
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: ihnp4!pur-ee!pur-phy!duncan!lawrence
  6. Mod.sources: Volume 6, Issue 80
  7. Archive-name: uEmacs3.7/Part10
  8.  
  9. [  This is the latest revision of one of two programs named "MicroEmacs";
  10.    when discussing these on the net, or in contacting the authors, make
  11.    sure to mention the version number -- in this case 3.7 -- as that is
  12.    the easiest way to distinguish between them.  Daniel will be posting
  13.    uuencoded executables in net.micro.pc and net.micro.amiga; the file
  14.    'readme' contains information on how to also get these from him
  15.    directly.   --r$ ]
  16.  
  17. echo extracting - region.c
  18. sed 's/^X//' > region.c << 'FRIDAY_NIGHT'
  19. X/*
  20. X * The routines in this file
  21. X * deal with the region, that magic space
  22. X * between "." and mark. Some functions are
  23. X * commands. Some functions are just for
  24. X * internal use.
  25. X */
  26. X#include        <stdio.h>
  27. X#include    "estruct.h"
  28. X#include        "edef.h"
  29. X
  30. X/*
  31. X * Kill the region. Ask "getregion"
  32. X * to figure out the bounds of the region.
  33. X * Move "." to the start, and kill the characters.
  34. X * Bound to "C-W".
  35. X */
  36. Xkillregion(f, n)
  37. X{
  38. X        register int    s;
  39. X        REGION          region;
  40. X
  41. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  42. X        return(rdonly());    /* we are in read only mode    */
  43. X        if ((s=getregion(®ion)) != TRUE)
  44. X                return (s);
  45. X        if ((lastflag&CFKILL) == 0)             /* This is a kill type  */
  46. X                kdelete();                      /* command, so do magic */
  47. X        thisflag |= CFKILL;                     /* kill buffer stuff.   */
  48. X        curwp->w_dotp = region.r_linep;
  49. X        curwp->w_doto = region.r_offset;
  50. X        return (ldelete(region.r_size, TRUE));
  51. X}
  52. X
  53. X/*
  54. X * Copy all of the characters in the
  55. X * region to the kill buffer. Don't move dot
  56. X * at all. This is a bit like a kill region followed
  57. X * by a yank. Bound to "M-W".
  58. X */
  59. Xcopyregion(f, n)
  60. X{
  61. X        register LINE   *linep;
  62. X        register int    loffs;
  63. X        register int    s;
  64. X        REGION          region;
  65. X
  66. X        if ((s=getregion(®ion)) != TRUE)
  67. X                return (s);
  68. X        if ((lastflag&CFKILL) == 0)             /* Kill type command.   */
  69. X                kdelete();
  70. X        thisflag |= CFKILL;
  71. X        linep = region.r_linep;                 /* Current line.        */
  72. X        loffs = region.r_offset;                /* Current offset.      */
  73. X        while (region.r_size--) {
  74. X                if (loffs == llength(linep)) {  /* End of line.         */
  75. X                        if ((s=kinsert('\n')) != TRUE)
  76. X                                return (s);
  77. X                        linep = lforw(linep);
  78. X                        loffs = 0;
  79. X                } else {                        /* Middle of line.      */
  80. X                        if ((s=kinsert(lgetc(linep, loffs))) != TRUE)
  81. X                                return (s);
  82. X                        ++loffs;
  83. X                }
  84. X        }
  85. X        return (TRUE);
  86. X}
  87. X
  88. X/*
  89. X * Lower case region. Zap all of the upper
  90. X * case characters in the region to lower case. Use
  91. X * the region code to set the limits. Scan the buffer,
  92. X * doing the changes. Call "lchange" to ensure that
  93. X * redisplay is done in all buffers. Bound to
  94. X * "C-X C-L".
  95. X */
  96. Xlowerregion(f, n)
  97. X{
  98. X        register LINE   *linep;
  99. X        register int    loffs;
  100. X        register int    c;
  101. X        register int    s;
  102. X        REGION          region;
  103. X
  104. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  105. X        return(rdonly());    /* we are in read only mode    */
  106. X        if ((s=getregion(®ion)) != TRUE)
  107. X                return (s);
  108. X        lchange(WFHARD);
  109. X        linep = region.r_linep;
  110. X        loffs = region.r_offset;
  111. X        while (region.r_size--) {
  112. X                if (loffs == llength(linep)) {
  113. X                        linep = lforw(linep);
  114. X                        loffs = 0;
  115. X                } else {
  116. X                        c = lgetc(linep, loffs);
  117. X                        if (c>='A' && c<='Z')
  118. X                                lputc(linep, loffs, c+'a'-'A');
  119. X                        ++loffs;
  120. X                }
  121. X        }
  122. X        return (TRUE);
  123. X}
  124. X
  125. X/*
  126. X * Upper case region. Zap all of the lower
  127. X * case characters in the region to upper case. Use
  128. X * the region code to set the limits. Scan the buffer,
  129. X * doing the changes. Call "lchange" to ensure that
  130. X * redisplay is done in all buffers. Bound to
  131. X * "C-X C-L".
  132. X */
  133. Xupperregion(f, n)
  134. X{
  135. X        register LINE   *linep;
  136. X        register int    loffs;
  137. X        register int    c;
  138. X        register int    s;
  139. X        REGION          region;
  140. X
  141. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  142. X        return(rdonly());    /* we are in read only mode    */
  143. X        if ((s=getregion(®ion)) != TRUE)
  144. X                return (s);
  145. X        lchange(WFHARD);
  146. X        linep = region.r_linep;
  147. X        loffs = region.r_offset;
  148. X        while (region.r_size--) {
  149. X                if (loffs == llength(linep)) {
  150. X                        linep = lforw(linep);
  151. X                        loffs = 0;
  152. X                } else {
  153. X                        c = lgetc(linep, loffs);
  154. X                        if (c>='a' && c<='z')
  155. X                                lputc(linep, loffs, c-'a'+'A');
  156. X                        ++loffs;
  157. X                }
  158. X        }
  159. X        return (TRUE);
  160. X}
  161. X
  162. X/*
  163. X * This routine figures out the
  164. X * bounds of the region in the current window, and
  165. X * fills in the fields of the "REGION" structure pointed
  166. X * to by "rp". Because the dot and mark are usually very
  167. X * close together, we scan outward from dot looking for
  168. X * mark. This should save time. Return a standard code.
  169. X * Callers of this routine should be prepared to get
  170. X * an "ABORT" status; we might make this have the
  171. X * conform thing later.
  172. X */
  173. Xgetregion(rp)
  174. Xregister REGION *rp;
  175. X{
  176. X        register LINE   *flp;
  177. X        register LINE   *blp;
  178. X        long fsize;
  179. X        long bsize;
  180. X
  181. X        if (curwp->w_markp == NULL) {
  182. X                mlwrite("No mark set in this window");
  183. X                return (FALSE);
  184. X        }
  185. X        if (curwp->w_dotp == curwp->w_markp) {
  186. X                rp->r_linep = curwp->w_dotp;
  187. X                if (curwp->w_doto < curwp->w_marko) {
  188. X                        rp->r_offset = curwp->w_doto;
  189. X                        rp->r_size = (long)(curwp->w_marko-curwp->w_doto);
  190. X                } else {
  191. X                        rp->r_offset = curwp->w_marko;
  192. X                        rp->r_size = (long)(curwp->w_doto-curwp->w_marko);
  193. X                }
  194. X                return (TRUE);
  195. X        }
  196. X        blp = curwp->w_dotp;
  197. X        bsize = (long)curwp->w_doto;
  198. X        flp = curwp->w_dotp;
  199. X        fsize = (long)(llength(flp)-curwp->w_doto+1);
  200. X        while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
  201. X                if (flp != curbp->b_linep) {
  202. X                        flp = lforw(flp);
  203. X                        if (flp == curwp->w_markp) {
  204. X                                rp->r_linep = curwp->w_dotp;
  205. X                                rp->r_offset = curwp->w_doto;
  206. X                                rp->r_size = fsize+curwp->w_marko;
  207. X                                return (TRUE);
  208. X                        }
  209. X                        fsize += llength(flp)+1;
  210. X                }
  211. X                if (lback(blp) != curbp->b_linep) {
  212. X                        blp = lback(blp);
  213. X                        bsize += llength(blp)+1;
  214. X                        if (blp == curwp->w_markp) {
  215. X                                rp->r_linep = blp;
  216. X                                rp->r_offset = curwp->w_marko;
  217. X                                rp->r_size = bsize - curwp->w_marko;
  218. X                                return (TRUE);
  219. X                        }
  220. X                }
  221. X        }
  222. X        mlwrite("Bug: lost mark");
  223. X        return (FALSE);
  224. X}
  225. FRIDAY_NIGHT
  226. echo extracting - search.c
  227. sed 's/^X//' > search.c << 'FRIDAY_NIGHT'
  228. X/*
  229. X * The functions in this file implement commands that search in the forward
  230. X * and backward directions. There are no special characters in the search
  231. X * strings. Probably should have a regular expression search, or something
  232. X * like that.
  233. X *
  234. X */
  235. X
  236. X#include        <stdio.h>
  237. X#include    "estruct.h"
  238. X#include        "edef.h"
  239. X
  240. X/*
  241. X * Search forward. Get a search string from the user, and search, beginning at
  242. X * ".", for the string. If found, reset the "." to be just after the match
  243. X * string, and [perhaps] repaint the display. Bound to "C-S".
  244. X */
  245. X
  246. X/*    string search input parameters    */
  247. X
  248. X#define    PTBEG    1    /* leave the point at the begining on search */
  249. X#define    PTEND    2    /* leave the point at the end on search */
  250. X
  251. Xforwsearch(f, n)
  252. X
  253. X{
  254. X    register int status;
  255. X
  256. X    /* resolve the repeat count */
  257. X    if (n == 0)
  258. X        n = 1;
  259. X    if (n < 1)    /* search backwards */
  260. X        return(backsearch(f, -n));
  261. X
  262. X    /* ask the user for the text of a pattern */
  263. X    if ((status = readpattern("Search")) != TRUE)
  264. X        return(status);
  265. X
  266. X    /* search for the pattern */
  267. X    while (n-- > 0) {
  268. X        if ((status = forscan(&pat[0],PTEND)) == FALSE)
  269. X            break;
  270. X    }
  271. X
  272. X    /* and complain if not there */
  273. X    if (status == FALSE)
  274. X        mlwrite("Not found");
  275. X    return(status);
  276. X}
  277. X
  278. Xforwhunt(f, n)
  279. X
  280. X{
  281. X    register int status;
  282. X
  283. X    /* resolve the repeat count */
  284. X    if (n == 0)
  285. X        n = 1;
  286. X    if (n < 1)    /* search backwards */
  287. X        return(backhunt(f, -n));
  288. X
  289. X    /* Make sure a pattern exists */
  290. X    if (pat[0] == 0) {
  291. X        mlwrite("No pattern set");
  292. X        return(FALSE);
  293. X    }
  294. X
  295. X    /* search for the pattern */
  296. X    while (n-- > 0) {
  297. X        if ((status = forscan(&pat[0],PTEND)) == FALSE)
  298. X            break;
  299. X    }
  300. X
  301. X    /* and complain if not there */
  302. X    if (status == FALSE)
  303. X        mlwrite("Not found");
  304. X    return(status);
  305. X}
  306. X
  307. X/*
  308. X * Reverse search. Get a search string from the user, and search, starting at
  309. X * "." and proceeding toward the front of the buffer. If found "." is left
  310. X * pointing at the first character of the pattern [the last character that was
  311. X * matched]. Bound to "C-R".
  312. X */
  313. Xbacksearch(f, n)
  314. X
  315. X{
  316. X    register int s;
  317. X
  318. X    /* resolve null and negative arguments */
  319. X    if (n == 0)
  320. X        n = 1;
  321. X    if (n < 1)
  322. X        return(forwsearch(f, -n));
  323. X
  324. X    /* get a pattern to search */
  325. X    if ((s = readpattern("Reverse search")) != TRUE)
  326. X        return(s);
  327. X
  328. X    /* and go search for it */
  329. X    bsearch(f,n);
  330. X    return(TRUE);
  331. X}
  332. X
  333. Xbackhunt(f, n)    /* hunt backward for the last search string entered */
  334. X
  335. X{
  336. X    /* resolve null and negative arguments */
  337. X    if (n == 0)
  338. X        n = 1;
  339. X    if (n < 1)
  340. X        return(forwhunt(f, -n));
  341. X
  342. X    /* Make sure a pattern exists */
  343. X    if (pat[0] == 0) {
  344. X        mlwrite("No pattern set");
  345. X        return(FALSE);
  346. X    }
  347. X
  348. X    /* and go search for it */
  349. X    bsearch(f,n);
  350. X    return(TRUE);
  351. X}
  352. X
  353. Xbsearch(f, n)
  354. X
  355. X{
  356. X    register LINE *clp;
  357. X    register int cbo;
  358. X    register LINE *tlp;
  359. X    register int tbo;
  360. X    register int c;
  361. X    register char *epp;
  362. X    register char *pp;
  363. X
  364. X    /* find a pointer to the end of the pattern */
  365. X    for (epp = &pat[0]; epp[1] != 0; ++epp)
  366. X        ;
  367. X
  368. X    /* make local copies of the starting location */
  369. X    clp = curwp->w_dotp;
  370. X    cbo = curwp->w_doto;
  371. X
  372. X    while (n-- > 0) {
  373. X        for (;;) {
  374. X            /* if we are at the begining of the line, wrap back around */
  375. X            if (cbo == 0) {
  376. X                clp = lback(clp);
  377. X
  378. X                if (clp == curbp->b_linep) {
  379. X                    mlwrite("Not found");
  380. X                    return(FALSE);
  381. X                }
  382. X
  383. X                cbo = llength(clp)+1;
  384. X            }
  385. X
  386. X            /* fake the <NL> at the end of a line */
  387. X            if (--cbo == llength(clp))
  388. X                c = '\n';
  389. X            else
  390. X                c = lgetc(clp, cbo);
  391. X
  392. X            /* check for a match against the end of the pattern */
  393. X            if (eq(c, *epp) != FALSE) {
  394. X                tlp = clp;
  395. X                tbo = cbo;
  396. X                pp  = epp;
  397. X
  398. X                /* scanning backwards through the rest of the
  399. X                   pattern looking for a match            */
  400. X                while (pp != &pat[0]) {
  401. X                    /* wrap across a line break */
  402. X                    if (tbo == 0) {
  403. X                        tlp = lback(tlp);
  404. X                        if (tlp == curbp->b_linep)
  405. X                            goto fail;
  406. X
  407. X                        tbo = llength(tlp)+1;
  408. X                    }
  409. X
  410. X                    /* fake the <NL> */
  411. X                    if (--tbo == llength(tlp))
  412. X                        c = '\n';
  413. X                    else
  414. X                        c = lgetc(tlp, tbo);
  415. X
  416. X                    if (eq(c, *--pp) == FALSE)
  417. X                        goto fail;
  418. X                }
  419. X
  420. X                /* A Match!  reset the current cursor */
  421. X                curwp->w_dotp  = tlp;
  422. X                curwp->w_doto  = tbo;
  423. X                curwp->w_flag |= WFMOVE;
  424. X                goto next;
  425. X            }
  426. Xfail:;
  427. X        }
  428. Xnext:;
  429. X    }
  430. X    return(TRUE);
  431. X}
  432. X
  433. X/*
  434. X * Compare two characters. The "bc" comes from the buffer. It has it's case
  435. X * folded out. The "pc" is from the pattern.
  436. X */
  437. Xeq(bc, pc)
  438. X    int bc;
  439. X    int pc;
  440. X
  441. X{
  442. X    if ((curwp->w_bufp->b_mode & MDEXACT) == 0) {
  443. X        if (bc>='a' && bc<='z')
  444. X            bc -= 0x20;
  445. X
  446. X        if (pc>='a' && pc<='z')
  447. X            pc -= 0x20;
  448. X    }
  449. X
  450. X    if (bc == pc)
  451. X        return(TRUE);
  452. X
  453. X    return(FALSE);
  454. X}
  455. X
  456. X/*
  457. X * Read a pattern. Stash it in the external variable "pat". The "pat" is not
  458. X * updated if the user types in an empty line. If the user typed an empty line,
  459. X * and there is no old pattern, it is an error. Display the old pattern, in the
  460. X * style of Jeff Lomicka. There is some do-it-yourself control expansion.
  461. X * change to using <ESC> to delemit the end-of-pattern to allow <NL>s in
  462. X * the search string.
  463. X */
  464. Xreadpattern(prompt)
  465. X
  466. Xchar *prompt;
  467. X
  468. X{
  469. X    register int s;
  470. X    char tpat[NPAT+20];
  471. X
  472. X    strcpy(tpat, prompt);    /* copy prompt to output string */
  473. X    strcat(tpat, " [");    /* build new prompt string */
  474. X    expandp(&pat[0], &tpat[strlen(tpat)], NPAT/2);    /* add old pattern */
  475. X    strcat(tpat, "]<ESC>: ");
  476. X
  477. X    s = mlreplyt(tpat, tpat, NPAT, 27);    /* Read pattern */
  478. X
  479. X    if (s == TRUE)                /* Specified */
  480. X        strcpy(pat, tpat);
  481. X    else if (s == FALSE && pat[0] != 0)    /* CR, but old one */
  482. X        s = TRUE;
  483. X
  484. X    return(s);
  485. X}
  486. X
  487. Xsreplace(f, n)    /*    Search and replace (ESC-R)    */
  488. X
  489. Xint f;        /* default flag */
  490. Xint n;        /* # of repetitions wanted */
  491. X
  492. X{
  493. X    return(replaces(FALSE, f, n));
  494. X}
  495. X
  496. Xqreplace(f, n)    /*    search and replace with query (ESC-CTRL-R)    */
  497. X
  498. Xint f;        /* default flag */
  499. Xint n;        /* # of repetitions wanted */
  500. X
  501. X{
  502. X    return(replaces(TRUE, f, n));
  503. X}
  504. X
  505. X/*    replaces:    search for a string and replace it with another
  506. X            string. query might be enabled (according to
  507. X            kind).                        */
  508. Xreplaces(kind, f, n)
  509. X
  510. Xint kind;    /* Query enabled flag */
  511. Xint f;        /* default flag */
  512. Xint n;        /* # of repetitions wanted */
  513. X
  514. X{
  515. X    register int i;        /* loop index */
  516. X    register int s;        /* success flag on pattern inputs */
  517. X    register int slength,
  518. X             rlength;    /* length of search and replace strings */
  519. X    register int numsub;    /* number of substitutions */
  520. X    register int nummatch;    /* number of found matches */
  521. X    int nlflag;        /* last char of search string a <NL>? */
  522. X    int nlrepl;        /* was a replace done on the last line? */
  523. X    char tmpc;        /* temporary character */
  524. X    char c;            /* input char for query */
  525. X    char tpat[NPAT];    /* temporary to hold search pattern */
  526. X    LINE *origline;        /* original "." position */
  527. X    int origoff;        /* and offset (for . query option) */
  528. X    LINE *lastline;        /* position of last replace and */
  529. X    int lastoff;        /* offset (for 'u' query option) */
  530. X
  531. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  532. X        return(rdonly());    /* we are in read only mode    */
  533. X
  534. X    /* check for negative repititions */
  535. X    if (f && n < 0)
  536. X        return(FALSE);
  537. X
  538. X    /* ask the user for the text of a pattern */
  539. X    if ((s = readpattern(
  540. X        (kind == FALSE ? "Replace" : "Query replace"))) != TRUE)
  541. X        return(s);
  542. X    strcpy(&tpat[0], &pat[0]);    /* salt it away */
  543. X
  544. X    /* ask for the replacement string */
  545. X    strcpy(&pat[0], &rpat[0]);    /* set up default string */
  546. X    if ((s = readpattern("with")) == ABORT)
  547. X        return(s);
  548. X
  549. X    /* move everything to the right place and length them */
  550. X    strcpy(&rpat[0], &pat[0]);
  551. X    strcpy(&pat[0], &tpat[0]);
  552. X    slength = strlen(&pat[0]);
  553. X    rlength = strlen(&rpat[0]);
  554. X
  555. X    /* set up flags so we can make sure not to do a recursive
  556. X       replace on the last line */
  557. X    nlflag = (pat[slength - 1] == '\n');
  558. X    nlrepl = FALSE;
  559. X
  560. X    if (kind) {
  561. X        /* build query replace question string */
  562. X        strcpy(tpat, "Replace '");
  563. X        expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
  564. X        strcat(tpat, "' with '");
  565. X        expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
  566. X        strcat(tpat, "'? ");
  567. X
  568. X        /* initialize last replaced pointers */
  569. X        lastline = NULL;
  570. X        lastoff = 0;
  571. X    }
  572. X
  573. X    /* save original . position */
  574. X    origline = curwp->w_dotp;
  575. X    origoff = curwp->w_doto;
  576. X
  577. X    /* scan through the file */
  578. X    numsub = 0;
  579. X    nummatch = 0;
  580. X    while ((f == FALSE || n > nummatch) &&
  581. X        (nlflag == FALSE || nlrepl == FALSE)) {
  582. X
  583. X        /* search for the pattern */
  584. X        if (forscan(&pat[0],PTBEG) != TRUE)
  585. X            break;        /* all done */
  586. X        ++nummatch;    /* increment # of matches */
  587. X
  588. X        /* check if we are on the last line */
  589. X        nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
  590. X        
  591. X        /* check for query */
  592. X        if (kind) {
  593. X            /* get the query */
  594. Xpprompt:        mlwrite(&tpat[0], &pat[0], &rpat[0]);
  595. Xqprompt:
  596. X            update(FALSE);  /* show the proposed place to change */
  597. X            c = (*term.t_getchar)();    /* and input */
  598. X            mlwrite("");            /* and clear it */
  599. X
  600. X            /* and respond appropriately */
  601. X            switch (c) {
  602. X                case 'y':    /* yes, substitute */
  603. X                case ' ':
  604. X                        break;
  605. X
  606. X                case 'n':    /* no, onword */
  607. X                        forwchar(FALSE, 1);
  608. X                        continue;
  609. X
  610. X                case '!':    /* yes/stop asking */
  611. X                        kind = FALSE;
  612. X                        break;
  613. X
  614. X                case 'u':    /* undo last and re-prompt */
  615. X
  616. X            /* restore old position */
  617. X            if (lastline == NULL) {
  618. X                /* there is nothing to undo */
  619. X                (*term.t_beep)();
  620. X                goto qprompt;
  621. X            }
  622. X            curwp->w_dotp = lastline;
  623. X            curwp->w_doto = lastoff;
  624. X            lastline = NULL;
  625. X            lastoff = 0;
  626. X
  627. X            /* delete the new string */
  628. X            backchar(FALSE, rlength);
  629. X            if (ldelete((long)rlength, FALSE) != TRUE) {
  630. X                mlwrite("ERROR while deleting");
  631. X                return(FALSE);
  632. X            }
  633. X
  634. X            /* and put in the old one */
  635. X            for (i=0; i<slength; i++) {
  636. X                tmpc = pat[i];
  637. X                s = (tmpc == '\n' ? lnewline() :
  638. X                            linsert(1, tmpc));
  639. X                if (s != TRUE) {
  640. X                    /* error while inserting */
  641. X                    mlwrite("Out of memory while inserting");
  642. X                    return(FALSE);
  643. X                }
  644. X            }
  645. X
  646. X            --numsub;    /* one less substitutions */
  647. X
  648. X            /* backup, and reprompt */
  649. X            backchar(FALSE, slength);
  650. X            goto pprompt;
  651. X
  652. X                case '.':    /* abort! and return */
  653. X                        /* restore old position */
  654. X                        curwp->w_dotp = origline;
  655. X                        curwp->w_doto = origoff;
  656. X                        curwp->w_flag |= WFMOVE;
  657. X
  658. X                case BELL:    /* abort! and stay */
  659. X                        mlwrite("Aborted!");
  660. X                        return(FALSE);
  661. X
  662. X                default:    /* bitch and beep */
  663. X                        (*term.t_beep)();
  664. X
  665. X                case '?':    /* help me */
  666. X                        mlwrite(
  667. X"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: ");
  668. X                        goto qprompt;
  669. X
  670. X            }
  671. X        }
  672. X
  673. X        /* delete the sucker */
  674. X        if (ldelete((long)slength, FALSE) != TRUE) {
  675. X            /* error while deleting */
  676. X            mlwrite("ERROR while deleteing");
  677. X            return(FALSE);
  678. X        }
  679. X
  680. X        /* and insert its replacement */
  681. X        for (i=0; i<rlength; i++) {
  682. X            tmpc = rpat[i];
  683. X            s = (tmpc == '\n' ? lnewline() : linsert(1, tmpc));
  684. X            if (s != TRUE) {
  685. X                /* error while inserting */
  686. X                mlwrite("Out of memory while inserting");
  687. X                return(FALSE);
  688. X            }
  689. X        }
  690. X
  691. X        /* save where we are if we might undo this... */
  692. X        if (kind) {
  693. X            lastline = curwp->w_dotp;
  694. X            lastoff = curwp->w_doto;
  695. X        }
  696. X
  697. X        numsub++;    /* increment # of substitutions */
  698. X    }
  699. X
  700. X    /* and report the results */
  701. X    mlwrite("%d substitutions",numsub);
  702. X    return(TRUE);
  703. X}
  704. X
  705. Xforscan(patrn,leavep)    /*    search forward for a <patrn>    */
  706. X
  707. Xchar *patrn;        /* string to scan for */
  708. Xint leavep;        /* place to leave point
  709. X                PTBEG = begining of match
  710. X                PTEND = at end of match        */
  711. X
  712. X{
  713. X    register LINE *curline;        /* current line during scan */
  714. X    register int curoff;        /* position within current line */
  715. X    register LINE *lastline;    /* last line position during scan */
  716. X    register int lastoff;        /* position within last line */
  717. X    register int c;            /* character at current position */
  718. X    register LINE *matchline;    /* current line during matching */
  719. X    register int matchoff;        /* position in matching line */
  720. X    register char *patptr;        /* pointer into pattern */
  721. X
  722. X    /* setup local scan pointers to global "." */
  723. X
  724. X    curline = curwp->w_dotp;
  725. X    curoff = curwp->w_doto;
  726. X
  727. X    /* scan each character until we hit the head link record */
  728. X
  729. X    while (curline != curbp->b_linep) {
  730. X
  731. X        /* save the current position in case we need to
  732. X           restore it on a match            */
  733. X
  734. X        lastline = curline;
  735. X        lastoff = curoff;
  736. X
  737. X        /* get the current character resolving EOLs */
  738. X
  739. X        if (curoff == llength(curline)) {    /* if at EOL */
  740. X            curline = lforw(curline);    /* skip to next line */
  741. X            curoff = 0;
  742. X            c = '\n';            /* and return a <NL> */
  743. X        } else
  744. X            c = lgetc(curline, curoff++);    /* get the char */
  745. X
  746. X        /* test it against first char in pattern */
  747. X        if (eq(c, patrn[0]) != FALSE) {    /* if we find it..*/
  748. X            /* setup match pointers */
  749. X            matchline = curline;
  750. X            matchoff = curoff;
  751. X            patptr = &patrn[0];
  752. X
  753. X            /* scan through patrn for a match */
  754. X            while (*++patptr != 0) {
  755. X                /* advance all the pointers */
  756. X                if (matchoff == llength(matchline)) {
  757. X                    /* advance past EOL */
  758. X                    matchline = lforw(matchline);
  759. X                    matchoff = 0;
  760. X                    c = '\n';
  761. X                } else
  762. X                    c = lgetc(matchline, matchoff++);
  763. X
  764. X                /* and test it against the pattern */
  765. X                if (eq(*patptr, c) == FALSE)
  766. X                    goto fail;
  767. X            }
  768. X
  769. X            /* A SUCCESSFULL MATCH!!! */
  770. X            /* reset the global "." pointers */
  771. X            if (leavep == PTEND) {    /* at end of string */
  772. X                curwp->w_dotp = matchline;
  773. X                curwp->w_doto = matchoff;
  774. X            } else {        /* at begining of string */
  775. X                curwp->w_dotp = lastline;
  776. X                curwp->w_doto = lastoff;
  777. X            }
  778. X            curwp->w_flag |= WFMOVE; /* flag that we have moved */
  779. X            return(TRUE);
  780. X
  781. X        }
  782. Xfail:;            /* continue to search */
  783. X    }
  784. X
  785. X    /* we could not find a match */
  786. X
  787. X    return(FALSE);
  788. X}
  789. X
  790. X/*     expandp:    expand control key sequences for output        */
  791. X
  792. Xexpandp(srcstr, deststr, maxlength)
  793. X
  794. Xchar *srcstr;    /* string to expand */
  795. Xchar *deststr;    /* destination of expanded string */
  796. Xint maxlength;    /* maximum chars in destination */
  797. X
  798. X{
  799. X    char c;        /* current char to translate */
  800. X
  801. X    /* scan through the string */
  802. X    while ((c = *srcstr++) != 0) {
  803. X        if (c == '\n') {        /* its an EOL */
  804. X            *deststr++ = '<';
  805. X            *deststr++ = 'N';
  806. X            *deststr++ = 'L';
  807. X            *deststr++ = '>';
  808. X            maxlength -= 4;
  809. X        } else if (c < 0x20 || c == 0x7f) {    /* control character */
  810. X            *deststr++ = '^';
  811. X            *deststr++ = c ^ 0x40;
  812. X            maxlength -= 2;
  813. X        } else if (c == '%') {
  814. X            *deststr++ = '%';
  815. X            *deststr++ = '%';
  816. X            maxlength -= 2;
  817. X
  818. X        } else {            /* any other character */
  819. X            *deststr++ = c;
  820. X            maxlength--;
  821. X        }
  822. X
  823. X        /* check for maxlength */
  824. X        if (maxlength < 4) {
  825. X            *deststr++ = '$';
  826. X            *deststr = '\0';
  827. X            return(FALSE);
  828. X        }
  829. X    }
  830. X    *deststr = '\0';
  831. X    return(TRUE);
  832. X}
  833. FRIDAY_NIGHT
  834. echo extracting - spawn.c
  835. sed 's/^X//' > spawn.c << 'FRIDAY_NIGHT'
  836. X/*    Spawn:    various DOS access commands
  837. X        for MicroEMACS
  838. X*/
  839. X
  840. X#include        <stdio.h>
  841. X#include    "estruct.h"
  842. X#include        "edef.h"
  843. X
  844. X#if     AMIGA
  845. X#define  NEW   1006
  846. X#endif
  847. X
  848. X#if     VMS
  849. X#define EFN     0                               /* Event flag.          */
  850. X
  851. X#include        <ssdef.h>                       /* Random headers.      */
  852. X#include        <stsdef.h>
  853. X#include        <descrip.h>
  854. X#include        <iodef.h>
  855. X
  856. Xextern  int     oldmode[3];                     /* In "termio.c"        */
  857. Xextern  int     newmode[3];                     /* In "termio.c"        */
  858. Xextern  short   iochan;                         /* In "termio.c"        */
  859. X#endif
  860. X
  861. X#if     V7 | USG | BSD
  862. X#include        <signal.h>
  863. Xextern int vttidy();
  864. X#endif
  865. X
  866. X#if    MSDOS & MSC
  867. X#include    <process.h>
  868. X#define    system(a)    spawnlp(P_WAIT, a, NULL)
  869. X#endif
  870. X
  871. X/*
  872. X * Create a subjob with a copy of the command intrepreter in it. When the
  873. X * command interpreter exits, mark the screen as garbage so that you do a full
  874. X * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
  875. X * Under some (unknown) condition, you don't get one free when DCL starts up.
  876. X */
  877. Xspawncli(f, n)
  878. X{
  879. X#if     AMIGA
  880. X        long newcli;
  881. X
  882. X        newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
  883. X        mlwrite("[Starting new CLI]");
  884. X        sgarbf = TRUE;
  885. X        Execute("", newcli, 0);
  886. X        Close(newcli);
  887. X        return(TRUE);
  888. X#endif
  889. X
  890. X#if     V7 | USG | BSD
  891. X        register char *cp;
  892. X        char    *getenv();
  893. X#endif
  894. X#if     VMS
  895. X        movecursor(term.t_nrow, 0);             /* In last line.        */
  896. X        mlputs("[Starting DCL]\r\n");
  897. X        (*term.t_flush)();                      /* Ignore "ttcol".      */
  898. X        sgarbf = TRUE;
  899. X        return (sys(NULL));                     /* NULL => DCL.         */
  900. X#endif
  901. X#if     CPM
  902. X        mlwrite("Not in CP/M-86");
  903. X#endif
  904. X#if     MSDOS & AZTEC
  905. X        movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  906. X        (*term.t_flush)();
  907. X    (*term.t_close)();
  908. X    system("command.com");
  909. X    (*term.t_open)();
  910. X        sgarbf = TRUE;
  911. X        return(TRUE);
  912. X#endif
  913. X#if     MSDOS & LATTICE
  914. X        movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  915. X        (*term.t_flush)();
  916. X    (*term.t_close)();
  917. X        sys("\\command.com", "");               /* Run CLI.             */
  918. X    (*term.t_open)();
  919. X        sgarbf = TRUE;
  920. X        return(TRUE);
  921. X#endif
  922. X#if     V7 | USG | BSD
  923. X        movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  924. X        (*term.t_flush)();
  925. X        ttclose();                              /* stty to old settings */
  926. X        if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
  927. X                system(cp);
  928. X        else
  929. X#if    BSD
  930. X                system("exec /bin/csh");
  931. X#else
  932. X                system("exec /bin/sh");
  933. X#endif
  934. X        sgarbf = TRUE;
  935. X        sleep(2);
  936. X        ttopen();
  937. X        return(TRUE);
  938. X#endif
  939. X}
  940. X
  941. X#if    BSD
  942. X
  943. Xbktoshell()        /* suspend MicroEMACS and wait to wake up */
  944. X{
  945. X    int pid;
  946. X
  947. X    vttidy();
  948. X    pid = getpid();
  949. X    kill(pid,SIGTSTP);
  950. X}
  951. X
  952. Xrtfrmshell()
  953. X{
  954. X    ttopen();
  955. X    curwp->w_flag = WFHARD;
  956. X    sgarbf = TRUE;
  957. X}
  958. X#endif
  959. X
  960. X/*
  961. X * Run a one-liner in a subjob. When the command returns, wait for a single
  962. X * character to be typed, then mark the screen as garbage so a full repaint is
  963. X * done. Bound to "C-X !".
  964. X */
  965. Xspawn(f, n)
  966. X{
  967. X        register int    s;
  968. X        char            line[NLINE];
  969. X#if     AMIGA
  970. X        long newcli;
  971. X
  972. X        if ((s=mlreply("!", line, NLINE)) != TRUE)
  973. X                return (s);
  974. X        newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
  975. X        Execute(line,0,newcli);
  976. X        Close(newcli);
  977. X        (*term.t_getchar)();     /* Pause.               */
  978. X        sgarbf = TRUE;
  979. X        return(TRUE);
  980. X#endif
  981. X#if     VMS
  982. X        if ((s=mlreply("!", line, NLINE)) != TRUE)
  983. X                return (s);
  984. X        (*term.t_putchar)('\n');                /* Already have '\r'    */
  985. X        (*term.t_flush)();
  986. X        s = sys(line);                          /* Run the command.     */
  987. X        mlputs("\r\n\n[End]");                  /* Pause.               */
  988. X        (*term.t_flush)();
  989. X        (*term.t_getchar)();
  990. X        sgarbf = TRUE;
  991. X        return (s);
  992. X#endif
  993. X#if     CPM
  994. X        mlwrite("Not in CP/M-86");
  995. X        return (FALSE);
  996. X#endif
  997. X#if     MSDOS
  998. X        if ((s=mlreply("!", line, NLINE)) != TRUE)
  999. X                return(s);
  1000. X    movecursor(term.t_nrow - 1, 0);
  1001. X    (*term.t_close)();
  1002. X        system(line);
  1003. X    (*term.t_open)();
  1004. X        mlputs("\r\n\n[End]");                  /* Pause.               */
  1005. X        (*term.t_getchar)();     /* Pause.               */
  1006. X        sgarbf = TRUE;
  1007. X        return (TRUE);
  1008. X#endif
  1009. X#if     V7 | USG | BSD
  1010. X        if ((s=mlreply("!", line, NLINE)) != TRUE)
  1011. X                return (s);
  1012. X        (*term.t_putchar)('\n');                /* Already have '\r'    */
  1013. X        (*term.t_flush)();
  1014. X        ttclose();                              /* stty to old modes    */
  1015. X        system(line);
  1016. X        ttopen();
  1017. X        mlputs("[End]");                        /* Pause.               */
  1018. X        (*term.t_flush)();
  1019. X        while ((s = (*term.t_getchar)()) != '\r' && s != ' ')
  1020. X                ;
  1021. X        sgarbf = TRUE;
  1022. X        return (TRUE);
  1023. X#endif
  1024. X}
  1025. X
  1026. X/*
  1027. X * Pipe a one line command into a window
  1028. X * Bound to ^X @
  1029. X */
  1030. Xpipe(f, n)
  1031. X{
  1032. X        register int    s;    /* return status from CLI */
  1033. X    register WINDOW *wp;    /* pointer to new window */
  1034. X    register BUFFER *bp;    /* pointer to buffer to zot */
  1035. X        char    line[NLINE];    /* command line send to shell */
  1036. X    static char bname[] = "command";
  1037. X
  1038. X#if    AMIGA
  1039. X    static char filnam[] = "ram:command";
  1040. X        long newcli;
  1041. X#else
  1042. X    static char filnam[] = "command";
  1043. X#endif
  1044. X
  1045. X#if     VMS
  1046. X    mlwrite("Not availible under VMS");
  1047. X    return(FALSE);
  1048. X#endif
  1049. X#if     CPM
  1050. X        mlwrite("Not availible under CP/M-86");
  1051. X        return(FALSE);
  1052. X#endif
  1053. X
  1054. X    /* get the command to pipe in */
  1055. X        if ((s=mlreply("@", line, NLINE)) != TRUE)
  1056. X                return(s);
  1057. X
  1058. X    /* get rid of the command output buffer if it exists */
  1059. X        if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  1060. X        /* try to make sure we are off screen */
  1061. X        wp = wheadp;
  1062. X        while (wp != NULL) {
  1063. X            if (wp->w_bufp == bp) {
  1064. X                onlywind(FALSE, 1);
  1065. X                break;
  1066. X            }
  1067. X            wp = wp->w_wndp;
  1068. X        }
  1069. X        if (zotbuf(bp) != TRUE)
  1070. X            return(FALSE);
  1071. X    }
  1072. X
  1073. X#if     AMIGA
  1074. X        newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
  1075. X    strcat(line, " >");
  1076. X    strcat(line, filnam);
  1077. X        Execute(line,0,newcli);
  1078. X    s = TRUE;
  1079. X        Close(newcli);
  1080. X        sgarbf = TRUE;
  1081. X#endif
  1082. X#if     MSDOS
  1083. X    strcat(line," >");
  1084. X    strcat(line,filnam);
  1085. X    movecursor(term.t_nrow - 1, 0);
  1086. X    (*term.t_close)();
  1087. X        system(line);
  1088. X    (*term.t_open)();
  1089. X        sgarbf = TRUE;
  1090. X    s = TRUE;
  1091. X#endif
  1092. X#if     V7 | USG | BSD
  1093. X        (*term.t_putchar)('\n');                /* Already have '\r'    */
  1094. X        (*term.t_flush)();
  1095. X        ttclose();                              /* stty to old modes    */
  1096. X    strcat(line,">");
  1097. X    strcat(line,filnam);
  1098. X        system(line);
  1099. X        ttopen();
  1100. X        (*term.t_flush)();
  1101. X        sgarbf = TRUE;
  1102. X        s = TRUE;
  1103. X#endif
  1104. X
  1105. X    if (s != TRUE)
  1106. X        return(s);
  1107. X
  1108. X    /* split the current window to make room for the command output */
  1109. X    if (splitwind(FALSE, 1) == FALSE)
  1110. X            return(FALSE);
  1111. X
  1112. X    /* and read the stuff in */
  1113. X    if (getfile(filnam, FALSE) == FALSE)
  1114. X        return(FALSE);
  1115. X
  1116. X    /* make this window in VIEW mode, update all mode lines */
  1117. X    curwp->w_bufp->b_mode |= MDVIEW;
  1118. X    wp = wheadp;
  1119. X    while (wp != NULL) {
  1120. X        wp->w_flag |= WFMODE;
  1121. X        wp = wp->w_wndp;
  1122. X    }
  1123. X
  1124. X    /* and get rid of the temporary file */
  1125. X    unlink(filnam);
  1126. X    return(TRUE);
  1127. X}
  1128. X
  1129. X/*
  1130. X * filter a buffer through an external DOS program
  1131. X * Bound to ^X #
  1132. X */
  1133. Xfilter(f, n)
  1134. X
  1135. X{
  1136. X        register int    s;    /* return status from CLI */
  1137. X    register BUFFER *bp;    /* pointer to buffer to zot */
  1138. X        char line[NLINE];    /* command line send to shell */
  1139. X    char tmpnam[NFILEN];    /* place to store real file name */
  1140. X    static char bname1[] = "fltinp";
  1141. X
  1142. X#if    AMIGA
  1143. X    static char filnam1[] = "ram:fltinp";
  1144. X    static char filnam2[] = "ram:fltout";
  1145. X        long newcli;
  1146. X#else
  1147. X    static char filnam1[] = "fltinp";
  1148. X    static char filnam2[] = "fltout";
  1149. X#endif
  1150. X
  1151. X#if     VMS
  1152. X    mlwrite("Not availible under VMS");
  1153. X    return(FALSE);
  1154. X#endif
  1155. X#if     CPM
  1156. X        mlwrite("Not availible under CP/M-86");
  1157. X        return(FALSE);
  1158. X#endif
  1159. X
  1160. X    /* get the filter name and its args */
  1161. X        if ((s=mlreply("#", line, NLINE)) != TRUE)
  1162. X                return(s);
  1163. X
  1164. X    /* setup the proper file names */
  1165. X    bp = curbp;
  1166. X    strcpy(tmpnam, bp->b_fname);    /* save the original name */
  1167. X    strcpy(bp->b_fname, bname1);    /* set it to our new one */
  1168. X
  1169. X    /* write it out, checking for errors */
  1170. X    if (writeout(filnam1) != TRUE) {
  1171. X        mlwrite("[Cannot write filter file]");
  1172. X        strcpy(bp->b_fname, tmpnam);
  1173. X        return(FALSE);
  1174. X    }
  1175. X
  1176. X#if     AMIGA
  1177. X        newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
  1178. X    strcat(line, " <ram:fltinp >ram:fltout");
  1179. X        Execute(line,0,newcli);
  1180. X    s = TRUE;
  1181. X        Close(newcli);
  1182. X        sgarbf = TRUE;
  1183. X#endif
  1184. X#if     MSDOS
  1185. X    strcat(line," <fltinp >fltout");
  1186. X    movecursor(term.t_nrow - 1, 0);
  1187. X    (*term.t_close)();
  1188. X        system(line);
  1189. X    (*term.t_open)();
  1190. X        sgarbf = TRUE;
  1191. X    s = TRUE;
  1192. X#endif
  1193. X#if     V7 | USG | BSD
  1194. X        (*term.t_putchar)('\n');                /* Already have '\r'    */
  1195. X        (*term.t_flush)();
  1196. X        ttclose();                              /* stty to old modes    */
  1197. X    strcat(line," <fltinp >fltout");
  1198. X        system(line);
  1199. X        ttopen();
  1200. X        (*term.t_flush)();
  1201. X        sgarbf = TRUE;
  1202. X        s = TRUE;
  1203. X#endif
  1204. X
  1205. X    /* on failure, escape gracefully */
  1206. X    if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  1207. X        mlwrite("[Execution failed]");
  1208. X        strcpy(bp->b_fname, tmpnam);
  1209. X        unlink(filnam1);
  1210. X        unlink(filnam2);
  1211. X        return(s);
  1212. X    }
  1213. X
  1214. X    /* reset file name */
  1215. X    strcpy(bp->b_fname, tmpnam);    /* restore name */
  1216. X    bp->b_flag |= BFCHG;        /* flag it as changed */
  1217. X
  1218. X    /* and get rid of the temporary file */
  1219. X    unlink(filnam1);
  1220. X    unlink(filnam2);
  1221. X    return(TRUE);
  1222. X}
  1223. X
  1224. X#if     VMS
  1225. X/*
  1226. X * Run a command. The "cmd" is a pointer to a command string, or NULL if you
  1227. X * want to run a copy of DCL in the subjob (this is how the standard routine
  1228. X * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
  1229. X * and the way out, because DCL does not want the channel to be in raw mode.
  1230. X */
  1231. Xsys(cmd)
  1232. Xregister char   *cmd;
  1233. X{
  1234. X        struct  dsc$descriptor  cdsc;
  1235. X        struct  dsc$descriptor  *cdscp;
  1236. X        long    status;
  1237. X        long    substatus;
  1238. X        long    iosb[2];
  1239. X
  1240. X        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  1241. X                          oldmode, sizeof(oldmode), 0, 0, 0, 0);
  1242. X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  1243. X                return (FALSE);
  1244. X        cdscp = NULL;                           /* Assume DCL.          */
  1245. X        if (cmd != NULL) {                      /* Build descriptor.    */
  1246. X                cdsc.dsc$a_pointer = cmd;
  1247. X                cdsc.dsc$w_length  = strlen(cmd);
  1248. X                cdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  1249. X                cdsc.dsc$b_class   = DSC$K_CLASS_S;
  1250. X                cdscp = &cdsc;
  1251. X        }
  1252. X        status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
  1253. X        if (status != SS$_NORMAL)
  1254. X                substatus = status;
  1255. X        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  1256. X                          newmode, sizeof(newmode), 0, 0, 0, 0);
  1257. X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  1258. X                return (FALSE);
  1259. X        if ((substatus&STS$M_SUCCESS) == 0)     /* Command failed.      */
  1260. X                return (FALSE);
  1261. X        return (TRUE);
  1262. X}
  1263. X#endif
  1264. X
  1265. X#if    ~AZTEC & MSDOS
  1266. X
  1267. X/*
  1268. X * This routine, once again by Bob McNamara, is a C translation of the "system"
  1269. X * routine in the MWC-86 run time library. It differs from the "system" routine
  1270. X * in that it does not unconditionally append the string ".exe" to the end of
  1271. X * the command name. We needed to do this because we want to be able to spawn
  1272. X * off "command.com". We really do not understand what it does, but if you don't
  1273. X * do it exactly "malloc" starts doing very very strange things.
  1274. X */
  1275. Xsys(cmd, tail)
  1276. Xchar    *cmd;
  1277. Xchar    *tail;
  1278. X{
  1279. X#if MWC_86
  1280. X        register unsigned n;
  1281. X        extern   char     *__end;
  1282. X
  1283. X        n = __end + 15;
  1284. X        n >>= 4;
  1285. X        n = ((n + dsreg() + 16) & 0xFFF0) + 16;
  1286. X        return(execall(cmd, tail, n));
  1287. X#endif
  1288. X
  1289. X#if LATTICE
  1290. X        return(forklp(cmd, tail, (char *)NULL));
  1291. X#endif
  1292. X
  1293. X#if    MSC
  1294. X    return(spawnlp(P_WAIT, cmd, tail, NULL);
  1295. X#endif
  1296. X}
  1297. X#endif
  1298. X
  1299. X#if    MSDOS & LATTICE
  1300. X/*    System: a modified version of lattice's system() function
  1301. X        that detects the proper switchar and uses it
  1302. X        written by Dana Hogget                */
  1303. X
  1304. Xsystem(cmd)
  1305. X
  1306. Xchar *cmd;    /*  Incoming command line to execute  */
  1307. X
  1308. X{
  1309. X    char *getenv();
  1310. X    static char *swchar = "/C";    /*  Execution switch  */
  1311. X    union REGS inregs;    /*  parameters for dos call  */
  1312. X    union REGS outregs;    /*  Return results from dos call  */
  1313. X    char *shell;        /*  Name of system command processor  */
  1314. X    char *p;        /*  Temporary pointer  */
  1315. X    int ferr;        /*  Error condition if any  */
  1316. X
  1317. X    /*  get name of system shell  */
  1318. X    if ((shell = getenv("COMSPEC")) == NULL) {
  1319. X        return (-1);        /*  No shell located  */
  1320. X    }
  1321. X
  1322. X    p = cmd;
  1323. X    while (isspace(*p)) {        /*  find out if null command */
  1324. X        p++;
  1325. X    }
  1326. X
  1327. X    /**  If the command line is not empty, bring up the shell  **/
  1328. X    /**  and execute the command.  Otherwise, bring up the     **/
  1329. X    /**  shell in interactive mode.   **/
  1330. X
  1331. X    if (p && *p) {
  1332. X        /**  detect current switch character and us it  **/
  1333. X        inregs.h.ah = 0x37;    /*  get setting data  */
  1334. X        inregs.h.al = 0x00;    /*  get switch character  */
  1335. X        intdos(&inregs, &outregs);
  1336. X        *swchar = outregs.h.dl;
  1337. X        ferr = forkl(shell, "command", swchar, cmd, (char *)NULL);
  1338. X    } else {
  1339. X        ferr = forkl(shell, "command", (char *)NULL);
  1340. X    }
  1341. X
  1342. X    return (ferr ? ferr : wait());
  1343. X}
  1344. X#endif
  1345. X
  1346. FRIDAY_NIGHT
  1347. echo es.10 completed!
  1348. : That's all folks!
  1349.  
  1350.