home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume1 / 8711 / microemacs-3.9 / 5 < prev    next >
Text File  |  1987-11-17  |  44KB  |  1,798 lines

  1. Article 81 of comp.sources.misc:
  2. Path: tut!osu-cis!cbosgd!mandrill!hal!ncoast!allbery
  3. From: nwd@j.cc.purdue.edu (Daniel Lawrence)
  4. Newsgroups: comp.sources.misc
  5. Subject: MicroEmacs 3.9 (Part 5 of 16)
  6. Message-ID: <5652@ncoast.UUCP>
  7. Date: 14 Nov 87 21:08:42 GMT
  8. Sender: allbery@ncoast.UUCP
  9. Lines: 1783
  10. Approved: allbery@ncoast.UUCP
  11. X-Archive: comp.sources.misc/microemacs-3.9/4
  12.  
  13. # This is a shar archive.
  14. # Remove everything above this line.
  15. # Run the file through sh, not csh.
  16. # (type `sh mes.5')
  17. # If you do not see the message
  18. #    `mes.5 completed!'
  19. # then the file was incomplete.
  20. echo extracting - exec.c
  21. sed 's/^X//' > exec.c << 'FRIDAY_NIGHT'
  22. X/*    This file is for functions dealing with execution of
  23. X    commands, command lines, buffers, files and startup files
  24. X
  25. X    written 1986 by Daniel Lawrence                */
  26. X
  27. X#include    <stdio.h>
  28. X#include    "estruct.h"
  29. X#include    "edef.h"
  30. X
  31. X/* namedcmd:    execute a named command even if it is not bound */
  32. X
  33. Xnamedcmd(f, n)
  34. X
  35. Xint f, n;    /* command arguments [passed through to command executed] */
  36. X
  37. X{
  38. X    register int (*kfunc)(); /* ptr to the requexted function to bind to */
  39. X    int (*getname())();
  40. X
  41. X    /* prompt the user to type a named command */
  42. X    mlwrite(": ");
  43. X
  44. X    /* and now get the function name to execute */
  45. X    kfunc = getname();
  46. X    if (kfunc == NULL) {
  47. X        mlwrite("[No such function]");
  48. X        return(FALSE);
  49. X    }
  50. X
  51. X    /* and then execute the command */
  52. X    return((*kfunc)(f, n));
  53. X}
  54. X
  55. X/*    execcmd:    Execute a command line command to be typed in
  56. X            by the user                    */
  57. X
  58. Xexeccmd(f, n)
  59. X
  60. Xint f, n;    /* default Flag and Numeric argument */
  61. X
  62. X{
  63. X    register int status;        /* status return */
  64. X    char cmdstr[NSTRING];        /* string holding command to execute */
  65. X
  66. X    /* get the line wanted */
  67. X    if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  68. X        return(status);
  69. X
  70. X    execlevel = 0;
  71. X    return(docmd(cmdstr));
  72. X}
  73. X
  74. X/*    docmd:    take a passed string as a command line and translate
  75. X        it to be executed as a command. This function will be
  76. X        used by execute-command-line and by all source and
  77. X        startup files. Lastflag/thisflag is also updated.
  78. X
  79. X    format of the command line is:
  80. X
  81. X        {# arg} <command-name> {<argument string(s)>}
  82. X
  83. X*/
  84. X
  85. Xdocmd(cline)
  86. X
  87. Xchar *cline;    /* command line to execute */
  88. X
  89. X{
  90. X    register int f;        /* default argument flag */
  91. X    register int n;        /* numeric repeat value */
  92. X    int (*fnc)();        /* function to execute */
  93. X    int status;        /* return status of function */
  94. X    int oldcle;        /* old contents of clexec flag */
  95. X    char *oldestr;        /* original exec string */
  96. X    char tkn[NSTRING];    /* next token off of command line */
  97. X    int (*fncmatch())();
  98. X        
  99. X    /* if we are scanning and not executing..go back here */
  100. X    if (execlevel)
  101. X        return(TRUE);
  102. X
  103. X    oldestr = execstr;    /* save last ptr to string to execute */
  104. X    execstr = cline;    /* and set this one as current */
  105. X
  106. X    /* first set up the default command values */
  107. X    f = FALSE;
  108. X    n = 1;
  109. X    lastflag = thisflag;
  110. X    thisflag = 0;
  111. X
  112. X    if ((status = macarg(tkn)) != TRUE) {    /* and grab the first token */
  113. X        execstr = oldestr;
  114. X        return(status);
  115. X    }
  116. X
  117. X    /* process leadin argument */
  118. X    if (gettyp(tkn) != TKCMD) {
  119. X        f = TRUE;
  120. X        strcpy(tkn, getval(tkn));
  121. X        n = atoi(tkn);
  122. X
  123. X        /* and now get the command to execute */
  124. X        if ((status = macarg(tkn)) != TRUE) {
  125. X            execstr = oldestr;
  126. X            return(status);    
  127. X        }    
  128. X    }
  129. X
  130. X    /* and match the token to see if it exists */
  131. X    if ((fnc = fncmatch(tkn)) == NULL) {
  132. X        mlwrite("[No such Function]");
  133. X        execstr = oldestr;
  134. X        return(FALSE);
  135. X    }
  136. X    
  137. X    /* save the arguments and go execute the command */
  138. X    oldcle = clexec;        /* save old clexec flag */
  139. X    clexec = TRUE;            /* in cline execution */
  140. X    status = (*fnc)(f, n);        /* call the function */
  141. X    cmdstatus = status;        /* save the status */
  142. X    clexec = oldcle;        /* restore clexec flag */
  143. X    execstr = oldestr;
  144. X    return(status);
  145. X}
  146. X
  147. X/* token:    chop a token off a string
  148. X        return a pointer past the token
  149. X*/
  150. X
  151. Xchar *token(src, tok, size)
  152. X
  153. Xchar *src, *tok;    /* source string, destination token string */
  154. Xint size;        /* maximum size of token */
  155. X
  156. X{
  157. X    register int quotef;    /* is the current string quoted? */
  158. X    register char c;    /* temporary character */
  159. X
  160. X    /* first scan past any whitespace in the source string */
  161. X    while (*src == ' ' || *src == '\t')
  162. X        ++src;
  163. X
  164. X    /* scan through the source string */
  165. X    quotef = FALSE;
  166. X    while (*src) {
  167. X        /* process special characters */
  168. X        if (*src == '~') {
  169. X            ++src;
  170. X            if (*src == 0)
  171. X                break;
  172. X            switch (*src++) {
  173. X                case 'r':    c = 13; break;
  174. X                case 'n':    c = 10; break;
  175. X                case 't':    c = 9;  break;
  176. X                case 'b':    c = 8;  break;
  177. X                case 'f':    c = 12; break;
  178. X                default:    c = *(src-1);
  179. X            }
  180. X            if (--size > 0) {
  181. X                *tok++ = c;
  182. X            }
  183. X        } else {
  184. X            /* check for the end of the token */
  185. X            if (quotef) {
  186. X                if (*src == '"')
  187. X                    break;
  188. X            } else {
  189. X                if (*src == ' ' || *src == '\t')
  190. X                    break;
  191. X            }
  192. X
  193. X            /* set quote mode if quote found */
  194. X            if (*src == '"')
  195. X                quotef = TRUE;
  196. X
  197. X            /* record the character */
  198. X            c = *src++;
  199. X            if (--size > 0)
  200. X                *tok++ = c;
  201. X        }
  202. X    }
  203. X
  204. X    /* terminate the token and exit */
  205. X    if (*src)
  206. X        ++src;
  207. X    *tok = 0;
  208. X    return(src);
  209. X}
  210. X
  211. Xmacarg(tok)    /* get a macro line argument */
  212. X
  213. Xchar *tok;    /* buffer to place argument */
  214. X
  215. X{
  216. X    int savcle;    /* buffer to store original clexec */
  217. X    int status;
  218. X
  219. X    savcle = clexec;    /* save execution mode */
  220. X    clexec = TRUE;        /* get the argument */
  221. X    status = nextarg("", tok, NSTRING, ctoec('\n'));
  222. X    clexec = savcle;    /* restore execution mode */
  223. X    return(status);
  224. X}
  225. X
  226. X/*    nextarg:    get the next argument    */
  227. X
  228. Xnextarg(prompt, buffer, size, terminator)
  229. X
  230. Xchar *prompt;        /* prompt to use if we must be interactive */
  231. Xchar *buffer;        /* buffer to put token into */
  232. Xint size;        /* size of the buffer */
  233. Xint terminator;        /* terminating char to be used on interactive fetch */
  234. X
  235. X{
  236. X    /* if we are interactive, go get it! */
  237. X    if (clexec == FALSE)
  238. X        return(getstring(prompt, buffer, size, terminator));
  239. X
  240. X    /* grab token and advance past */
  241. X    execstr = token(execstr, buffer, size);
  242. X
  243. X    /* evaluate it */
  244. X    strcpy(buffer, getval(buffer));
  245. X    return(TRUE);
  246. X}
  247. X
  248. X/*    storemac:    Set up a macro buffer and flag to store all
  249. X            executed command lines there            */
  250. X
  251. Xstoremac(f, n)
  252. X
  253. Xint f;        /* default flag */
  254. Xint n;        /* macro number to use */
  255. X
  256. X{
  257. X    register struct BUFFER *bp;    /* pointer to macro buffer */
  258. X    char bname[NBUFN];        /* name of buffer to use */
  259. X
  260. X    /* must have a numeric argument to this function */
  261. X    if (f == FALSE) {
  262. X        mlwrite("No macro specified");
  263. X        return(FALSE);
  264. X    }
  265. X
  266. X    /* range check the macro number */
  267. X    if (n < 1 || n > 40) {
  268. X        mlwrite("Macro number out of range");
  269. X        return(FALSE);
  270. X    }
  271. X
  272. X    /* construct the macro buffer name */
  273. X    strcpy(bname, "[Macro xx]");
  274. X    bname[7] = '0' + (n / 10);
  275. X    bname[8] = '0' + (n % 10);
  276. X
  277. X    /* set up the new macro buffer */
  278. X    if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  279. X        mlwrite("Can not create macro");
  280. X        return(FALSE);
  281. X    }
  282. X
  283. X    /* and make sure it is empty */
  284. X    bclear(bp);
  285. X
  286. X    /* and set the macro store pointers to it */
  287. X    mstore = TRUE;
  288. X    bstore = bp;
  289. X    return(TRUE);
  290. X}
  291. X
  292. X#if    PROC
  293. X/*    storeproc:    Set up a procedure buffer and flag to store all
  294. X            executed command lines there            */
  295. X
  296. Xstoreproc(f, n)
  297. X
  298. Xint f;        /* default flag */
  299. Xint n;        /* macro number to use */
  300. X
  301. X{
  302. X    register struct BUFFER *bp;    /* pointer to macro buffer */
  303. X    register int status;        /* return status */
  304. X    char bname[NBUFN];        /* name of buffer to use */
  305. X
  306. X    /* a numeric argument means its a numbered macro */
  307. X    if (f == TRUE)
  308. X        return(storemac(f, n));
  309. X
  310. X    /* get the name of the procedure */
  311. X        if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
  312. X                return(status);
  313. X
  314. X    /* construct the macro buffer name */
  315. X    bname[0] = '[';
  316. X    strcat(bname, "]");
  317. X
  318. X    /* set up the new macro buffer */
  319. X    if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  320. X        mlwrite("Can not create macro");
  321. X        return(FALSE);
  322. X    }
  323. X
  324. X    /* and make sure it is empty */
  325. X    bclear(bp);
  326. X
  327. X    /* and set the macro store pointers to it */
  328. X    mstore = TRUE;
  329. X    bstore = bp;
  330. X    return(TRUE);
  331. X}
  332. X
  333. X/*    execproc:    Execute a procedure                */
  334. X
  335. Xexecproc(f, n)
  336. X
  337. Xint f, n;    /* default flag and numeric arg */
  338. X
  339. X{
  340. X        register BUFFER *bp;        /* ptr to buffer to execute */
  341. X        register int status;        /* status return */
  342. X        char bufn[NBUFN+2];        /* name of buffer to execute */
  343. X
  344. X    /* find out what buffer the user wants to execute */
  345. X        if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
  346. X                return(status);
  347. X
  348. X    /* construct the buffer name */
  349. X    bufn[0] = '[';
  350. X    strcat(bufn, "]");
  351. X
  352. X    /* find the pointer to that buffer */
  353. X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  354. X        mlwrite("No such procedure");
  355. X                return(FALSE);
  356. X        }
  357. X
  358. X    /* and now execute it as asked */
  359. X    while (n-- > 0)
  360. X        if ((status = dobuf(bp)) != TRUE)
  361. X            return(status);
  362. X    return(TRUE);
  363. X}
  364. X#endif
  365. X
  366. X/*    execbuf:    Execute the contents of a buffer of commands    */
  367. X
  368. Xexecbuf(f, n)
  369. X
  370. Xint f, n;    /* default flag and numeric arg */
  371. X
  372. X{
  373. X        register BUFFER *bp;        /* ptr to buffer to execute */
  374. X        register int status;        /* status return */
  375. X        char bufn[NSTRING];        /* name of buffer to execute */
  376. X
  377. X    /* find out what buffer the user wants to execute */
  378. X        if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
  379. X                return(status);
  380. X
  381. X    /* find the pointer to that buffer */
  382. X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  383. X        mlwrite("No such buffer");
  384. X                return(FALSE);
  385. X        }
  386. X
  387. X    /* and now execute it as asked */
  388. X    while (n-- > 0)
  389. X        if ((status = dobuf(bp)) != TRUE)
  390. X            return(status);
  391. X    return(TRUE);
  392. X}
  393. X
  394. X/*    dobuf:    execute the contents of the buffer pointed to
  395. X        by the passed BP
  396. X
  397. X    Directives start with a "!" and include:
  398. X
  399. X    !endm        End a macro
  400. X    !if (cond)    conditional execution
  401. X    !else
  402. X    !endif
  403. X    !return        Return (terminating current macro)
  404. X    !goto <label>    Jump to a label in the current macro
  405. X    !force        Force macro to continue...even if command fails
  406. X    !while (cond)    Execute a loop if the condition is true
  407. X    !endwhile
  408. X    
  409. X    Line Labels begin with a "*" as the first nonblank char, like:
  410. X
  411. X    *LBL01
  412. X*/
  413. X
  414. Xdobuf(bp)
  415. X
  416. XBUFFER *bp;    /* buffer to execute */
  417. X
  418. X{
  419. X        register int status;    /* status return */
  420. X    register LINE *lp;    /* pointer to line to execute */
  421. X    register LINE *hlp;    /* pointer to line header */
  422. X    register LINE *glp;    /* line to goto */
  423. X    LINE *mp;        /* Macro line storage temp */
  424. X    int dirnum;        /* directive index */
  425. X    int linlen;        /* length of line to execute */
  426. X    int i;            /* index */
  427. X    int c;            /* temp character */
  428. X    int force;        /* force TRUE result? */
  429. X    WINDOW *wp;        /* ptr to windows to scan */
  430. X    WHBLOCK *whlist;    /* ptr to !WHILE list */
  431. X    WHBLOCK *scanner;    /* ptr during scan */
  432. X    WHBLOCK *whtemp;    /* temporary ptr to a WHBLOCK */
  433. X    char *einit;        /* initial value of eline */
  434. X    char *eline;        /* text of line to execute */
  435. X    char tkn[NSTRING];    /* buffer to evaluate an expresion in */
  436. X
  437. X#if    DEBUGM
  438. X    char *sp;            /* temp for building debug string */
  439. X    register char *ep;    /* ptr to end of outline */
  440. X#endif
  441. X
  442. X    /* clear IF level flags/while ptr */
  443. X    execlevel = 0;
  444. X    whlist = NULL;
  445. X    scanner = NULL;
  446. X
  447. X    /* scan the buffer to execute, building WHILE header blocks */
  448. X    hlp = bp->b_linep;
  449. X    lp = hlp->l_fp;
  450. X    while (lp != hlp) {
  451. X        /* scan the current line */
  452. X        eline = lp->l_text;
  453. X        i = lp->l_used;
  454. X
  455. X        /* trim leading whitespace */
  456. X        while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
  457. X            ++eline;
  458. X
  459. X        /* if theres nothing here, don't bother */
  460. X        if (i <= 0)
  461. X            goto nxtscan;
  462. X
  463. X        /* if is a while directive, make a block... */
  464. X        if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
  465. X            whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  466. X            if (whtemp == NULL) {
  467. Xnoram:                mlwrite("%%Out of memory during while scan");
  468. Xfailexit:            freewhile(scanner);
  469. X                freewhile(whlist);
  470. X                return(FALSE);
  471. X            }
  472. X            whtemp->w_begin = lp;
  473. X            whtemp->w_type = BTWHILE;
  474. X            whtemp->w_next = scanner;
  475. X            scanner = whtemp;
  476. X        }
  477. X
  478. X        /* if is a BREAK directive, make a block... */
  479. X        if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
  480. X            if (scanner == NULL) {
  481. X                mlwrite("%%!BREAK outside of any !WHILE loop");
  482. X                goto failexit;
  483. X            }
  484. X            whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  485. X            if (whtemp == NULL)
  486. X                goto noram;
  487. X            whtemp->w_begin = lp;
  488. X            whtemp->w_type = BTBREAK;
  489. X            whtemp->w_next = scanner;
  490. X            scanner = whtemp;
  491. X        }
  492. X
  493. X        /* if it is an endwhile directive, record the spot... */
  494. X        if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
  495. X            if (scanner == NULL) {
  496. X                mlwrite("%%!ENDWHILE with no preceding !WHILE in '%s'",
  497. X                    bp->b_bname);
  498. X                goto failexit;
  499. X            }
  500. X            /* move top records from the scanner list to the
  501. X               whlist until we have moved all BREAK records
  502. X               and one WHILE record */
  503. X            do {
  504. X                scanner->w_end = lp;
  505. X                whtemp = whlist;
  506. X                whlist = scanner;
  507. X                scanner = scanner->w_next;
  508. X                whlist->w_next = whtemp;
  509. X            } while (whlist->w_type == BTBREAK);
  510. X        }
  511. X
  512. Xnxtscan:    /* on to the next line */
  513. X        lp = lp->l_fp;
  514. X    }
  515. X
  516. X    /* while and endwhile should match! */
  517. X    if (scanner != NULL) {
  518. X        mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'",
  519. X            bp->b_bname);
  520. X        goto failexit;
  521. X    }
  522. X
  523. X    /* let the first command inherit the flags from the last one..*/
  524. X    thisflag = lastflag;
  525. X
  526. X    /* starting at the beginning of the buffer */
  527. X    hlp = bp->b_linep;
  528. X    lp = hlp->l_fp;
  529. X    while (lp != hlp) {
  530. X        /* allocate eline and copy macro line to it */
  531. X        linlen = lp->l_used;
  532. X        if ((einit = eline = malloc(linlen+1)) == NULL) {
  533. X            mlwrite("%%Out of Memory during macro execution");
  534. X            freewhile(whlist);
  535. X            return(FALSE);
  536. X        }
  537. X        strncpy(eline, lp->l_text, linlen);
  538. X        eline[linlen] = 0;    /* make sure it ends */
  539. X
  540. X        /* trim leading whitespace */
  541. X        while (*eline == ' ' || *eline == '\t')
  542. X            ++eline;
  543. X
  544. X        /* dump comments and blank lines */
  545. X        if (*eline == ';' || *eline == 0)
  546. X            goto onward;
  547. X
  548. X#if    DEBUGM
  549. X        /* if $debug == TRUE, every line to execute
  550. X           gets echoed and a key needs to be pressed to continue
  551. X           ^G will abort the command */
  552. X    
  553. X        if (macbug) {
  554. X            strcpy(outline, "<<<");
  555. X    
  556. X            /* debug macro name */
  557. X            strcat(outline, bp->b_bname);
  558. X            strcat(outline, ":");
  559. X    
  560. X            /* debug if levels */
  561. X            strcat(outline, itoa(execlevel));
  562. X            strcat(outline, ":");
  563. X
  564. X            /* and lastly the line */
  565. X            strcat(outline, eline);
  566. X            strcat(outline, ">>>");
  567. X    
  568. X            /* change all '%' to ':' so mlwrite won't expect arguments */
  569. X            sp = outline;
  570. X            while (*sp)
  571. X            if (*sp++ == '%') {
  572. X                /* advance to the end */
  573. X                ep = --sp;
  574. X                while (*ep++)
  575. X                    ;
  576. X                /* null terminate the string one out */
  577. X                *(ep + 1) = 0;
  578. X                /* copy backwards */
  579. X                while(ep-- > sp)
  580. X                    *(ep + 1) = *ep;
  581. X
  582. X                /* and advance sp past the new % */
  583. X                sp += 2;                    
  584. X            }
  585. X    
  586. X            /* write out the debug line */
  587. X            mlforce(outline);
  588. X            update(TRUE);
  589. X    
  590. X            /* and get the keystroke */
  591. X            if ((c = get1key()) == abortc) {
  592. X                mlforce("[Macro aborted]");
  593. X                freewhile(whlist);
  594. X                return(FALSE);
  595. X            }
  596. X
  597. X            if (c == metac)
  598. X                macbug = FALSE;
  599. X        }
  600. X#endif
  601. X
  602. X        /* Parse directives here.... */
  603. X        dirnum = -1;
  604. X        if (*eline == '!') {
  605. X            /* Find out which directive this is */
  606. X            ++eline;
  607. X            for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
  608. X                if (strncmp(eline, dname[dirnum],
  609. X                            strlen(dname[dirnum])) == 0)
  610. X                    break;
  611. X
  612. X            /* and bitch if it's illegal */
  613. X            if (dirnum == NUMDIRS) {
  614. X                mlwrite("%%Unknown Directive");
  615. X                freewhile(whlist);
  616. X                return(FALSE);
  617. X            }
  618. X
  619. X            /* service only the !ENDM macro here */
  620. X            if (dirnum == DENDM) {
  621. X                mstore = FALSE;
  622. X                bstore = NULL;
  623. X                goto onward;
  624. X            }
  625. X
  626. X            /* restore the original eline....*/
  627. X            --eline;
  628. X        }
  629. X
  630. X        /* if macro store is on, just salt this away */
  631. X        if (mstore) {
  632. X            /* allocate the space for the line */
  633. X            linlen = strlen(eline);
  634. X            if ((mp=lalloc(linlen)) == NULL) {
  635. X                mlwrite("Out of memory while storing macro");
  636. X                return (FALSE);
  637. X            }
  638. X    
  639. X            /* copy the text into the new line */
  640. X            for (i=0; i<linlen; ++i)
  641. X                lputc(mp, i, eline[i]);
  642. X    
  643. X            /* attach the line to the end of the buffer */
  644. X                   bstore->b_linep->l_bp->l_fp = mp;
  645. X            mp->l_bp = bstore->b_linep->l_bp;
  646. X            bstore->b_linep->l_bp = mp;
  647. X            mp->l_fp = bstore->b_linep;
  648. X            goto onward;
  649. X        }
  650. X    
  651. X
  652. X        force = FALSE;
  653. X
  654. X        /* dump comments */
  655. X        if (*eline == '*')
  656. X            goto onward;
  657. X
  658. X        /* now, execute directives */
  659. X        if (dirnum != -1) {
  660. X            /* skip past the directive */
  661. X            while (*eline && *eline != ' ' && *eline != '\t')
  662. X                ++eline;
  663. X            execstr = eline;
  664. X
  665. X            switch (dirnum) {
  666. X            case DIF:    /* IF directive */
  667. X                /* grab the value of the logical exp */
  668. X                if (execlevel == 0) {
  669. X                    if (macarg(tkn) != TRUE)
  670. X                        goto eexec;
  671. X                    if (stol(tkn) == FALSE)
  672. X                        ++execlevel;
  673. X                } else
  674. X                    ++execlevel;
  675. X                goto onward;
  676. X
  677. X            case DWHILE:    /* WHILE directive */
  678. X                /* grab the value of the logical exp */
  679. X                if (execlevel == 0) {
  680. X                    if (macarg(tkn) != TRUE)
  681. X                        goto eexec;
  682. X                    if (stol(tkn) == TRUE)
  683. X                        goto onward;
  684. X                }
  685. X                /* drop down and act just like !BREAK */
  686. X
  687. X            case DBREAK:    /* BREAK directive */
  688. X                if (dirnum == DBREAK && execlevel)
  689. X                    goto onward;
  690. X
  691. X                /* jump down to the endwhile */
  692. X                /* find the right while loop */
  693. X                whtemp = whlist;
  694. X                while (whtemp) {
  695. X                    if (whtemp->w_begin == lp)
  696. X                        break;
  697. X                    whtemp = whtemp->w_next;
  698. X                }
  699. X            
  700. X                if (whtemp == NULL) {
  701. X                    mlwrite("%%Internal While loop error");
  702. X                    freewhile(whlist);
  703. X                    return(FALSE);
  704. X                }
  705. X            
  706. X                /* reset the line pointer back.. */
  707. X                lp = whtemp->w_end;
  708. X                goto onward;
  709. X
  710. X            case DELSE:    /* ELSE directive */
  711. X                if (execlevel == 1)
  712. X                    --execlevel;
  713. X                else if (execlevel == 0 )
  714. X                    ++execlevel;
  715. X                goto onward;
  716. X
  717. X            case DENDIF:    /* ENDIF directive */
  718. X                if (execlevel)
  719. X                    --execlevel;
  720. X                goto onward;
  721. X
  722. X            case DGOTO:    /* GOTO directive */
  723. X                /* .....only if we are currently executing */
  724. X                if (execlevel == 0) {
  725. X
  726. X                    /* grab label to jump to */
  727. X                    eline = token(eline, golabel, NPAT);
  728. X                    linlen = strlen(golabel);
  729. X                    glp = hlp->l_fp;
  730. X                    while (glp != hlp) {
  731. X                        if (*glp->l_text == '*' &&
  732. X                            (strncmp(&glp->l_text[1], golabel,
  733. X                                    linlen) == 0)) {
  734. X                            lp = glp;
  735. X                            goto onward;
  736. X                        }
  737. X                        glp = glp->l_fp;
  738. X                    }
  739. X                    mlwrite("%%No such label");
  740. X                    freewhile(whlist);
  741. X                    return(FALSE);
  742. X                }
  743. X                goto onward;
  744. X    
  745. X            case DRETURN:    /* RETURN directive */
  746. X                if (execlevel == 0)
  747. X                    goto eexec;
  748. X                goto onward;
  749. X
  750. X            case DENDWHILE:    /* ENDWHILE directive */
  751. X                if (execlevel) {
  752. X                    --execlevel;
  753. X                    goto onward;
  754. X                } else {
  755. X                    /* find the right while loop */
  756. X                    whtemp = whlist;
  757. X                    while (whtemp) {
  758. X                        if (whtemp->w_type == BTWHILE &&
  759. X                            whtemp->w_end == lp)
  760. X                            break;
  761. X                        whtemp = whtemp->w_next;
  762. X                    }
  763. X        
  764. X                    if (whtemp == NULL) {
  765. X                        mlwrite("%%Internal While loop error");
  766. X                        freewhile(whlist);
  767. X                        return(FALSE);
  768. X                    }
  769. X        
  770. X                    /* reset the line pointer back.. */
  771. X                    lp = whtemp->w_begin->l_bp;
  772. X                    goto onward;
  773. X                }
  774. X
  775. X            case DFORCE:    /* FORCE directive */
  776. X                force = TRUE;
  777. X
  778. X            }
  779. X        }
  780. X
  781. X        /* execute the statement */
  782. X        status = docmd(eline);
  783. X        if (force)        /* force the status */
  784. X            status = TRUE;
  785. X
  786. X        /* check for a command error */
  787. X        if (status != TRUE) {
  788. X            /* look if buffer is showing */
  789. X            wp = wheadp;
  790. X            while (wp != NULL) {
  791. X                if (wp->w_bufp == bp) {
  792. X                    /* and point it */
  793. X                    wp->w_dotp = lp;
  794. X                    wp->w_doto = 0;
  795. X                    wp->w_flag |= WFHARD;
  796. X                }
  797. X                wp = wp->w_wndp;
  798. X            }
  799. X            /* in any case set the buffer . */
  800. X            bp->b_dotp = lp;
  801. X            bp->b_doto = 0;
  802. X            free(einit);
  803. X            execlevel = 0;
  804. X            freewhile(whlist);
  805. X            return(status);
  806. X        }
  807. X
  808. Xonward:        /* on to the next line */
  809. X        free(einit);
  810. X        lp = lp->l_fp;
  811. X    }
  812. X
  813. Xeexec:    /* exit the current function */
  814. X    execlevel = 0;
  815. X    freewhile(whlist);
  816. X        return(TRUE);
  817. X}
  818. X
  819. Xfreewhile(wp)    /* free a list of while block pointers */
  820. X
  821. XWHBLOCK *wp;    /* head of structure to free */
  822. X
  823. X{
  824. X    if (wp == NULL)
  825. X        return;
  826. X    if (wp->w_next)
  827. X        freewhile(wp->w_next);
  828. X    free(wp);
  829. X}
  830. X
  831. Xexecfile(f, n)    /* execute a series of commands in a file */
  832. X
  833. Xint f, n;    /* default flag and numeric arg to pass on to file */
  834. X
  835. X{
  836. X    register int status;    /* return status of name query */
  837. X    char fname[NSTRING];    /* name of file to execute */
  838. X    char *fspec;        /* full file spec */
  839. X
  840. X    if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
  841. X        return(status);
  842. X
  843. X#if    1
  844. X    /* look up the path for the file */
  845. X    fspec = flook(fname, TRUE);
  846. X
  847. X    /* if it isn't around */
  848. X    if (fspec == NULL)
  849. X        return(FALSE);
  850. X
  851. X#endif
  852. X    /* otherwise, execute it */
  853. X    while (n-- > 0)
  854. X        if ((status=dofile(fspec)) != TRUE)
  855. X            return(status);
  856. X
  857. X    return(TRUE);
  858. X}
  859. X
  860. X/*    dofile:    yank a file into a buffer and execute it
  861. X        if there are no errors, delete the buffer on exit */
  862. X
  863. Xdofile(fname)
  864. X
  865. Xchar *fname;    /* file name to execute */
  866. X
  867. X{
  868. X    register BUFFER *bp;    /* buffer to place file to exeute */
  869. X    register BUFFER *cb;    /* temp to hold current buf while we read */
  870. X    register int status;    /* results of various calls */
  871. X    char bname[NBUFN];    /* name of buffer */
  872. X
  873. X    makename(bname, fname);        /* derive the name of the buffer */
  874. X    unqname(bname);            /* make sure we don't stomp things */
  875. X    if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  876. X        return(FALSE);
  877. X
  878. X    bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  879. X    cb = curbp;        /* save the old buffer */
  880. X    curbp = bp;        /* make this one current */
  881. X    /* and try to read in the file to execute */
  882. X    if ((status = readin(fname, FALSE)) != TRUE) {
  883. X        curbp = cb;    /* restore the current buffer */
  884. X        return(status);
  885. X    }
  886. X
  887. X    /* go execute it! */
  888. X    curbp = cb;        /* restore the current buffer */
  889. X    if ((status = dobuf(bp)) != TRUE)
  890. X        return(status);
  891. X
  892. X    /* if not displayed, remove the now unneeded buffer and exit */
  893. X    if (bp->b_nwnd == 0)
  894. X        zotbuf(bp);
  895. X    return(TRUE);
  896. X}
  897. X
  898. X/*    cbuf:    Execute the contents of a numbered buffer    */
  899. X
  900. Xcbuf(f, n, bufnum)
  901. X
  902. Xint f, n;    /* default flag and numeric arg */
  903. Xint bufnum;    /* number of buffer to execute */
  904. X
  905. X{
  906. X        register BUFFER *bp;        /* ptr to buffer to execute */
  907. X        register int status;        /* status return */
  908. X    static char bufname[] = "[Macro xx]";
  909. X
  910. X    /* make the buffer name */
  911. X    bufname[7] = '0' + (bufnum / 10);
  912. X    bufname[8] = '0' + (bufnum % 10);
  913. X
  914. X    /* find the pointer to that buffer */
  915. X        if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
  916. X            mlwrite("Macro not defined");
  917. X                return(FALSE);
  918. X        }
  919. X
  920. X    /* and now execute it as asked */
  921. X    while (n-- > 0)
  922. X        if ((status = dobuf(bp)) != TRUE)
  923. X            return(status);
  924. X    return(TRUE);
  925. X}
  926. X
  927. Xcbuf1(f, n)
  928. X
  929. X{
  930. X    cbuf(f, n, 1);
  931. X}
  932. X
  933. Xcbuf2(f, n)
  934. X
  935. X{
  936. X    cbuf(f, n, 2);
  937. X}
  938. X
  939. Xcbuf3(f, n)
  940. X
  941. X{
  942. X    cbuf(f, n, 3);
  943. X}
  944. X
  945. Xcbuf4(f, n)
  946. X
  947. X{
  948. X    cbuf(f, n, 4);
  949. X}
  950. X
  951. Xcbuf5(f, n)
  952. X
  953. X{
  954. X    cbuf(f, n, 5);
  955. X}
  956. X
  957. Xcbuf6(f, n)
  958. X
  959. X{
  960. X    cbuf(f, n, 6);
  961. X}
  962. X
  963. Xcbuf7(f, n)
  964. X
  965. X{
  966. X    cbuf(f, n, 7);
  967. X}
  968. X
  969. Xcbuf8(f, n)
  970. X
  971. X{
  972. X    cbuf(f, n, 8);
  973. X}
  974. X
  975. Xcbuf9(f, n)
  976. X
  977. X{
  978. X    cbuf(f, n, 9);
  979. X}
  980. X
  981. Xcbuf10(f, n)
  982. X
  983. X{
  984. X    cbuf(f, n, 10);
  985. X}
  986. X
  987. Xcbuf11(f, n)
  988. X
  989. X{
  990. X    cbuf(f, n, 11);
  991. X}
  992. X
  993. Xcbuf12(f, n)
  994. X
  995. X{
  996. X    cbuf(f, n, 12);
  997. X}
  998. X
  999. Xcbuf13(f, n)
  1000. X
  1001. X{
  1002. X    cbuf(f, n, 13);
  1003. X}
  1004. X
  1005. Xcbuf14(f, n)
  1006. X
  1007. X{
  1008. X    cbuf(f, n, 14);
  1009. X}
  1010. X
  1011. Xcbuf15(f, n)
  1012. X
  1013. X{
  1014. X    cbuf(f, n, 15);
  1015. X}
  1016. X
  1017. Xcbuf16(f, n)
  1018. X
  1019. X{
  1020. X    cbuf(f, n, 16);
  1021. X}
  1022. X
  1023. Xcbuf17(f, n)
  1024. X
  1025. X{
  1026. X    cbuf(f, n, 17);
  1027. X}
  1028. X
  1029. Xcbuf18(f, n)
  1030. X
  1031. X{
  1032. X    cbuf(f, n, 18);
  1033. X}
  1034. X
  1035. Xcbuf19(f, n)
  1036. X
  1037. X{
  1038. X    cbuf(f, n, 19);
  1039. X}
  1040. X
  1041. Xcbuf20(f, n)
  1042. X
  1043. X{
  1044. X    cbuf(f, n, 20);
  1045. X}
  1046. X
  1047. Xcbuf21(f, n)
  1048. X
  1049. X{
  1050. X    cbuf(f, n, 21);
  1051. X}
  1052. X
  1053. Xcbuf22(f, n)
  1054. X
  1055. X{
  1056. X    cbuf(f, n, 22);
  1057. X}
  1058. X
  1059. Xcbuf23(f, n)
  1060. X
  1061. X{
  1062. X    cbuf(f, n, 23);
  1063. X}
  1064. X
  1065. Xcbuf24(f, n)
  1066. X
  1067. X{
  1068. X    cbuf(f, n, 24);
  1069. X}
  1070. X
  1071. Xcbuf25(f, n)
  1072. X
  1073. X{
  1074. X    cbuf(f, n, 25);
  1075. X}
  1076. X
  1077. Xcbuf26(f, n)
  1078. X
  1079. X{
  1080. X    cbuf(f, n, 26);
  1081. X}
  1082. X
  1083. Xcbuf27(f, n)
  1084. X
  1085. X{
  1086. X    cbuf(f, n, 27);
  1087. X}
  1088. X
  1089. Xcbuf28(f, n)
  1090. X
  1091. X{
  1092. X    cbuf(f, n, 28);
  1093. X}
  1094. X
  1095. Xcbuf29(f, n)
  1096. X
  1097. X{
  1098. X    cbuf(f, n, 29);
  1099. X}
  1100. X
  1101. Xcbuf30(f, n)
  1102. X
  1103. X{
  1104. X    cbuf(f, n, 30);
  1105. X}
  1106. X
  1107. Xcbuf31(f, n)
  1108. X
  1109. X{
  1110. X    cbuf(f, n, 31);
  1111. X}
  1112. X
  1113. Xcbuf32(f, n)
  1114. X
  1115. X{
  1116. X    cbuf(f, n, 32);
  1117. X}
  1118. X
  1119. Xcbuf33(f, n)
  1120. X
  1121. X{
  1122. X    cbuf(f, n, 33);
  1123. X}
  1124. X
  1125. Xcbuf34(f, n)
  1126. X
  1127. X{
  1128. X    cbuf(f, n, 34);
  1129. X}
  1130. X
  1131. Xcbuf35(f, n)
  1132. X
  1133. X{
  1134. X    cbuf(f, n, 35);
  1135. X}
  1136. X
  1137. Xcbuf36(f, n)
  1138. X
  1139. X{
  1140. X    cbuf(f, n, 36);
  1141. X}
  1142. X
  1143. Xcbuf37(f, n)
  1144. X
  1145. X{
  1146. X    cbuf(f, n, 37);
  1147. X}
  1148. X
  1149. Xcbuf38(f, n)
  1150. X
  1151. X{
  1152. X    cbuf(f, n, 38);
  1153. X}
  1154. X
  1155. Xcbuf39(f, n)
  1156. X
  1157. X{
  1158. X    cbuf(f, n, 39);
  1159. X}
  1160. X
  1161. Xcbuf40(f, n)
  1162. X
  1163. X{
  1164. X    cbuf(f, n, 40);
  1165. X}
  1166. X
  1167. X
  1168. FRIDAY_NIGHT
  1169. echo extracting - file.c
  1170. sed 's/^X//' > file.c << 'FRIDAY_NIGHT'
  1171. X/*    FILE.C:   for MicroEMACS
  1172. X
  1173. X    The routines in this file handle the reading, writing
  1174. X    and lookup of disk files.  All of details about the
  1175. X    reading and writing of the disk are in "fileio.c".
  1176. X
  1177. X*/
  1178. X
  1179. X#include        <stdio.h>
  1180. X#include    "estruct.h"
  1181. X#include        "edef.h"
  1182. X
  1183. X/*
  1184. X * Read a file into the current
  1185. X * buffer. This is really easy; all you do it
  1186. X * find the name of the file, and call the standard
  1187. X * "read a file into the current buffer" code.
  1188. X * Bound to "C-X C-R".
  1189. X */
  1190. Xfileread(f, n)
  1191. X{
  1192. X        register int    s;
  1193. X        char fname[NFILEN];
  1194. X
  1195. X    if (restflag)        /* don't allow this command if restricted */
  1196. X        return(resterr());
  1197. X        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
  1198. X                return(s);
  1199. X        return(readin(fname, TRUE));
  1200. X}
  1201. X
  1202. X/*
  1203. X * Insert a file into the current
  1204. X * buffer. This is really easy; all you do it
  1205. X * find the name of the file, and call the standard
  1206. X * "insert a file into the current buffer" code.
  1207. X * Bound to "C-X C-I".
  1208. X */
  1209. Xinsfile(f, n)
  1210. X{
  1211. X        register int    s;
  1212. X        char fname[NFILEN];
  1213. X
  1214. X    if (restflag)        /* don't allow this command if restricted */
  1215. X        return(resterr());
  1216. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  1217. X        return(rdonly());    /* we are in read only mode    */
  1218. X        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
  1219. X                return(s);
  1220. X        return(ifile(fname));
  1221. X}
  1222. X
  1223. X/*
  1224. X * Select a file for editing.
  1225. X * Look around to see if you can find the
  1226. X * fine in another buffer; if you can find it
  1227. X * just switch to the buffer. If you cannot find
  1228. X * the file, create a new buffer, read in the
  1229. X * text, and switch to the new buffer.
  1230. X * Bound to C-X C-F.
  1231. X */
  1232. Xfilefind(f, n)
  1233. X{
  1234. X        char fname[NFILEN];    /* file user wishes to find */
  1235. X        register int s;        /* status return */
  1236. X
  1237. X    if (restflag)        /* don't allow this command if restricted */
  1238. X        return(resterr());
  1239. X        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
  1240. X                return(s);
  1241. X    return(getfile(fname, TRUE));
  1242. X}
  1243. X
  1244. Xviewfile(f, n)    /* visit a file in VIEW mode */
  1245. X{
  1246. X        char fname[NFILEN];    /* file user wishes to find */
  1247. X        register int s;        /* status return */
  1248. X    register WINDOW *wp;    /* scan for windows that need updating */
  1249. X
  1250. X    if (restflag)        /* don't allow this command if restricted */
  1251. X        return(resterr());
  1252. X        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
  1253. X                return (s);
  1254. X    s = getfile(fname, FALSE);
  1255. X    if (s) {    /* if we succeed, put it in view mode */
  1256. X        curwp->w_bufp->b_mode |= MDVIEW;
  1257. X
  1258. X        /* scan through and update mode lines of all windows */
  1259. X        wp = wheadp;
  1260. X        while (wp != NULL) {
  1261. X            wp->w_flag |= WFMODE;
  1262. X            wp = wp->w_wndp;
  1263. X        }
  1264. X    }
  1265. X    return(s);
  1266. X}
  1267. X
  1268. X#if    CRYPT
  1269. Xresetkey()    /* reset the encryption key if needed */
  1270. X
  1271. X{
  1272. X    register int s;    /* return status */
  1273. X
  1274. X    /* turn off the encryption flag */
  1275. X    cryptflag = FALSE;
  1276. X
  1277. X    /* if we are in crypt mode */
  1278. X    if (curbp->b_mode & MDCRYPT) {
  1279. X        if (curbp->b_key[0] == 0) {
  1280. X            s = setkey(FALSE, 0);
  1281. X            if (s != TRUE)
  1282. X                return(s);
  1283. X        }
  1284. X
  1285. X        /* let others know... */
  1286. X        cryptflag = TRUE;
  1287. X
  1288. X        /* and set up the key to be used! */
  1289. X        /* de-encrypt it */
  1290. X        crypt((char *)NULL, 0);
  1291. X        crypt(curbp->b_key, strlen(curbp->b_key));
  1292. X
  1293. X        /* re-encrypt it...seeding it to start */
  1294. X        crypt((char *)NULL, 0);
  1295. X        crypt(curbp->b_key, strlen(curbp->b_key));
  1296. X    }
  1297. X
  1298. X    return(TRUE);
  1299. X}
  1300. X#endif
  1301. X
  1302. Xgetfile(fname, lockfl)
  1303. X
  1304. Xchar fname[];        /* file name to find */
  1305. Xint lockfl;        /* check the file for locks? */
  1306. X
  1307. X{
  1308. X        register BUFFER *bp;
  1309. X        register LINE   *lp;
  1310. X        register int    i;
  1311. X        register int    s;
  1312. X        char bname[NBUFN];    /* buffer name to put file */
  1313. X
  1314. X#if    MSDOS
  1315. X    mklower(fname);        /* msdos isn't case sensitive */
  1316. X#endif
  1317. X        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  1318. X                if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
  1319. X            swbuffer(bp);
  1320. X                        lp = curwp->w_dotp;
  1321. X                        i = curwp->w_ntrows/2;
  1322. X                        while (i-- && lback(lp)!=curbp->b_linep)
  1323. X                                lp = lback(lp);
  1324. X                        curwp->w_linep = lp;
  1325. X                        curwp->w_flag |= WFMODE|WFHARD;
  1326. X                        mlwrite("[Old buffer]");
  1327. X                        return (TRUE);
  1328. X                }
  1329. X        }
  1330. X        makename(bname, fname);                 /* New buffer name.     */
  1331. X        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
  1332. X        /* old buffer name conflict code */
  1333. X                s = mlreply("Buffer name: ", bname, NBUFN);
  1334. X                if (s == ABORT)                 /* ^G to just quit      */
  1335. X                        return (s);
  1336. X                if (s == FALSE) {               /* CR to clobber it     */
  1337. X                        makename(bname, fname);
  1338. X                        break;
  1339. X                }
  1340. X        }
  1341. X        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
  1342. X                mlwrite("Cannot create buffer");
  1343. X                return (FALSE);
  1344. X        }
  1345. X        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
  1346. X                curbp->b_dotp = curwp->w_dotp;
  1347. X                curbp->b_doto = curwp->w_doto;
  1348. X                curbp->b_markp = curwp->w_markp;
  1349. X                curbp->b_marko = curwp->w_marko;
  1350. X        }
  1351. X        curbp = bp;                             /* Switch to it.        */
  1352. X        curwp->w_bufp = bp;
  1353. X        curbp->b_nwnd++;
  1354. X        return(readin(fname, lockfl));          /* Read it in.          */
  1355. X}
  1356. X
  1357. X/*
  1358. X    Read file "fname" into the current buffer, blowing away any text
  1359. X    found there.  Called by both the read and find commands.  Return
  1360. X    the final status of the read.  Also called by the mainline, to
  1361. X    read in a file specified on the command line as an argument. 
  1362. X    The command bound to M-FNR is called after the buffer is set up
  1363. X    and before it is read. 
  1364. X*/
  1365. X
  1366. Xreadin(fname, lockfl)
  1367. X
  1368. Xchar    fname[];    /* name of file to read */
  1369. Xint    lockfl;        /* check for file locks? */
  1370. X
  1371. X{
  1372. X        register LINE   *lp1;
  1373. X        register LINE   *lp2;
  1374. X        register int    i;
  1375. X        register WINDOW *wp;
  1376. X        register BUFFER *bp;
  1377. X        register int    s;
  1378. X        register int    nbytes;
  1379. X        register int    nline;
  1380. X    int        lflag;        /* any lines longer than allowed? */
  1381. X    char mesg[NSTRING];
  1382. X
  1383. X#if    FILOCK
  1384. X    if (lockfl && lockchk(fname) == ABORT)
  1385. X        return(ABORT);
  1386. X#endif
  1387. X#if    CRYPT
  1388. X    s = resetkey();
  1389. X    if (s != TRUE)
  1390. X        return(s);
  1391. X#endif
  1392. X        bp = curbp;                             /* Cheap.               */
  1393. X        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
  1394. X                return (s);
  1395. X        bp->b_flag &= ~(BFINVS|BFCHG);
  1396. X        strcpy(bp->b_fname, fname);
  1397. X
  1398. X    /* let a user macro get hold of things...if he wants */
  1399. X    execute(META|SPEC|'R', FALSE, 1);
  1400. X
  1401. X    /* turn off ALL keyboard translation in case we get a dos error */
  1402. X    TTkclose();
  1403. X
  1404. X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  1405. X                goto out;
  1406. X
  1407. X        if (s == FIOFNF) {                      /* File not found.      */
  1408. X                mlwrite("[New file]");
  1409. X                goto out;
  1410. X        }
  1411. X
  1412. X    /* read the file in */
  1413. X        mlwrite("[Reading file]");
  1414. X        nline = 0;
  1415. X    lflag = FALSE;
  1416. X        while ((s=ffgetline()) == FIOSUC) {
  1417. X                nbytes = strlen(fline);
  1418. X                if ((lp1=lalloc(nbytes)) == NULL) {
  1419. X                        s = FIOMEM;             /* Keep message on the  */
  1420. X                        break;                  /* display.             */
  1421. X                }
  1422. X                lp2 = lback(curbp->b_linep);
  1423. X                lp2->l_fp = lp1;
  1424. X                lp1->l_fp = curbp->b_linep;
  1425. X                lp1->l_bp = lp2;
  1426. X                curbp->b_linep->l_bp = lp1;
  1427. X                for (i=0; i<nbytes; ++i)
  1428. X                        lputc(lp1, i, fline[i]);
  1429. X                ++nline;
  1430. X        }
  1431. X        ffclose();                              /* Ignore errors.       */
  1432. X    strcpy(mesg, "[");
  1433. X    if (s==FIOERR) {
  1434. X        strcat(mesg, "I/O ERROR, ");
  1435. X        curbp->b_flag |= BFTRUNC;
  1436. X    }
  1437. X    if (s == FIOMEM) {
  1438. X        strcat(mesg, "OUT OF MEMORY, ");
  1439. X        curbp->b_flag |= BFTRUNC;
  1440. X    }
  1441. X    sprintf(&mesg[strlen(mesg)], "Read %d line", nline);
  1442. X        if (nline > 1)
  1443. X        strcat(mesg, "s");
  1444. X    strcat(mesg, "]");
  1445. X    mlwrite(mesg);
  1446. X
  1447. Xout:
  1448. X    TTkopen();    /* open the keyboard again */
  1449. X        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  1450. X                if (wp->w_bufp == curbp) {
  1451. X                        wp->w_linep = lforw(curbp->b_linep);
  1452. X                        wp->w_dotp  = lforw(curbp->b_linep);
  1453. X                        wp->w_doto  = 0;
  1454. X                        wp->w_markp = NULL;
  1455. X                        wp->w_marko = 0;
  1456. X                        wp->w_flag |= WFMODE|WFHARD;
  1457. X                }
  1458. X        }
  1459. X        if (s == FIOERR || s == FIOFNF)        /* False if error.      */
  1460. X                return(FALSE);
  1461. X        return (TRUE);
  1462. X}
  1463. X
  1464. X/*
  1465. X * Take a file name, and from it
  1466. X * fabricate a buffer name. This routine knows
  1467. X * about the syntax of file names on the target system.
  1468. X * I suppose that this information could be put in
  1469. X * a better place than a line of code.
  1470. X */
  1471. Xmakename(bname, fname)
  1472. Xchar    bname[];
  1473. Xchar    fname[];
  1474. X{
  1475. X        register char *cp1;
  1476. X        register char *cp2;
  1477. X
  1478. X        cp1 = &fname[0];
  1479. X        while (*cp1 != 0)
  1480. X                ++cp1;
  1481. X
  1482. X#if     AMIGA
  1483. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
  1484. X                --cp1;
  1485. X#endif
  1486. X#if     VMS
  1487. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
  1488. X                --cp1;
  1489. X#endif
  1490. X#if     CPM
  1491. X        while (cp1!=&fname[0] && cp1[-1]!=':')
  1492. X                --cp1;
  1493. X#endif
  1494. X#if     MSDOS
  1495. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  1496. X                --cp1;
  1497. X#endif
  1498. X#if     ST520
  1499. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
  1500. X                --cp1;
  1501. X#endif
  1502. X#if     FINDER
  1503. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  1504. X                --cp1;
  1505. X#endif
  1506. X#if     V7 | USG | BSD
  1507. X        while (cp1!=&fname[0] && cp1[-1]!='/')
  1508. X                --cp1;
  1509. X#endif
  1510. X        cp2 = &bname[0];
  1511. X        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  1512. X                *cp2++ = *cp1++;
  1513. X        *cp2 = 0;
  1514. X}
  1515. X
  1516. Xunqname(name)    /* make sure a buffer name is unique */
  1517. X
  1518. Xchar *name;    /* name to check on */
  1519. X
  1520. X{
  1521. X    register char *sp;
  1522. X
  1523. X    /* check to see if it is in the buffer list */
  1524. X    while (bfind(name, 0, FALSE) != NULL) {
  1525. X
  1526. X        /* go to the end of the name */
  1527. X        sp = name;
  1528. X        while (*sp)
  1529. X            ++sp;
  1530. X        if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
  1531. X            *sp++ = '0';
  1532. X            *sp = 0;
  1533. X        } else
  1534. X            *(--sp) += 1;
  1535. X    }
  1536. X}
  1537. X
  1538. X/*
  1539. X * Ask for a file name, and write the
  1540. X * contents of the current buffer to that file.
  1541. X * Update the remembered file name and clear the
  1542. X * buffer changed flag. This handling of file names
  1543. X * is different from the earlier versions, and
  1544. X * is more compatable with Gosling EMACS than
  1545. X * with ITS EMACS. Bound to "C-X C-W".
  1546. X */
  1547. Xfilewrite(f, n)
  1548. X{
  1549. X        register WINDOW *wp;
  1550. X        register int    s;
  1551. X        char            fname[NFILEN];
  1552. X
  1553. X    if (restflag)        /* don't allow this command if restricted */
  1554. X        return(resterr());
  1555. X        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
  1556. X                return (s);
  1557. X        if ((s=writeout(fname)) == TRUE) {
  1558. X                strcpy(curbp->b_fname, fname);
  1559. X                curbp->b_flag &= ~BFCHG;
  1560. X                wp = wheadp;                    /* Update mode lines.   */
  1561. X                while (wp != NULL) {
  1562. X                        if (wp->w_bufp == curbp)
  1563. X                                wp->w_flag |= WFMODE;
  1564. X                        wp = wp->w_wndp;
  1565. X                }
  1566. X        }
  1567. X        return (s);
  1568. X}
  1569. X
  1570. X/*
  1571. X * Save the contents of the current
  1572. X * buffer in its associatd file. No nothing
  1573. X * if nothing has changed (this may be a bug, not a
  1574. X * feature). Error if there is no remembered file
  1575. X * name for the buffer. Bound to "C-X C-S". May
  1576. X * get called by "C-Z".
  1577. X */
  1578. Xfilesave(f, n)
  1579. X{
  1580. X        register WINDOW *wp;
  1581. X        register int    s;
  1582. X
  1583. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  1584. X        return(rdonly());    /* we are in read only mode    */
  1585. X        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
  1586. X                return (TRUE);
  1587. X        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
  1588. X                mlwrite("No file name");
  1589. X                return (FALSE);
  1590. X        }
  1591. X
  1592. X    /* complain about truncated files */
  1593. X    if ((curbp->b_flag&BFTRUNC) != 0) {
  1594. X        if (mlyesno("Truncated file..write it out") == FALSE) {
  1595. X            mlwrite("[Aborted]");
  1596. X            return(FALSE);
  1597. X        }
  1598. X    }
  1599. X
  1600. X        if ((s=writeout(curbp->b_fname)) == TRUE) {
  1601. X                curbp->b_flag &= ~BFCHG;
  1602. X                wp = wheadp;                    /* Update mode lines.   */
  1603. X                while (wp != NULL) {
  1604. X                        if (wp->w_bufp == curbp)
  1605. X                                wp->w_flag |= WFMODE;
  1606. X                        wp = wp->w_wndp;
  1607. X                }
  1608. X        }
  1609. X        return (s);
  1610. X}
  1611. X
  1612. X/*
  1613. X * This function performs the details of file
  1614. X * writing. Uses the file management routines in the
  1615. X * "fileio.c" package. The number of lines written is
  1616. X * displayed. Sadly, it looks inside a LINE; provide
  1617. X * a macro for this. Most of the grief is error
  1618. X * checking of some sort.
  1619. X */
  1620. Xwriteout(fn)
  1621. Xchar    *fn;
  1622. X{
  1623. X        register int    s;
  1624. X        register LINE   *lp;
  1625. X        register int    nline;
  1626. X
  1627. X#if    CRYPT
  1628. X    s = resetkey();
  1629. X    if (s != TRUE)
  1630. X        return(s);
  1631. X#endif
  1632. X    /* turn off ALL keyboard translation in case we get a dos error */
  1633. X    TTkclose();
  1634. X
  1635. X        if ((s=ffwopen(fn)) != FIOSUC) {        /* Open writes message. */
  1636. X        TTkopen();
  1637. X                return (FALSE);
  1638. X        }
  1639. X    mlwrite("[Writing...]");        /* tell us were writing */
  1640. X        lp = lforw(curbp->b_linep);             /* First line.          */
  1641. X        nline = 0;                              /* Number of lines.     */
  1642. X        while (lp != curbp->b_linep) {
  1643. X                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
  1644. X                        break;
  1645. X                ++nline;
  1646. X                lp = lforw(lp);
  1647. X        }
  1648. X        if (s == FIOSUC) {                      /* No write error.      */
  1649. X                s = ffclose();
  1650. X                if (s == FIOSUC) {              /* No close error.      */
  1651. X                        if (nline == 1)
  1652. X                                mlwrite("[Wrote 1 line]");
  1653. X                        else
  1654. X                                mlwrite("[Wrote %d lines]", nline);
  1655. X                }
  1656. X        } else                                  /* Ignore close error   */
  1657. X                ffclose();                      /* if a write error.    */
  1658. X    TTkopen();
  1659. X        if (s != FIOSUC)                        /* Some sort of error.  */
  1660. X                return (FALSE);
  1661. X        return (TRUE);
  1662. X}
  1663. X
  1664. X/*
  1665. X * The command allows the user
  1666. X * to modify the file name associated with
  1667. X * the current buffer. It is like the "f" command
  1668. X * in UNIX "ed". The operation is simple; just zap
  1669. X * the name in the BUFFER structure, and mark the windows
  1670. X * as needing an update. You can type a blank line at the
  1671. X * prompt if you wish.
  1672. X */
  1673. Xfilename(f, n)
  1674. X{
  1675. X        register WINDOW *wp;
  1676. X        register int    s;
  1677. X        char            fname[NFILEN];
  1678. X
  1679. X    if (restflag)        /* don't allow this command if restricted */
  1680. X        return(resterr());
  1681. X        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
  1682. X                return (s);
  1683. X        if (s == FALSE)
  1684. X                strcpy(curbp->b_fname, "");
  1685. X        else
  1686. X                strcpy(curbp->b_fname, fname);
  1687. X        wp = wheadp;                            /* Update mode lines.   */
  1688. X        while (wp != NULL) {
  1689. X                if (wp->w_bufp == curbp)
  1690. X                        wp->w_flag |= WFMODE;
  1691. X                wp = wp->w_wndp;
  1692. X        }
  1693. X    curbp->b_mode &= ~MDVIEW;    /* no longer read only mode */
  1694. X        return (TRUE);
  1695. X}
  1696. X
  1697. X/*
  1698. X * Insert file "fname" into the current
  1699. X * buffer, Called by insert file command. Return the final
  1700. X * status of the read.
  1701. X */
  1702. Xifile(fname)
  1703. Xchar    fname[];
  1704. X{
  1705. X        register LINE   *lp0;
  1706. X        register LINE   *lp1;
  1707. X        register LINE   *lp2;
  1708. X        register int    i;
  1709. X        register BUFFER *bp;
  1710. X        register int    s;
  1711. X        register int    nbytes;
  1712. X        register int    nline;
  1713. X    int        lflag;        /* any lines longer than allowed? */
  1714. X    char mesg[NSTRING];
  1715. X
  1716. X        bp = curbp;                             /* Cheap.               */
  1717. X        bp->b_flag |= BFCHG;            /* we have changed    */
  1718. X    bp->b_flag &= ~BFINVS;            /* and are not temporary*/
  1719. X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  1720. X                goto out;
  1721. X        if (s == FIOFNF) {                      /* File not found.      */
  1722. X                mlwrite("[No such file]");
  1723. X        return(FALSE);
  1724. X        }
  1725. X        mlwrite("[Inserting file]");
  1726. X
  1727. X#if    CRYPT
  1728. X    s = resetkey();
  1729. X    if (s != TRUE)
  1730. X        return(s);
  1731. X#endif
  1732. X    /* back up a line and save the mark here */
  1733. X    curwp->w_dotp = lback(curwp->w_dotp);
  1734. X    curwp->w_doto = 0;
  1735. X    curwp->w_markp = curwp->w_dotp;
  1736. X    curwp->w_marko = 0;
  1737. X
  1738. X        nline = 0;
  1739. X    lflag = FALSE;
  1740. X        while ((s=ffgetline()) == FIOSUC) {
  1741. X                nbytes = strlen(fline);
  1742. X                if ((lp1=lalloc(nbytes)) == NULL) {
  1743. X                        s = FIOMEM;             /* Keep message on the  */
  1744. X                        break;                  /* display.             */
  1745. X                }
  1746. X        lp0 = curwp->w_dotp;    /* line previous to insert */
  1747. X        lp2 = lp0->l_fp;    /* line after insert */
  1748. X
  1749. X        /* re-link new line between lp0 and lp2 */
  1750. X        lp2->l_bp = lp1;
  1751. X        lp0->l_fp = lp1;
  1752. X        lp1->l_bp = lp0;
  1753. X        lp1->l_fp = lp2;
  1754. X
  1755. X        /* and advance and write out the current line */
  1756. X        curwp->w_dotp = lp1;
  1757. X                for (i=0; i<nbytes; ++i)
  1758. X                        lputc(lp1, i, fline[i]);
  1759. X                ++nline;
  1760. X        }
  1761. X        ffclose();                              /* Ignore errors.       */
  1762. X    curwp->w_markp = lforw(curwp->w_markp);
  1763. X    strcpy(mesg, "[");
  1764. X    if (s==FIOERR) {
  1765. X        strcat(mesg, "I/O ERROR, ");
  1766. X        curbp->b_flag |= BFTRUNC;
  1767. X    }
  1768. X    if (s == FIOMEM) {
  1769. X        strcat(mesg, "OUT OF MEMORY, ");
  1770. X        curbp->b_flag |= BFTRUNC;
  1771. X    }
  1772. X    sprintf(&mesg[strlen(mesg)], "Inserted %d line", nline);
  1773. X        if (nline > 1)
  1774. X        strcat(mesg, "s");
  1775. X    strcat(mesg, "]");
  1776. X    mlwrite(mesg);
  1777. X
  1778. Xout:
  1779. X    /* advance to the next line and mark the window for changes */
  1780. X    curwp->w_dotp = lforw(curwp->w_dotp);
  1781. X    curwp->w_flag |= WFHARD | WFMODE;
  1782. X
  1783. X    /* copy window parameters back to the buffer structure */
  1784. X    curbp->b_dotp = curwp->w_dotp;
  1785. X    curbp->b_doto = curwp->w_doto;
  1786. X    curbp->b_markp = curwp->w_markp;
  1787. X    curbp->b_marko = curwp->w_marko;
  1788. X
  1789. X        if (s == FIOERR)                        /* False if error.      */
  1790. X                return (FALSE);
  1791. X        return (TRUE);
  1792. X}
  1793. FRIDAY_NIGHT
  1794. echo mes.5 completed!
  1795. # That's all folks!
  1796.  
  1797.  
  1798.