home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8706 / 16 < prev    next >
Internet Message Format  |  1993-09-01  |  64KB

  1. From mipos3!intelca!oliveb!pyramid!uccba!hal!ncoast!allbery Fri Jun 19 14:06:26 PDT 1987
  2. Article 9 of comp.sources.misc:
  3. Path: td2cad!mipos3!intelca!oliveb!pyramid!uccba!hal!ncoast!allbery
  4. >From: davidsen@steinmetz.UUCP (William E. Davidsen Jr)
  5. Newsgroups: comp.sources.misc
  6. Subject: memacs 3.8i 4 of 11
  7. Message-ID: <2659@ncoast.UUCP>
  8. Date: 15 Jun 87 18:59:39 GMT
  9. Sender: allbery@ncoast.UUCP
  10. Lines: 2613
  11. Approved: allbery@ncoast.UUCP
  12. X-Archive: comp.sources.misc/8706/16
  13.  
  14. :
  15. #!/bin/sh
  16. # shar+ created from directory /usr2/davidsen/emacs38i
  17. # 13:42 on Thu Jun 11, 1987 by davidsen
  18. echo 'x - eval.c (text)'
  19. sed << 'E!O!F' 's/^X//' > eval.c
  20. X/*    EVAL.C:    Expresion evaluation functions for
  21. X        MicroEMACS
  22. X
  23. X    written 1986 by Daniel Lawrence                */
  24. X
  25. X#include    <stdio.h>
  26. X#include    "estruct.h"
  27. X#include    "edef.h"
  28. X#include    "evar.h"
  29. X
  30. Xchar value[NSTRING];        /* buffer to return value in */
  31. X
  32. Xvarinit()        /* initialize the user variable list */
  33. X
  34. X{
  35. X    register int i;
  36. X
  37. X    for (i=0; i < MAXVARS; i++)
  38. X        uv[i].u_name[0] = 0;
  39. X}
  40. X
  41. Xchar *gtfun(fname)    /* evaluate a function */
  42. X
  43. Xchar *fname;        /* name of function to evaluate */
  44. X
  45. X{
  46. X    register int fnum;        /* index to function to eval */
  47. X    register int status;        /* return status */
  48. X    char arg1[NSTRING];        /* value of first argument */
  49. X    char arg2[NSTRING];        /* value of second argument */
  50. X    char arg3[NSTRING];        /* value of third argument */
  51. X    static char result[2 * NSTRING];    /* string result */
  52. X
  53. X    /* look the function up in the function table */
  54. X    fname[3] = 0;    /* only first 3 chars significant */
  55. X    mklower(fname);    /* and let it be upper or lower case */
  56. X    for (fnum = 0; fnum < NFUNCS; fnum++)
  57. X        if (strcmp(fname, funcs[fnum].f_name) == 0)
  58. X            break;
  59. X
  60. X    /* return errorm on a bad reference */
  61. X    if (fnum == NFUNCS)
  62. X        return(errorm);
  63. X
  64. X    /* if needed, retrieve the first argument */
  65. X    if (funcs[fnum].f_type >= MONAMIC) {
  66. X        if ((status = macarg(arg1)) != TRUE)
  67. X            return(errorm);
  68. X
  69. X        /* if needed, retrieve the second argument */
  70. X        if (funcs[fnum].f_type >= DYNAMIC) {
  71. X            if ((status = macarg(arg2)) != TRUE)
  72. X                return(errorm);
  73. X    
  74. X            /* if needed, retrieve the third argument */
  75. X            if (funcs[fnum].f_type >= TRINAMIC)
  76. X                if ((status = macarg(arg3)) != TRUE)
  77. X                    return(errorm);
  78. X        }
  79. X    }
  80. X        
  81. X
  82. X    /* and now evaluate it! */
  83. X    switch (fnum) {
  84. X        case UFADD:    return(itoa(atoi(arg1) + atoi(arg2)));
  85. X        case UFSUB:    return(itoa(atoi(arg1) - atoi(arg2)));
  86. X        case UFTIMES:    return(itoa(atoi(arg1) * atoi(arg2)));
  87. X        case UFDIV:    return(itoa(atoi(arg1) / atoi(arg2)));
  88. X        case UFMOD:    return(itoa(atoi(arg1) % atoi(arg2)));
  89. X        case UFNEG:    return(itoa(-atoi(arg1)));
  90. X        case UFCAT:    strcpy(result, arg1);
  91. X                return(strcat(result, arg2));
  92. X        case UFLEFT:    return(strncpy(result, arg1, atoi(arg2)));
  93. X        case UFRIGHT:    return(strcpy(result, &arg1[atoi(arg2)-1]));
  94. X        case UFMID:    return(strncpy(result, &arg1[atoi(arg2)-1],
  95. X                    atoi(arg3)));
  96. X        case UFNOT:    return(ltos(stol(arg1) == FALSE));
  97. X        case UFEQUAL:    return(ltos(atoi(arg1) == atoi(arg2)));
  98. X        case UFLESS:    return(ltos(atoi(arg1) < atoi(arg2)));
  99. X        case UFGREATER:    return(ltos(atoi(arg1) > atoi(arg2)));
  100. X        case UFSEQUAL:    return(ltos(strcmp(arg1, arg2) == 0));
  101. X        case UFSLESS:    return(ltos(strcmp(arg1, arg2) < 0));
  102. X        case UFSGREAT:    return(ltos(strcmp(arg1, arg2) > 0));
  103. X        case UFIND:    return(getval(arg1));
  104. X        case UFAND:    return(ltos(stol(arg1) && stol(arg2)));
  105. X        case UFOR:    return(ltos(stol(arg1) || stol(arg2)));
  106. X        case UFLENGTH:    return(itoa(strlen(arg1)));
  107. X        case UFUPPER:    return(mkupper(arg1));
  108. X        case UFLOWER:    return(mklower(arg1));
  109. X        case UFTRUTH:    return(ltos(atoi(arg1) == 42));
  110. X        case UFASCII:    return(itoa((int)arg1[0]));
  111. X        case UFCHR:    result[0] = atoi(arg1);
  112. X                result[1] = 0;
  113. X                return(result);
  114. X        case UFGTKEY:    result[0] = tgetc();
  115. X                result[1] = 0;
  116. X                return(result);
  117. X        case UFRND:    return(itoa((ernd() % abs(atoi(arg1))) + 1));
  118. X        case UFABS:    return(itoa(abs(atoi(arg1))));
  119. X    }
  120. X
  121. X    exit(-11);    /* never should get here */
  122. X}
  123. X
  124. Xchar *gtusr(vname)    /* look up a user var's value */
  125. X
  126. Xchar *vname;        /* name of user variable to fetch */
  127. X
  128. X{
  129. X
  130. X    register int vnum;    /* ordinal number of user var */
  131. X
  132. X    /* scan the list looking for the user var name */
  133. X    for (vnum = 0; vnum < MAXVARS; vnum++)
  134. X        if (strcmp(vname, uv[vnum].u_name) == 0)
  135. X            break;
  136. X
  137. X    /* return errorm on a bad reference */
  138. X    if (vnum == MAXVARS)
  139. X        return(errorm);
  140. X
  141. X    return(uv[vnum].u_value);
  142. X}
  143. X
  144. Xchar *gtenv(vname)
  145. X
  146. Xchar *vname;        /* name of environment variable to retrieve */
  147. X
  148. X{
  149. X    register int vnum;    /* ordinal number of var refrenced */
  150. X
  151. X    /* scan the list, looking for the referenced name */
  152. X    for (vnum = 0; vnum < NEVARS; vnum++)
  153. X        if (strcmp(vname, envars[vnum]) == 0)
  154. X            break;
  155. X
  156. X    /* return errorm on a bad reference */
  157. X    if (vnum == NEVARS)
  158. X        return(errorm);
  159. X
  160. X    /* otherwise, fetch the appropriate value */
  161. X    switch (vnum) {
  162. X        case EVFILLCOL:    return(itoa(fillcol));
  163. X        case EVPAGELEN:    return(itoa(term.t_nrow + 1));
  164. X        case EVCURCOL:    return(itoa(getccol(FALSE) + 1));
  165. X        case EVCURLINE: return(itoa(getcline()));
  166. X        case EVRAM:    return(itoa((int)(envram / 1024l)));
  167. X        case EVFLICKER:    return(ltos(flickcode));
  168. X        case EVCURWIDTH:return(itoa(term.t_nrow));
  169. X        case EVCBUFNAME:return(curbp->b_bname);
  170. X        case EVCFNAME:    return(curbp->b_fname);
  171. X        case EVSRES:    return(sres);
  172. X        case EVDEBUG:    return(ltos(macbug));
  173. X        case EVSTATUS:    return(ltos(cmdstatus));
  174. X        case EVPALETTE:    return(palstr);
  175. X        case EVASAVE:    return(itoa(gasave));
  176. X        case EVACOUNT:    return(itoa(gacount));
  177. X        case EVLASTKEY: return(itoa(lastkey));
  178. X        case EVCURCHAR:    return(itoa(
  179. X                    lgetc(curwp->w_dotp,curwp->w_doto)));
  180. X        case EVDISCMD:    return(ltos(discmd));
  181. X        case EVVERSION:    return(VERSION);
  182. X        case EVPROGNAME:return(PROGNAME);
  183. X        case EVSEED:    return(itoa(seed));
  184. X        case EVDISINP:    return(ltos(disinp));
  185. X    }
  186. X    exit(-12);    /* again, we should never get here */
  187. X}
  188. X
  189. Xint setvar(f, n)        /* set a variable */
  190. X
  191. Xint f;        /* default flag */
  192. Xint n;        /* numeric arg (can overide prompted value) */
  193. X
  194. X{
  195. X    register int vnum;    /* ordinal number of var refrenced */
  196. X    register int status;    /* status return */
  197. X    register int vtype;    /* type of variable to set */
  198. X    register int c;        /* translated character */
  199. X    register char * sp;    /* scratch string pointer */
  200. X    char var[NVSIZE+1];    /* name of variable to fetch */
  201. X    char value[NSTRING];    /* value to set variable to */
  202. X
  203. X    /* first get the variable to set.. */
  204. X    if (clexec == FALSE) {
  205. X        status = mlreply("Variable to set: ", &var[0], NVSIZE);
  206. X        if (status != TRUE)
  207. X            return(status);
  208. X    } else {    /* macro line argument */
  209. X        /* grab token and skip it */
  210. X        execstr = token(execstr, var);
  211. X    }
  212. X
  213. X    /* check the legality and find the var */
  214. Xsv01:    vtype = -1;
  215. X    switch (var[0]) {
  216. X
  217. X        case '$': /* check for legal enviromnent var */
  218. X            for (vnum = 0; vnum < NEVARS; vnum++)
  219. X                if (strcmp(&var[1], envars[vnum]) == 0) {
  220. X                    vtype = TKENV;
  221. X                    break;
  222. X                }
  223. X            break;
  224. X
  225. X        case '%': /* check for existing legal user variable */
  226. X            for (vnum = 0; vnum < MAXVARS; vnum++)
  227. X                if (strcmp(&var[1], uv[vnum].u_name) == 0) {
  228. X                    vtype = TKVAR;
  229. X                    break;
  230. X                }
  231. X            if (vnum < MAXVARS)
  232. X                break;
  233. X
  234. X            /* create a new one??? */
  235. X            for (vnum = 0; vnum < MAXVARS; vnum++)
  236. X                if (uv[vnum].u_name[0] == 0) {
  237. X                    vtype = TKVAR;
  238. X                    strcpy(uv[vnum].u_name, &var[1]);
  239. X                    break;
  240. X                }
  241. X            break;
  242. X
  243. X        case '&':    /* indirect operator? */
  244. X            var[4] = 0;
  245. X            if (strcmp(&var[1], "ind") == 0) {
  246. X                /* grab token, and eval it */
  247. X                execstr = token(execstr, var);
  248. X                strcpy(var, getval(var));
  249. X                goto sv01;
  250. X            }
  251. X    }
  252. X
  253. X    /* if its not legal....bitch */
  254. X    if (vtype == -1) {
  255. X        mlwrite("%%No such variable");
  256. X        return(FALSE);
  257. X    }
  258. X
  259. X    /* get the value for that variable */
  260. X    if (f == TRUE)
  261. X        strcpy(value, itoa(n));
  262. X    else {
  263. X        status = mlreply("Value: ", &value[0], NSTRING);
  264. X        if (status != TRUE)
  265. X            return(status);
  266. X    }
  267. X
  268. X    /* and set the appropriate value */
  269. X    status = TRUE;
  270. X    switch (vtype) {
  271. X    case TKVAR: /* set a user variable */
  272. X        if (uv[vnum].u_value != NULL)
  273. X            free(uv[vnum].u_value);
  274. X        sp = malloc(strlen(value) + 1);
  275. X        if (sp == NULL)
  276. X            return(FALSE);
  277. X        strcpy(sp, value);
  278. X        uv[vnum].u_value = sp;
  279. X        break;
  280. X
  281. X    case TKENV: /* set an environment variable */
  282. X        status = TRUE;    /* by default */
  283. X        switch (vnum) {
  284. X        case EVFILLCOL:    fillcol = atoi(value);
  285. X                break;
  286. X        case EVPAGELEN:    status = newsize(TRUE, atoi(value));
  287. X                break;
  288. X        case EVCURCOL:    status = setccol(atoi(value));
  289. X                break;
  290. X        case EVCURLINE:    status = gotoline(TRUE, atoi(value));
  291. X                break;
  292. X        case EVRAM:    break;
  293. X        case EVFLICKER:    flickcode = stol(value);
  294. X                break;
  295. X        case EVCURWIDTH:status = newwidth(TRUE, atoi(value));
  296. X                break;
  297. X        case EVCBUFNAME:strcpy(curbp->b_bname, value);
  298. X                curwp->w_flag |= WFMODE;
  299. X                break;
  300. X        case EVCFNAME:    strcpy(curbp->b_fname, value);
  301. X                curwp->w_flag |= WFMODE;
  302. X                break;
  303. X        case EVSRES:    status = TTrez(value);
  304. X                break;
  305. X        case EVDEBUG:    macbug = stol(value);
  306. X                break;
  307. X        case EVSTATUS:    cmdstatus = stol(value);
  308. X                break;
  309. X        case EVPALETTE:    strncpy(palstr, value, 48);
  310. X                spal(palstr);
  311. X                break;
  312. X        case EVASAVE:    gasave = atoi(value);
  313. X                break;
  314. X        case EVACOUNT:    gacount = atoi(value);
  315. X                break;
  316. X        case EVLASTKEY:    lastkey = atoi(value);
  317. X                break;
  318. X        case EVCURCHAR:    ldelete(1, FALSE);    /* delete 1 char */
  319. X                c = atoi(value);
  320. X                if (c == '\n')
  321. X                    lnewline(FALSE, 1);
  322. X                else
  323. X                    linsert(1, c);
  324. X                break;
  325. X        case EVDISCMD:    discmd = stol(value);
  326. X                break;
  327. X        case EVVERSION:    break;
  328. X        case EVPROGNAME:break;
  329. X        case EVSEED:    seed = atoi(value);
  330. X                break;
  331. X        case EVDISINP:    disinp = stol(value);
  332. X                break;
  333. X        }
  334. X        break;
  335. X    }
  336. X    return(status);
  337. X}
  338. X
  339. X/*    atoi:    ascii string to integer......This is too
  340. X        inconsistant to use the system's    */
  341. X
  342. Xatoi(st)
  343. X
  344. Xchar *st;
  345. X
  346. X{
  347. X    int result;    /* resulting number */
  348. X    int sign;    /* sign of resulting number */
  349. X    char c;        /* current char being examined */
  350. X
  351. X    result = 0;
  352. X    sign = 1;
  353. X
  354. X    /* skip preceding whitespace */
  355. X    while (*st == ' ' || *st == '\t')
  356. X        ++st;
  357. X
  358. X    /* check for sign */
  359. X    if (*st == '-') {
  360. X        sign = -1;
  361. X        ++st;
  362. X    }
  363. X    if (*st == '+')
  364. X        ++st;
  365. X
  366. X    /* scan digits, build value */
  367. X    while ((c = *st++))
  368. X        if (c >= '0' && c <= '9')
  369. X            result = result * 10 + c - '0';
  370. X        else
  371. X            return(0);
  372. X
  373. X    return(result * sign);
  374. X}
  375. X
  376. X/*    itoa:    integer to ascii string.......... This is too
  377. X        inconsistant to use the system's    */
  378. X
  379. Xchar *itoa(i)
  380. X
  381. Xint i;    /* integer to translate to a string */
  382. X
  383. X{
  384. X    register int digit;        /* current digit being used */
  385. X    register char *sp;        /* pointer into result */
  386. X    register int sign;        /* sign of resulting number */
  387. X    static char result[INTWIDTH+1];    /* resulting string */
  388. X
  389. X    /* eliminate the trivial 0 */
  390. X    if (i == 0)
  391. X        return("0");
  392. X
  393. X    /* record the sign...*/
  394. X    sign = 1;
  395. X    if (i < 0) {
  396. X        sign = -1;
  397. X        i = -i;
  398. X    }
  399. X
  400. X    /* and build the string (backwards!) */
  401. X    sp = result + INTWIDTH;
  402. X    *sp = 0;
  403. X    while (i) {
  404. X        digit = i % 10;
  405. X        *(--sp) = '0' + digit;    /* and install the new digit */
  406. X        i = i / 10;
  407. X    }
  408. X
  409. X    /* and fix the sign */
  410. X    if (sign == -1) {
  411. X        *(--sp) = '-';    /* and install the minus sign */
  412. X    }
  413. X
  414. X    return(sp);
  415. X}
  416. X
  417. Xint gettyp(token)    /* find the type of a passed token */
  418. X
  419. Xchar *token;    /* token to analyze */
  420. X
  421. X{
  422. X    register char c;    /* first char in token */
  423. X
  424. X    /* grab the first char (this is all we need) */
  425. X    c = *token;
  426. X
  427. X    /* no blanks!!! */
  428. X    if (c == 0)
  429. X        return(TKNUL);
  430. X
  431. X    /* a numeric literal? */
  432. X    if (c >= '0' && c <= '9')
  433. X        return(TKLIT);
  434. X
  435. X    switch (c) {
  436. X        case '"':    return(TKSTR);
  437. X
  438. X        case '!':    return(TKDIR);
  439. X        case '@':    return(TKARG);
  440. X        case '#':    return(TKBUF);
  441. X        case '$':    return(TKENV);
  442. X        case '%':    return(TKVAR);
  443. X        case '&':    return(TKFUN);
  444. X        case '*':    return(TKLBL);
  445. X
  446. X        default:    return(TKCMD);
  447. X    }
  448. X}
  449. X
  450. Xchar *getval(token)    /* find the value of a token */
  451. X
  452. Xchar *token;        /* token to evaluate */
  453. X
  454. X{
  455. X    register int status;    /* error return */
  456. X    register BUFFER *bp;    /* temp buffer pointer */
  457. X    register int blen;    /* length of buffer argument */
  458. X    char pad[20];        /* pad 20 bytes on stack for safety */
  459. X    char buf[NSTRING];    /* string buffer for some returns */
  460. X
  461. X    switch (gettyp(token)) {
  462. X        case TKNUL:    return("");
  463. X
  464. X        case TKARG:    /* interactive argument */
  465. X                strcpy(token, getval(&token[1]));
  466. X                status = getstring(token,
  467. X                       buf, NSTRING, ctoec('\n'));
  468. X                if (status == ABORT)
  469. X                    return(errorm);
  470. X                return(buf);
  471. X
  472. X        case TKBUF:    /* buffer contents fetch */
  473. X
  474. X                /* grab the right buffer */
  475. X                strcpy(token, getval(&token[1]));
  476. X                bp = bfind(token, FALSE, 0);
  477. X                if (bp == NULL)
  478. X                    return(errorm);
  479. X        
  480. X                /* if the buffer is displayed, get the window
  481. X                   vars instead of the buffer vars */
  482. X                if (bp->b_nwnd > 0) {
  483. X                    curbp->b_dotp = curwp->w_dotp;
  484. X                    curbp->b_doto = curwp->w_doto;
  485. X                }
  486. X
  487. X                /* make sure we are not at the end */
  488. X                if (bp->b_linep == bp->b_dotp)
  489. X                    return(errorm);
  490. X        
  491. X                /* grab the line as an argument */
  492. X                blen = bp->b_dotp->l_used - bp->b_doto;
  493. X                if (blen > NSTRING)
  494. X                    blen = NSTRING;
  495. X                strncpy(buf, bp->b_dotp->l_text + bp->b_doto,
  496. X                    blen);
  497. X                buf[blen] = 0;
  498. X        
  499. X                /* and step the buffer's line ptr ahead a line */
  500. X                bp->b_dotp = bp->b_dotp->l_fp;
  501. X                bp->b_doto = 0;
  502. X
  503. X                /* if displayed buffer, reset window ptr vars*/
  504. X                if (bp->b_nwnd > 0) {
  505. X                    curwp->w_dotp = curbp->b_dotp;
  506. X                    curwp->w_doto = 0;
  507. X                    curwp->w_flag |= WFMOVE;
  508. X                }
  509. X
  510. X                /* and return the spoils */
  511. X                return(buf);        
  512. X
  513. X        case TKVAR:    return(gtusr(token+1));
  514. X        case TKENV:    return(gtenv(token+1));
  515. X        case TKFUN:    return(gtfun(token+1));
  516. X        case TKDIR:    return(errorm);
  517. X        case TKLBL:    return(itoa(gtlbl(token)));
  518. X        case TKLIT:    return(token);
  519. X        case TKSTR:    return(token+1);
  520. X        case TKCMD:    return(token);
  521. X    }
  522. X}
  523. X
  524. Xgtlbl(token)    /* find the line number of the given label */
  525. X
  526. Xchar *token;    /* label name to find */
  527. X
  528. X{
  529. X    return(1);
  530. X}
  531. X
  532. Xint stol(val)    /* convert a string to a numeric logical */
  533. X
  534. Xchar *val;    /* value to check for stol */
  535. X
  536. X{
  537. X    /* check for logical values */
  538. X    if (val[0] == 'F')
  539. X        return(FALSE);
  540. X    if (val[0] == 'T')
  541. X        return(TRUE);
  542. X
  543. X    /* check for numeric truth (!= 0) */
  544. X    return((atoi(val) != 0));
  545. X}
  546. X
  547. Xchar *ltos(val)        /* numeric logical to string logical */
  548. X
  549. Xint val;    /* value to translate */
  550. X
  551. X{
  552. X    if (val)
  553. X        return(truem);
  554. X    else
  555. X        return(falsem);
  556. X}
  557. X
  558. Xchar *mkupper(str)    /* make a string upper case */
  559. X
  560. Xchar *str;        /* string to upper case */
  561. X
  562. X{
  563. X    char *sp;
  564. X
  565. X    sp = str;
  566. X    while (*sp) {
  567. X        if ('a' <= *sp && *sp <= 'z')
  568. X            *sp += 'A' - 'a';
  569. X        ++sp;
  570. X    }
  571. X    return(str);
  572. X}
  573. X
  574. Xchar *mklower(str)    /* make a string lower case */
  575. X
  576. Xchar *str;        /* string to lower case */
  577. X
  578. X{
  579. X    char *sp;
  580. X
  581. X    sp = str;
  582. X    while (*sp) {
  583. X        if ('A' <= *sp && *sp <= 'Z')
  584. X            *sp += 'a' - 'A';
  585. X        ++sp;
  586. X    }
  587. X    return(str);
  588. X}
  589. X
  590. Xint abs(x)    /* take the absolute value of an integer */
  591. X
  592. Xint x;
  593. X
  594. X{
  595. X    return(x < 0 ? -x : x);
  596. X}
  597. X
  598. Xint ernd()    /* returns a random integer */
  599. X
  600. X{
  601. X    seed = abs(seed * 1721 + 10007);
  602. X    return(seed);
  603. X}
  604. E!O!F
  605. newsize=`wc -c < eval.c`
  606. if [ $newsize -ne 13772 ]
  607. then echo "File eval.c was $newsize bytes, 13772 expected"
  608. fi
  609. echo 'x - evar.h (text)'
  610. sed << 'E!O!F' 's/^X//' > evar.h
  611. X/*    EVAR.H:    Environment and user variable definitions
  612. X        for MicroEMACS
  613. X
  614. X        written 1986 by Daniel Lawrence
  615. X*/
  616. X
  617. X/*    structure to hold user variables and their definitions    */
  618. X
  619. Xtypedef struct UVAR {
  620. X    char u_name[NVSIZE + 1];        /* name of user variable */
  621. X    char *u_value;                /* value (string) */
  622. X} UVAR;
  623. X
  624. X/*    current user variables (This structure will probably change)    */
  625. X
  626. X#define    MAXVARS        100
  627. X
  628. XUVAR uv[MAXVARS];    /* user variables */
  629. X
  630. X/*    list of recognized environment variables    */
  631. X
  632. Xchar *envars[] = {
  633. X    "fillcol",        /* current fill column */
  634. X    "pagelen",        /* number of lines used by editor */
  635. X    "curcol",        /* current column pos of cursor */
  636. X    "curline",        /* current line in file */
  637. X    "ram",            /* ram in use by malloc */
  638. X    "flicker",        /* flicker supression */
  639. X    "curwidth",        /* current screen width */
  640. X    "cbufname",        /* current buffer name */
  641. X    "cfname",        /* current file name */
  642. X    "sres",            /* current screen resolution */
  643. X    "debug",        /* macro debugging */
  644. X    "status",        /* returns the status of the last command */
  645. X    "palette",        /* current palette string */
  646. X    "asave",        /* # of chars between auto-saves */
  647. X    "acount",        /* # of chars until next auto-save */
  648. X    "lastkey",        /* last keyboard char struck */
  649. X    "curchar",        /* current character under the cursor */
  650. X    "discmd",        /* display commands on command line */
  651. X    "version",        /* current version number */
  652. X    "progname",        /* returns current prog name - "MicroEMACS" */
  653. X    "seed",            /* current random number seed */
  654. X    "disinp",        /* display command line input characters */
  655. X};
  656. X
  657. X#define    NEVARS    sizeof(envars) / sizeof(char *)
  658. X
  659. X/*     and its preprocesor definitions        */
  660. X
  661. X#define    EVFILLCOL    0
  662. X#define    EVPAGELEN    1
  663. X#define    EVCURCOL    2
  664. X#define    EVCURLINE    3
  665. X#define    EVRAM        4
  666. X#define    EVFLICKER    5
  667. X#define    EVCURWIDTH    6
  668. X#define    EVCBUFNAME    7
  669. X#define    EVCFNAME    8
  670. X#define    EVSRES        9
  671. X#define    EVDEBUG        10
  672. X#define    EVSTATUS    11
  673. X#define    EVPALETTE    12
  674. X#define    EVASAVE        13
  675. X#define    EVACOUNT    14
  676. X#define    EVLASTKEY    15
  677. X#define    EVCURCHAR    16
  678. X#define    EVDISCMD    17
  679. X#define    EVVERSION    18
  680. X#define    EVPROGNAME    19
  681. X#define    EVSEED        20
  682. X#define    EVDISINP    21
  683. X
  684. X/*    list of recognized user functions    */
  685. X
  686. Xtypedef struct UFUNC {
  687. X    char *f_name;    /* name of function */
  688. X    int f_type;    /* 1 = monamic, 2 = dynamic */
  689. X} UFUNC;
  690. X
  691. X#define    NILNAMIC    0
  692. X#define    MONAMIC        1
  693. X#define    DYNAMIC        2
  694. X#define    TRINAMIC    3
  695. X
  696. XUFUNC funcs[] = {
  697. X    "add", DYNAMIC,        /* add two numbers together */
  698. X    "sub", DYNAMIC,        /* subtraction */
  699. X    "tim", DYNAMIC,        /* multiplication */
  700. X    "div", DYNAMIC,        /* division */
  701. X    "mod", DYNAMIC,        /* mod */
  702. X    "neg", MONAMIC,        /* negate */
  703. X    "cat", DYNAMIC,        /* concatinate string */
  704. X    "lef", DYNAMIC,        /* left string(string, len) */
  705. X    "rig", DYNAMIC,        /* right string(string, pos) */
  706. X    "mid", TRINAMIC,    /* mid string(string, pos, len) */
  707. X    "not", MONAMIC,        /* logical not */
  708. X    "equ", DYNAMIC,        /* logical equality check */
  709. X    "les", DYNAMIC,        /* logical less than */
  710. X    "gre", DYNAMIC,        /* logical greater than */
  711. X    "seq", DYNAMIC,        /* string logical equality check */
  712. X    "sle", DYNAMIC,        /* string logical less than */
  713. X    "sgr", DYNAMIC,        /* string logical greater than */
  714. X    "ind", MONAMIC,        /* evaluate indirect value */
  715. X    "and", DYNAMIC,        /* logical and */
  716. X    "or",  DYNAMIC,        /* logical or */
  717. X    "len", MONAMIC,        /* string length */
  718. X    "upp", MONAMIC,        /* uppercase string */
  719. X    "low", MONAMIC,        /* lower case string */
  720. X    "tru", MONAMIC,        /* Truth of the universe logical test */
  721. X    "asc", MONAMIC,        /* char to integer conversion */
  722. X    "chr", MONAMIC,        /* integer to char conversion */
  723. X    "gtk", NILNAMIC,    /* get 1 charater */
  724. X    "rnd", MONAMIC,        /* get a random number */
  725. X    "abs", MONAMIC,        /* absolute value of a number */
  726. X};
  727. X
  728. X#define    NFUNCS    sizeof(funcs) / sizeof(UFUNC)
  729. X
  730. X/*     and its preprocesor definitions        */
  731. X
  732. X#define    UFADD        0
  733. X#define    UFSUB        1
  734. X#define    UFTIMES        2
  735. X#define    UFDIV        3
  736. X#define    UFMOD        4
  737. X#define    UFNEG        5
  738. X#define    UFCAT        6
  739. X#define    UFLEFT        7
  740. X#define    UFRIGHT        8
  741. X#define    UFMID        9
  742. X#define    UFNOT        10
  743. X#define    UFEQUAL        11
  744. X#define    UFLESS        12
  745. X#define    UFGREATER    13
  746. X#define    UFSEQUAL    14
  747. X#define    UFSLESS        15
  748. X#define    UFSGREAT    16
  749. X#define    UFIND        17
  750. X#define    UFAND        18
  751. X#define    UFOR        19
  752. X#define    UFLENGTH    20
  753. X#define    UFUPPER        21
  754. X#define    UFLOWER        22
  755. X#define    UFTRUTH        23
  756. X#define    UFASCII        24
  757. X#define    UFCHR        25
  758. X#define    UFGTKEY        26
  759. X#define    UFRND        27
  760. X#define    UFABS        28
  761. E!O!F
  762. newsize=`wc -c < evar.h`
  763. if [ $newsize -ne 4174 ]
  764. then echo "File evar.h was $newsize bytes, 4174 expected"
  765. fi
  766. echo 'x - exec.c (text)'
  767. sed << 'E!O!F' 's/^X//' > exec.c
  768. X/*    This file is for functions dealing with execution of
  769. X    commands, command lines, buffers, files and startup files
  770. X
  771. X    written 1986 by Daniel Lawrence                */
  772. X
  773. X#include    <stdio.h>
  774. X#include    "estruct.h"
  775. X#include    "edef.h"
  776. X
  777. X#if    MEGAMAX & ST520
  778. Xoverlay    "exec"
  779. X#endif
  780. X
  781. X#if    DEBUGM
  782. Xchar outline[NSTRING];        /* global string to hold debug line text */
  783. X#endif
  784. X
  785. X/* namedcmd:    execute a named command even if it is not bound */
  786. X
  787. Xnamedcmd(f, n)
  788. X
  789. Xint f, n;    /* command arguments [passed through to command executed] */
  790. X
  791. X{
  792. X    register (*kfunc)();    /* ptr to the requexted function to bind to */
  793. X    int (*getname())();
  794. X
  795. X    /* prompt the user to type a named command */
  796. X    mlwrite(": ");
  797. X
  798. X    /* and now get the function name to execute */
  799. X    kfunc = getname();
  800. X    if (kfunc == NULL) {
  801. X        mlwrite("[No such function]");
  802. X        return(FALSE);
  803. X    }
  804. X
  805. X    /* and then execute the command */
  806. X    return((*kfunc)(f, n));
  807. X}
  808. X
  809. X/*    execcmd:    Execute a command line command to be typed in
  810. X            by the user                    */
  811. X
  812. Xexeccmd(f, n)
  813. X
  814. Xint f, n;    /* default Flag and Numeric argument */
  815. X
  816. X{
  817. X    register int status;        /* status return */
  818. X    char cmdstr[NSTRING];        /* string holding command to execute */
  819. X
  820. X    /* get the line wanted */
  821. X    if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  822. X        return(status);
  823. X
  824. X    execlevel = 0;
  825. X    return(docmd(cmdstr));
  826. X}
  827. X
  828. X/*    docmd:    take a passed string as a command line and translate
  829. X        it to be executed as a command. This function will be
  830. X        used by execute-command-line and by all source and
  831. X        startup files. Lastflag/thisflag is also updated.
  832. X
  833. X    format of the command line is:
  834. X
  835. X        {# arg} <command-name> {<argument string(s)>}
  836. X
  837. X    Directives start with a "!" and include:
  838. X
  839. X    !endm        End a macro
  840. X    !if (cond)    conditional execution
  841. X    !else
  842. X    !endif
  843. X    !return        Return (terminating current macro)
  844. X    !goto <label>    Jump to a label in the current macro
  845. X
  846. X    Line Labels begin with a "*" in column 1, like:
  847. X
  848. X    *LBL01
  849. X*/
  850. X
  851. Xdocmd(cline)
  852. X
  853. Xchar *cline;    /* command line to execute */
  854. X
  855. X{
  856. X    register int f;        /* default argument flag */
  857. X    register int n;        /* numeric repeat value */
  858. X    register int i;
  859. X    int (*fnc)();        /* function to execute */
  860. X    int status;        /* return status of function */
  861. X    int oldcle;        /* old contents of clexec flag */
  862. X    int llen;        /* length of cline */
  863. X    int force;        /* force TRUE result? */
  864. X    char *tmp;        /* tmp pointer into cline */
  865. X    struct LINE *lp;    /* a line pointer */
  866. X    char *oldestr;        /* original exec string */
  867. X    char token[NSTRING];    /* next token off of command line */
  868. X    int (*fncmatch())();
  869. X#if    DEBUGM
  870. X    /* if $debug == TRUE, every line to execute
  871. X       gets echoed and a key needs to be pressed to continue
  872. X       ^G will abort the command */
  873. X    register char *sp;    /* pointer into buf to expand %s */
  874. X
  875. X    if (macbug) {
  876. X        strcpy(outline, "<<<");
  877. X#if    1    /* debug if levels */
  878. X        strcat(outline, itoa(execlevel));
  879. X        strcat(outline, ":");
  880. X#endif
  881. X        strcat(outline, cline);
  882. X        strcat(outline, ">>>");
  883. X
  884. X        /* change all '%' to ':' so mlwrite won't expect arguments */
  885. X        sp = outline;
  886. X        while (*sp) {
  887. X            if (*sp++ == '%')
  888. X                *(sp-1) = ':';
  889. X        }
  890. X
  891. X        /* write out the debug line */
  892. X        mlwrite(outline);
  893. X        update(TRUE);
  894. X
  895. X        /* and get the keystroke */
  896. X        if (tgetc() == 7) {
  897. X            mlwrite("[Macro aborted]");
  898. X            return(FALSE);
  899. X        }
  900. X    }
  901. X#endif
  902. X        
  903. X    /* dump comments here */
  904. X    if (*cline == ';')
  905. X        return(TRUE);
  906. X
  907. X    /* eat leading spaces */
  908. X    while (*cline == ' ' || *cline == '\t')
  909. X        ++cline;
  910. X
  911. X    /* check to see if this line turns macro storage off */
  912. X    if (cline[0] == '!' && strncmp(&cline[1], "endm", 4) == 0) {
  913. X        mstore = FALSE;
  914. X        bstore = NULL;
  915. X        return(TRUE);
  916. X    }
  917. X
  918. X    /* if macro store is on, just salt this away */
  919. X    if (mstore) {
  920. X        /* allocate the space for the line */
  921. X        llen = strlen(cline);
  922. X        if ((lp=lalloc(llen)) == NULL) {
  923. X            mlwrite("Out of memory while storing macro");
  924. X            return (FALSE);
  925. X        }
  926. X
  927. X        /* copy the text into the new line */
  928. X        for (i=0; i<llen; ++i)
  929. X            lputc(lp, i, cline[i]);
  930. X
  931. X        /* attach the line to the end of the buffer */
  932. X               bstore->b_linep->l_bp->l_fp = lp;
  933. X        lp->l_bp = bstore->b_linep->l_bp;
  934. X        bstore->b_linep->l_bp = lp;
  935. X        lp->l_fp = bstore->b_linep;
  936. X        return (TRUE);
  937. X    }
  938. X    
  939. X    /* dump labels here */
  940. X    if (*cline == '*')
  941. X        return(TRUE);
  942. X
  943. X    force = FALSE;
  944. X    oldestr = execstr;    /* save last ptr to string to execute */
  945. X    execstr = cline;    /* and set this one as current */
  946. X
  947. X    /* process directives */
  948. X    if (*cline == '!') {
  949. X        /* save directive location and skip it */
  950. X        tmp = cline;
  951. X        while (*execstr && *execstr != ' ' && *execstr != '\t')
  952. X            ++execstr;
  953. X
  954. X        if (tmp[1] == 'f' && tmp[2] == 'o') {
  955. X            force = TRUE;
  956. X            goto do001;
  957. X
  958. X        } else if (tmp[1] == 'i' && tmp[2] == 'f') {
  959. X
  960. X            /* IF directive */
  961. X            /* grab the value of the logical exp */
  962. X            if (execlevel == 0) {
  963. X                if ((status = macarg(token)) != TRUE) {
  964. X                    execstr = oldestr;
  965. X                    return(status);
  966. X                }
  967. X                status = stol(token);
  968. X            } else
  969. X                status = TRUE;
  970. X
  971. X            if (status) {
  972. X
  973. X                /* IF (TRUE) */
  974. X                if (execlevel != 0)
  975. X                    ++execlevel;
  976. X            } else {
  977. X
  978. X                /* IF (FALSE) */
  979. X                ++execlevel;
  980. X            }
  981. X
  982. X        } else if (tmp[1] == 'e' && tmp[2] == 'l') {
  983. X
  984. X            /* ELSE directive */
  985. X            if (execlevel == 1)
  986. X                --execlevel;
  987. X            else if (execlevel == 0 )
  988. X                ++execlevel;
  989. X
  990. X        } else if (tmp[1] == 'e' && tmp[2] == 'n') {
  991. X
  992. X            /* ENDIF directive */
  993. X            if (execlevel)
  994. X                --execlevel;
  995. X
  996. X        } else if (tmp[1] == 'r' && tmp[2] == 'e') {
  997. X
  998. X            /* RETURN directive */
  999. X            execstr = oldestr;
  1000. X            if (execlevel)
  1001. X                return(TRUE);
  1002. X            else
  1003. X                return(RET);
  1004. X
  1005. X        } else if (tmp[1] == 'g' && tmp[2] == 'o') {
  1006. X
  1007. X            /* GOTO directive */
  1008. X            /* .....only if we are currently executing */
  1009. X            if (execlevel) {
  1010. X                execstr = oldestr;
  1011. X                return(TRUE);
  1012. X            }
  1013. X
  1014. X            while (*execstr == ' ' || *execstr == '\t')
  1015. X                ++execstr;
  1016. X            strncpy(golabel, execstr, NPAT - 1);
  1017. X            return(GOLINE);
  1018. X
  1019. X        } else {
  1020. X            mlwrite("%%Unknown Directive");
  1021. X            return(FALSE);
  1022. X        }
  1023. X
  1024. X        /* restore execstr and exit */
  1025. X        execstr = oldestr;
  1026. X        return(TRUE);
  1027. X    }
  1028. X
  1029. Xdo001:    /* if we are scanning and not executing..go back here */
  1030. X    if (execlevel) {
  1031. X        execstr = oldestr;
  1032. X        return(TRUE);
  1033. X    }
  1034. X
  1035. X    /* first set up the default command values */
  1036. X    f = FALSE;
  1037. X    n = 1;
  1038. X    lastflag = thisflag;
  1039. X    thisflag = 0;
  1040. X
  1041. X    if ((status = macarg(token)) != TRUE) {    /* and grab the first token */
  1042. X        execstr = oldestr;
  1043. X        return(status);
  1044. X    }
  1045. X
  1046. X    /* process leadin argument */
  1047. X    if (gettyp(token) != TKCMD) {
  1048. X        f = TRUE;
  1049. X        strcpy(token, getval(token));
  1050. X        n = atoi(token);
  1051. X
  1052. X        /* and now get the command to execute */
  1053. X        if ((status = macarg(token)) != TRUE) {
  1054. X            execstr = oldestr;
  1055. X            return(status);    
  1056. X        }    
  1057. X    }
  1058. X
  1059. X    /* and match the token to see if it exists */
  1060. X    if ((fnc = fncmatch(token)) == NULL) {
  1061. X        mlwrite("[No such Function]");
  1062. X        execstr = oldestr;
  1063. X        return(FALSE);
  1064. X    }
  1065. X    
  1066. X    /* save the arguments and go execute the command */
  1067. X    oldcle = clexec;        /* save old clexec flag */
  1068. X    clexec = TRUE;            /* in cline execution */
  1069. X    status = (*fnc)(f, n);        /* call the function */
  1070. X    cmdstatus = status;        /* save the status */
  1071. X    if (force)            /* force the status */
  1072. X        status = TRUE;
  1073. X    clexec = oldcle;        /* restore clexec flag */
  1074. X    execstr = oldestr;
  1075. X    return(status);
  1076. X}
  1077. X
  1078. X/* token:    chop a token off a string
  1079. X        return a pointer past the token
  1080. X*/
  1081. X
  1082. Xchar *token(src, tok)
  1083. X
  1084. Xchar *src, *tok;    /* source string, destination token string */
  1085. X
  1086. X{
  1087. X    register int quotef;    /* is the current string quoted? */
  1088. X
  1089. X    /* first scan past any whitespace in the source string */
  1090. X    while (*src == ' ' || *src == '\t')
  1091. X        ++src;
  1092. X
  1093. X    /* scan through the source string */
  1094. X    quotef = FALSE;
  1095. X    while (*src) {
  1096. X        /* process special characters */
  1097. X        if (*src == '~') {
  1098. X            ++src;
  1099. X            if (*src == 0)
  1100. X                break;
  1101. X            switch (*src++) {
  1102. X                case 'r':    *tok++ = 13; break;
  1103. X                case 'n':    *tok++ = 10; break;
  1104. X                case 't':    *tok++ = 9;  break;
  1105. X                case 'b':    *tok++ = 8;  break;
  1106. X                case 'f':    *tok++ = 12; break;
  1107. X                default:    *tok++ = *(src-1);
  1108. X            }
  1109. X        } else {
  1110. X            /* check for the end of the token */
  1111. X            if (quotef) {
  1112. X                if (*src == '"')
  1113. X                    break;
  1114. X            } else {
  1115. X                if (*src == ' ' || *src == '\t')
  1116. X                    break;
  1117. X            }
  1118. X
  1119. X            /* set quote mode if qoute found */
  1120. X            if (*src == '"')
  1121. X                quotef = TRUE;
  1122. X
  1123. X            /* record the character */
  1124. X            *tok++ = *src++;
  1125. X        }
  1126. X    }
  1127. X
  1128. X    /* terminate the token and exit */
  1129. X    if (*src)
  1130. X        ++src;
  1131. X    *tok = 0;
  1132. X    return(src);
  1133. X}
  1134. X
  1135. Xmacarg(tok)    /* get a macro line argument */
  1136. X
  1137. Xchar *tok;    /* buffer to place argument */
  1138. X
  1139. X{
  1140. X    int savcle;    /* buffer to store original clexec */
  1141. X    int status;
  1142. X
  1143. X    savcle = clexec;    /* save execution mode */
  1144. X    clexec = TRUE;        /* get the argument */
  1145. X    status = nextarg("", tok, NSTRING, ctoec('\n'));
  1146. X    clexec = savcle;    /* restore execution mode */
  1147. X    return(status);
  1148. X}
  1149. X
  1150. X/*    nextarg:    get the next argument    */
  1151. X
  1152. Xnextarg(prompt, buffer, size, terminator)
  1153. X
  1154. Xchar *prompt;        /* prompt to use if we must be interactive */
  1155. Xchar *buffer;        /* buffer to put token into */
  1156. Xchar *size;        /* size of the buffer */
  1157. Xint terminator;        /* terminating char to be used on interactive fetch */
  1158. X
  1159. X{
  1160. X    /* if we are interactive, go get it! */
  1161. X    if (clexec == FALSE)
  1162. X        return(getstring(prompt, buffer, size, terminator));
  1163. X
  1164. X    /* grab token and advance past */
  1165. X    execstr = token(execstr, buffer);
  1166. X
  1167. X    /* evaluate it */
  1168. X    strcpy(buffer, getval(buffer));
  1169. X    return(TRUE);
  1170. X}
  1171. X
  1172. X/*    storemac:    Set up a macro buffer and flag to store all
  1173. X            executed command lines there            */
  1174. X
  1175. Xstoremac(f, n)
  1176. X
  1177. Xint f;        /* default flag */
  1178. Xint n;        /* macro number to use */
  1179. X
  1180. X{
  1181. X    register struct BUFFER *bp;    /* pointer to macro buffer */
  1182. X    char bname[NBUFN];        /* name of buffer to use */
  1183. X
  1184. X    /* must have a numeric argument to this function */
  1185. X    if (f == FALSE) {
  1186. X        mlwrite("No macro specified");
  1187. X        return(FALSE);
  1188. X    }
  1189. X
  1190. X    /* range check the macro number */
  1191. X    if (n < 1 || n > 40) {
  1192. X        mlwrite("Macro number out of range");
  1193. X        return(FALSE);
  1194. X    }
  1195. X
  1196. X    /* construct the macro buffer name */
  1197. X    strcpy(bname, "[Macro xx]");
  1198. X    bname[7] = '0' + (n / 10);
  1199. X    bname[8] = '0' + (n % 10);
  1200. X
  1201. X    /* set up the new macro buffer */
  1202. X    if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  1203. X        mlwrite("Can not create macro");
  1204. X        return(FALSE);
  1205. X    }
  1206. X
  1207. X    /* and make sure it is empty */
  1208. X    bclear(bp);
  1209. X
  1210. X    /* and set the macro store pointers to it */
  1211. X    mstore = TRUE;
  1212. X    bstore = bp;
  1213. X    return(TRUE);
  1214. X}
  1215. X
  1216. X#if    PROC
  1217. X/*    storeproc:    Set up a procedure buffer and flag to store all
  1218. X            executed command lines there            */
  1219. X
  1220. Xstoreproc(f, n)
  1221. X
  1222. Xint f;        /* default flag */
  1223. Xint n;        /* macro number to use */
  1224. X
  1225. X{
  1226. X    register struct BUFFER *bp;    /* pointer to macro buffer */
  1227. X    register int status;        /* return status */
  1228. X    char bname[NBUFN];        /* name of buffer to use */
  1229. X
  1230. X    /* a numeric argument means its a numbered macro */
  1231. X    if (f == TRUE)
  1232. X        return(storemac(f, n));
  1233. X
  1234. X    /* get the name of the procedure */
  1235. X        if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
  1236. X                return(status);
  1237. X
  1238. X    /* construct the macro buffer name */
  1239. X    bname[0] = '[';
  1240. X    strcat(bname, "]");
  1241. X
  1242. X    /* set up the new macro buffer */
  1243. X    if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  1244. X        mlwrite("Can not create macro");
  1245. X        return(FALSE);
  1246. X    }
  1247. X
  1248. X    /* and make sure it is empty */
  1249. X    bclear(bp);
  1250. X
  1251. X    /* and set the macro store pointers to it */
  1252. X    mstore = TRUE;
  1253. X    bstore = bp;
  1254. X    return(TRUE);
  1255. X}
  1256. X
  1257. X/*    execproc:    Execute a procedure                */
  1258. X
  1259. Xexecproc(f, n)
  1260. X
  1261. Xint f, n;    /* default flag and numeric arg */
  1262. X
  1263. X{
  1264. X        register BUFFER *bp;        /* ptr to buffer to execute */
  1265. X        register int status;        /* status return */
  1266. X        char bufn[NBUFN+2];        /* name of buffer to execute */
  1267. X
  1268. X    /* find out what buffer the user wants to execute */
  1269. X        if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
  1270. X                return(status);
  1271. X
  1272. X    /* construct the buffer name */
  1273. X    bufn[0] = '[';
  1274. X    strcat(bufn, "]");
  1275. X
  1276. X    /* find the pointer to that buffer */
  1277. X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  1278. X        mlwrite("No such procedure");
  1279. X                return(FALSE);
  1280. X        }
  1281. X
  1282. X    /* and now execute it as asked */
  1283. X    while (n-- > 0)
  1284. X        if ((status = dobuf(bp)) != TRUE)
  1285. X            return(status);
  1286. X    return(TRUE);
  1287. X}
  1288. X#endif
  1289. X
  1290. X/*    execbuf:    Execute the contents of a buffer of commands    */
  1291. X
  1292. Xexecbuf(f, n)
  1293. X
  1294. Xint f, n;    /* default flag and numeric arg */
  1295. X
  1296. X{
  1297. X        register BUFFER *bp;        /* ptr to buffer to execute */
  1298. X        register int status;        /* status return */
  1299. X        char bufn[NBUFN];        /* name of buffer to execute */
  1300. X
  1301. X    /* find out what buffer the user wants to execute */
  1302. X        if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
  1303. X                return(status);
  1304. X
  1305. X    /* find the pointer to that buffer */
  1306. X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  1307. X        mlwrite("No such buffer");
  1308. X                return(FALSE);
  1309. X        }
  1310. X
  1311. X    /* and now execute it as asked */
  1312. X    while (n-- > 0)
  1313. X        if ((status = dobuf(bp)) != TRUE)
  1314. X            return(status);
  1315. X    return(TRUE);
  1316. X}
  1317. X
  1318. X/*    dobuf:    execute the contents of the buffer pointed to
  1319. X        by the passed BP                */
  1320. X
  1321. Xdobuf(bp)
  1322. X
  1323. XBUFFER *bp;    /* buffer to execute */
  1324. X
  1325. X{
  1326. X        register int status;        /* status return */
  1327. X    register LINE *lp;        /* pointer to line to execute */
  1328. X    register LINE *hlp;        /* pointer to line header */
  1329. X    register LINE *glp;        /* line to goto */
  1330. X    register int linlen;        /* length of line to execute */
  1331. X    register WINDOW *wp;        /* ptr to windows to scan */
  1332. X    char *eline;            /* text of line to execute */
  1333. X
  1334. X    /* clear IF level flags */
  1335. X    execlevel = 0;
  1336. X
  1337. X    /* starting at the beginning of the buffer */
  1338. X    hlp = bp->b_linep;
  1339. X    lp = hlp->l_fp;
  1340. X    while (lp != hlp) {
  1341. X        /* allocate eline and copy macro line to it */
  1342. X        linlen = lp->l_used;
  1343. X        if ((eline = malloc(linlen+1)) == NULL) {
  1344. X            mlwrite("%%Out of Memory during macro execution");
  1345. X            return(FALSE);
  1346. X        }
  1347. X        strncpy(eline, lp->l_text, linlen);
  1348. X        eline[linlen] = 0;    /* make sure it ends */
  1349. X
  1350. X        /* trim leading whitespace */
  1351. X        while (eline[0] == ' ' || eline[0] == '\t')
  1352. X            strcpy(eline, &eline[1]);
  1353. X
  1354. X        /* if it is not a comment, execute it */
  1355. X        if (eline[0] != 0 && eline[0] != ';') {
  1356. X            status = docmd(eline);
  1357. X
  1358. X            /* if it is a !GOTO directive, deal with it */
  1359. X            if (status == GOLINE) {
  1360. X                linlen = strlen(golabel);
  1361. X                glp = hlp->l_fp;
  1362. X                while (glp != hlp) {
  1363. X                    if (*glp->l_text == '*' &&
  1364. X                        (strncmp(&glp->l_text[1], golabel,
  1365. X                                linlen) == 0)) {
  1366. X                        lp = glp;
  1367. X                        status = TRUE;
  1368. X                    }
  1369. X                glp = glp->l_fp;
  1370. X                }
  1371. X            }
  1372. X
  1373. X            if (status == GOLINE) {
  1374. X                mlwrite("%%No such label");
  1375. X                return(FALSE);
  1376. X            }
  1377. X
  1378. X            /* if it is a !RETURN directive...do so */
  1379. X            if (status == RET) {
  1380. X                free(eline);
  1381. X                break;
  1382. X            }
  1383. X
  1384. X            /* check for a command error */
  1385. X            if (status != TRUE) {
  1386. X                /* look if buffer is showing */
  1387. X                wp = wheadp;
  1388. X                while (wp != NULL) {
  1389. X                    if (wp->w_bufp == bp) {
  1390. X                        /* and point it */
  1391. X                        wp->w_dotp = lp;
  1392. X                        wp->w_doto = 0;
  1393. X                        wp->w_flag |= WFHARD;
  1394. X                    }
  1395. X                    wp = wp->w_wndp;
  1396. X                }
  1397. X                /* in any case set the buffer . */
  1398. X                bp->b_dotp = lp;
  1399. X                bp->b_doto = 0;
  1400. X                free(eline);
  1401. X                execlevel = 0;
  1402. X                return(status);
  1403. X            }
  1404. X        }
  1405. X
  1406. X        /* on to the next line */
  1407. X        free(eline);
  1408. X        lp = lp->l_fp;
  1409. X    }
  1410. X
  1411. X    /* exit the current function */
  1412. X    execlevel = 0;
  1413. X        return(TRUE);
  1414. X}
  1415. X
  1416. Xexecfile(f, n)    /* execute a series of commands in a file
  1417. X*/
  1418. X
  1419. Xint f, n;    /* default flag and numeric arg to pass on to file */
  1420. X
  1421. X{
  1422. X    register int status;    /* return status of name query */
  1423. X    char fname[NSTRING];    /* name of file to execute */
  1424. X
  1425. X    if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
  1426. X        return(status);
  1427. X
  1428. X    /* otherwise, execute it */
  1429. X    while (n-- > 0)
  1430. X        if ((status=dofile(fname)) != TRUE)
  1431. X            return(status);
  1432. X
  1433. X    return(TRUE);
  1434. X}
  1435. X
  1436. X/*    dofile:    yank a file into a buffer and execute it
  1437. X        if there are no errors, delete the buffer on exit */
  1438. X
  1439. Xdofile(fname)
  1440. X
  1441. Xchar *fname;    /* file name to execute */
  1442. X
  1443. X{
  1444. X    register BUFFER *bp;    /* buffer to place file to exeute */
  1445. X    register BUFFER *cb;    /* temp to hold current buf while we read */
  1446. X    register int status;    /* results of various calls */
  1447. X    char bname[NBUFN];    /* name of buffer */
  1448. X
  1449. X    makename(bname, fname);        /* derive the name of the buffer */
  1450. X    if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  1451. X        return(FALSE);
  1452. X
  1453. X    bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  1454. X    cb = curbp;        /* save the old buffer */
  1455. X    curbp = bp;        /* make this one current */
  1456. X    /* and try to read in the file to execute */
  1457. X    if ((status = readin(fname, FALSE)) != TRUE) {
  1458. X        curbp = cb;    /* restore the current buffer */
  1459. X        return(status);
  1460. X    }
  1461. X
  1462. X    /* go execute it! */
  1463. X    curbp = cb;        /* restore the current buffer */
  1464. X    if ((status = dobuf(bp)) != TRUE)
  1465. X        return(status);
  1466. X
  1467. X    /* if not displayed, remove the now unneeded buffer and exit */
  1468. X    if (bp->b_nwnd == 0)
  1469. X        zotbuf(bp);
  1470. X    return(TRUE);
  1471. X}
  1472. X
  1473. X/*    cbuf:    Execute the contents of a numbered buffer    */
  1474. X
  1475. Xcbuf(f, n, bufnum)
  1476. X
  1477. Xint f, n;    /* default flag and numeric arg */
  1478. Xint bufnum;    /* number of buffer to execute */
  1479. X
  1480. X{
  1481. X        register BUFFER *bp;        /* ptr to buffer to execute */
  1482. X        register int status;        /* status return */
  1483. X    static char bufname[] = "[Macro xx]";
  1484. X
  1485. X    /* make the buffer name */
  1486. X    bufname[7] = '0' + (bufnum / 10);
  1487. X    bufname[8] = '0' + (bufnum % 10);
  1488. X
  1489. X    /* find the pointer to that buffer */
  1490. X        if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
  1491. X            mlwrite("Macro not defined");
  1492. X                return(FALSE);
  1493. X        }
  1494. X
  1495. X    /* and now execute it as asked */
  1496. X    while (n-- > 0)
  1497. X        if ((status = dobuf(bp)) != TRUE)
  1498. X            return(status);
  1499. X    return(TRUE);
  1500. X}
  1501. X
  1502. Xcbuf1(f, n)
  1503. X
  1504. X{
  1505. X    cbuf(f, n, 1);
  1506. X}
  1507. X
  1508. Xcbuf2(f, n)
  1509. X
  1510. X{
  1511. X    cbuf(f, n, 2);
  1512. X}
  1513. X
  1514. Xcbuf3(f, n)
  1515. X
  1516. X{
  1517. X    cbuf(f, n, 3);
  1518. X}
  1519. X
  1520. Xcbuf4(f, n)
  1521. X
  1522. X{
  1523. X    cbuf(f, n, 4);
  1524. X}
  1525. X
  1526. Xcbuf5(f, n)
  1527. X
  1528. X{
  1529. X    cbuf(f, n, 5);
  1530. X}
  1531. X
  1532. Xcbuf6(f, n)
  1533. X
  1534. X{
  1535. X    cbuf(f, n, 6);
  1536. X}
  1537. X
  1538. Xcbuf7(f, n)
  1539. X
  1540. X{
  1541. X    cbuf(f, n, 7);
  1542. X}
  1543. X
  1544. Xcbuf8(f, n)
  1545. X
  1546. X{
  1547. X    cbuf(f, n, 8);
  1548. X}
  1549. X
  1550. Xcbuf9(f, n)
  1551. X
  1552. X{
  1553. X    cbuf(f, n, 9);
  1554. X}
  1555. X
  1556. Xcbuf10(f, n)
  1557. X
  1558. X{
  1559. X    cbuf(f, n, 10);
  1560. X}
  1561. X
  1562. Xcbuf11(f, n)
  1563. X
  1564. X{
  1565. X    cbuf(f, n, 11);
  1566. X}
  1567. X
  1568. Xcbuf12(f, n)
  1569. X
  1570. X{
  1571. X    cbuf(f, n, 12);
  1572. X}
  1573. X
  1574. Xcbuf13(f, n)
  1575. X
  1576. X{
  1577. X    cbuf(f, n, 13);
  1578. X}
  1579. X
  1580. Xcbuf14(f, n)
  1581. X
  1582. X{
  1583. X    cbuf(f, n, 14);
  1584. X}
  1585. X
  1586. Xcbuf15(f, n)
  1587. X
  1588. X{
  1589. X    cbuf(f, n, 15);
  1590. X}
  1591. X
  1592. Xcbuf16(f, n)
  1593. X
  1594. X{
  1595. X    cbuf(f, n, 16);
  1596. X}
  1597. X
  1598. Xcbuf17(f, n)
  1599. X
  1600. X{
  1601. X    cbuf(f, n, 17);
  1602. X}
  1603. X
  1604. Xcbuf18(f, n)
  1605. X
  1606. X{
  1607. X    cbuf(f, n, 18);
  1608. X}
  1609. X
  1610. Xcbuf19(f, n)
  1611. X
  1612. X{
  1613. X    cbuf(f, n, 19);
  1614. X}
  1615. X
  1616. Xcbuf20(f, n)
  1617. X
  1618. X{
  1619. X    cbuf(f, n, 20);
  1620. X}
  1621. X
  1622. Xcbuf21(f, n)
  1623. X
  1624. X{
  1625. X    cbuf(f, n, 21);
  1626. X}
  1627. X
  1628. Xcbuf22(f, n)
  1629. X
  1630. X{
  1631. X    cbuf(f, n, 22);
  1632. X}
  1633. X
  1634. Xcbuf23(f, n)
  1635. X
  1636. X{
  1637. X    cbuf(f, n, 23);
  1638. X}
  1639. X
  1640. Xcbuf24(f, n)
  1641. X
  1642. X{
  1643. X    cbuf(f, n, 24);
  1644. X}
  1645. X
  1646. Xcbuf25(f, n)
  1647. X
  1648. X{
  1649. X    cbuf(f, n, 25);
  1650. X}
  1651. X
  1652. Xcbuf26(f, n)
  1653. X
  1654. X{
  1655. X    cbuf(f, n, 26);
  1656. X}
  1657. X
  1658. Xcbuf27(f, n)
  1659. X
  1660. X{
  1661. X    cbuf(f, n, 27);
  1662. X}
  1663. X
  1664. Xcbuf28(f, n)
  1665. X
  1666. X{
  1667. X    cbuf(f, n, 28);
  1668. X}
  1669. X
  1670. Xcbuf29(f, n)
  1671. X
  1672. X{
  1673. X    cbuf(f, n, 29);
  1674. X}
  1675. X
  1676. Xcbuf30(f, n)
  1677. X
  1678. X{
  1679. X    cbuf(f, n, 30);
  1680. X}
  1681. X
  1682. Xcbuf31(f, n)
  1683. X
  1684. X{
  1685. X    cbuf(f, n, 31);
  1686. X}
  1687. X
  1688. Xcbuf32(f, n)
  1689. X
  1690. X{
  1691. X    cbuf(f, n, 32);
  1692. X}
  1693. X
  1694. Xcbuf33(f, n)
  1695. X
  1696. X{
  1697. X    cbuf(f, n, 33);
  1698. X}
  1699. X
  1700. Xcbuf34(f, n)
  1701. X
  1702. X{
  1703. X    cbuf(f, n, 34);
  1704. X}
  1705. X
  1706. Xcbuf35(f, n)
  1707. X
  1708. X{
  1709. X    cbuf(f, n, 35);
  1710. X}
  1711. X
  1712. Xcbuf36(f, n)
  1713. X
  1714. X{
  1715. X    cbuf(f, n, 36);
  1716. X}
  1717. X
  1718. Xcbuf37(f, n)
  1719. X
  1720. X{
  1721. X    cbuf(f, n, 37);
  1722. X}
  1723. X
  1724. Xcbuf38(f, n)
  1725. X
  1726. X{
  1727. X    cbuf(f, n, 38);
  1728. X}
  1729. X
  1730. Xcbuf39(f, n)
  1731. X
  1732. X{
  1733. X    cbuf(f, n, 39);
  1734. X}
  1735. X
  1736. Xcbuf40(f, n)
  1737. X
  1738. X{
  1739. X    cbuf(f, n, 40);
  1740. X}
  1741. X
  1742. X
  1743. E!O!F
  1744. newsize=`wc -c < exec.c`
  1745. if [ $newsize -ne 18271 ]
  1746. then echo "File exec.c was $newsize bytes, 18271 expected"
  1747. fi
  1748. echo 'x - file.c (text)'
  1749. sed << 'E!O!F' 's/^X//' > file.c
  1750. X/*    FILE.C:   for MicroEMACS
  1751. X
  1752. X    The routines in this file handle the reading, writing
  1753. X    and lookup of disk files.  All of details about the
  1754. X    reading and writing of the disk are in "fileio.c".
  1755. X
  1756. X*/
  1757. X
  1758. X#include        <stdio.h>
  1759. X#include    "estruct.h"
  1760. X#include        "edef.h"
  1761. X
  1762. X/*
  1763. X * Read a file into the current
  1764. X * buffer. This is really easy; all you do it
  1765. X * find the name of the file, and call the standard
  1766. X * "read a file into the current buffer" code.
  1767. X * Bound to "C-X C-R".
  1768. X */
  1769. Xfileread(f, n)
  1770. X{
  1771. X        register int    s;
  1772. X        char fname[NFILEN];
  1773. X
  1774. X    if (restflag)        /* don't allow this command if restricted */
  1775. X        return(resterr());
  1776. X        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
  1777. X                return(s);
  1778. X        return(readin(fname, TRUE));
  1779. X}
  1780. X
  1781. X/*
  1782. X * Insert a file into the current
  1783. X * buffer. This is really easy; all you do it
  1784. X * find the name of the file, and call the standard
  1785. X * "insert a file into the current buffer" code.
  1786. X * Bound to "C-X C-I".
  1787. X */
  1788. Xinsfile(f, n)
  1789. X{
  1790. X        register int    s;
  1791. X        char fname[NFILEN];
  1792. X
  1793. X    if (restflag)        /* don't allow this command if restricted */
  1794. X        return(resterr());
  1795. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  1796. X        return(rdonly());    /* we are in read only mode    */
  1797. X        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
  1798. X                return(s);
  1799. X        return(ifile(fname));
  1800. X}
  1801. X
  1802. X/*
  1803. X * Select a file for editing.
  1804. X * Look around to see if you can find the
  1805. X * fine in another buffer; if you can find it
  1806. X * just switch to the buffer. If you cannot find
  1807. X * the file, create a new buffer, read in the
  1808. X * text, and switch to the new buffer.
  1809. X * Bound to C-X C-F.
  1810. X */
  1811. Xfilefind(f, n)
  1812. X{
  1813. X        char fname[NFILEN];    /* file user wishes to find */
  1814. X        register int s;        /* status return */
  1815. X
  1816. X    if (restflag)        /* don't allow this command if restricted */
  1817. X        return(resterr());
  1818. X        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
  1819. X                return(s);
  1820. X    return(getfile(fname, TRUE));
  1821. X}
  1822. X
  1823. Xviewfile(f, n)    /* visit a file in VIEW mode */
  1824. X{
  1825. X        char fname[NFILEN];    /* file user wishes to find */
  1826. X        register int s;        /* status return */
  1827. X    register WINDOW *wp;    /* scan for windows that need updating */
  1828. X
  1829. X    if (restflag)        /* don't allow this command if restricted */
  1830. X        return(resterr());
  1831. X        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
  1832. X                return (s);
  1833. X    s = getfile(fname, FALSE);
  1834. X    if (s) {    /* if we succeed, put it in view mode */
  1835. X        curwp->w_bufp->b_mode |= MDVIEW;
  1836. X
  1837. X        /* scan through and update mode lines of all windows */
  1838. X        wp = wheadp;
  1839. X        while (wp != NULL) {
  1840. X            wp->w_flag |= WFMODE;
  1841. X            wp = wp->w_wndp;
  1842. X        }
  1843. X    }
  1844. X    return(s);
  1845. X}
  1846. X
  1847. X#if    CRYPT
  1848. Xresetkey()    /* reset the encryption key if needed */
  1849. X
  1850. X{
  1851. X    register int s;    /* return status */
  1852. X
  1853. X    /* turn off the encryption flag */
  1854. X    cryptflag = FALSE;
  1855. X
  1856. X    /* if we are in crypt mode */
  1857. X    if (curbp->b_mode & MDCRYPT) {
  1858. X        if (curbp->b_key[0] == 0) {
  1859. X            s = setkey(FALSE, 0);
  1860. X            if (s != TRUE)
  1861. X                return(s);
  1862. X        }
  1863. X
  1864. X        /* let others know... */
  1865. X        cryptflag = TRUE;
  1866. X
  1867. X        /* and set up the key to be used! */
  1868. X        /* de-encrypt it */
  1869. X        crypt((char *)NULL, 0);
  1870. X        crypt(curbp->b_key, strlen(curbp->b_key));
  1871. X
  1872. X        /* re-encrypt it...seeding it to start */
  1873. X        crypt((char *)NULL, 0);
  1874. X        crypt(curbp->b_key, strlen(curbp->b_key));
  1875. X    }
  1876. X
  1877. X    return(TRUE);
  1878. X}
  1879. X#endif
  1880. X
  1881. Xgetfile(fname, lockfl)
  1882. X
  1883. Xchar fname[];        /* file name to find */
  1884. Xint lockfl;        /* check the file for locks? */
  1885. X
  1886. X{
  1887. X        register BUFFER *bp;
  1888. X        register LINE   *lp;
  1889. X        register int    i;
  1890. X        register int    s;
  1891. X        char bname[NBUFN];    /* buffer name to put file */
  1892. X
  1893. X#if    MSDOS
  1894. X    mklower(fname);        /* msdos isn't case sensitive */
  1895. X#endif
  1896. X        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  1897. X                if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
  1898. X            swbuffer(bp);
  1899. X                        lp = curwp->w_dotp;
  1900. X                        i = curwp->w_ntrows/2;
  1901. X                        while (i-- && lback(lp)!=curbp->b_linep)
  1902. X                                lp = lback(lp);
  1903. X                        curwp->w_linep = lp;
  1904. X                        curwp->w_flag |= WFMODE|WFHARD;
  1905. X                        mlwrite("[Old buffer]");
  1906. X                        return (TRUE);
  1907. X                }
  1908. X        }
  1909. X        makename(bname, fname);                 /* New buffer name.     */
  1910. X        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
  1911. X        /* old buffer name conflict code */
  1912. X                s = mlreply("Buffer name: ", bname, NBUFN);
  1913. X                if (s == ABORT)                 /* ^G to just quit      */
  1914. X                        return (s);
  1915. X                if (s == FALSE) {               /* CR to clobber it     */
  1916. X                        makename(bname, fname);
  1917. X                        break;
  1918. X                }
  1919. X        }
  1920. X        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
  1921. X                mlwrite("Cannot create buffer");
  1922. X                return (FALSE);
  1923. X        }
  1924. X        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
  1925. X                curbp->b_dotp = curwp->w_dotp;
  1926. X                curbp->b_doto = curwp->w_doto;
  1927. X                curbp->b_markp = curwp->w_markp;
  1928. X                curbp->b_marko = curwp->w_marko;
  1929. X        }
  1930. X        curbp = bp;                             /* Switch to it.        */
  1931. X        curwp->w_bufp = bp;
  1932. X        curbp->b_nwnd++;
  1933. X        return(readin(fname, lockfl));          /* Read it in.          */
  1934. X}
  1935. X
  1936. X/*
  1937. X * Read file "fname" into the current
  1938. X * buffer, blowing away any text found there. Called
  1939. X * by both the read and find commands. Return the final
  1940. X * status of the read. Also called by the mainline,
  1941. X * to read in a file specified on the command line as
  1942. X * an argument. If the filename ends in a ".c", CMODE is
  1943. X * set for the current buffer.
  1944. X */
  1945. Xreadin(fname, lockfl)
  1946. X
  1947. Xchar    fname[];    /* name of file to read */
  1948. Xint    lockfl;        /* check for file locks? */
  1949. X
  1950. X{
  1951. X        register LINE   *lp1;
  1952. X        register LINE   *lp2;
  1953. X        register int    i;
  1954. X        register WINDOW *wp;
  1955. X        register BUFFER *bp;
  1956. X        register int    s;
  1957. X        register int    nbytes;
  1958. X        register int    nline;
  1959. X    register char    *sptr;        /* pointer into filename string */
  1960. X    int        lflag;        /* any lines longer than allowed? */
  1961. X        char            line[NLINE];
  1962. X
  1963. X#if    FILOCK
  1964. X    if (lockfl && lockchk(fname) == ABORT)
  1965. X        return(ABORT);
  1966. X#endif
  1967. X#if    CRYPT
  1968. X    s = resetkey();
  1969. X    if (s != TRUE)
  1970. X        return(s);
  1971. X#endif
  1972. X        bp = curbp;                             /* Cheap.               */
  1973. X        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
  1974. X                return (s);
  1975. X        bp->b_flag &= ~(BFINVS|BFCHG);
  1976. X#if    ACMODE
  1977. X    if (strlen(fname) > 1) {        /* check if a 'C' file    */
  1978. X        sptr = fname + strlen(fname) - 2;
  1979. X        if (*sptr == '.' &&
  1980. X           (*(sptr + 1) == 'c' || *(sptr + 1) == 'h'))
  1981. X            bp->b_mode |= MDCMOD;
  1982. X    }
  1983. X#endif
  1984. X        strcpy(bp->b_fname, fname);
  1985. X
  1986. X    /* turn off ALL keyboard translation in case we get a dos error */
  1987. X    TTkclose();
  1988. X
  1989. X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  1990. X                goto out;
  1991. X        if (s == FIOFNF) {                      /* File not found.      */
  1992. X                mlwrite("[New file]");
  1993. X                goto out;
  1994. X        }
  1995. X        mlwrite("[Reading file]");
  1996. X        nline = 0;
  1997. X    lflag = FALSE;
  1998. X        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
  1999. X            || s == FIOFUN) {
  2000. X        if (s == FIOLNG) {
  2001. X            lflag = TRUE;
  2002. X            --nline;
  2003. X        }
  2004. X                nbytes = strlen(line);
  2005. X                if ((lp1=lalloc(nbytes)) == NULL) {
  2006. X                        s = FIOERR;             /* Keep message on the  */
  2007. X                        break;                  /* display.             */
  2008. X                }
  2009. X                lp2 = lback(curbp->b_linep);
  2010. X                lp2->l_fp = lp1;
  2011. X                lp1->l_fp = curbp->b_linep;
  2012. X                lp1->l_bp = lp2;
  2013. X                curbp->b_linep->l_bp = lp1;
  2014. X                for (i=0; i<nbytes; ++i)
  2015. X                        lputc(lp1, i, line[i]);
  2016. X                ++nline;
  2017. X                if (s == FIOFUN)
  2018. X                    break;
  2019. X        }
  2020. X        ffclose();                              /* Ignore errors.       */
  2021. X    strcpy(line, "[");
  2022. X    if (lflag)
  2023. X        strcat(line, "Long lines wrapped, ");
  2024. X    if (s == FIOFUN)
  2025. X        strcat(line, "Funny line at EOF, ");
  2026. X        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!   */
  2027. X        sprintf(&line[strlen(line)], "Read %d line", nline);
  2028. X                if (nline > 1)
  2029. X            strcat(line, "s");
  2030. X        strcat(line, "]");
  2031. X        }
  2032. X    if (s != FIOERR)
  2033. X        mlwrite(line);
  2034. X
  2035. Xout:
  2036. X    TTkopen();    /* open the keyboard again */
  2037. X        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  2038. X                if (wp->w_bufp == curbp) {
  2039. X                        wp->w_linep = lforw(curbp->b_linep);
  2040. X                        wp->w_dotp  = lforw(curbp->b_linep);
  2041. X                        wp->w_doto  = 0;
  2042. X                        wp->w_markp = NULL;
  2043. X                        wp->w_marko = 0;
  2044. X                        wp->w_flag |= WFMODE|WFHARD;
  2045. X                }
  2046. X        }
  2047. X        if (s == FIOERR || s == FIOFNF)        /* False if error.      */
  2048. X                return(FALSE);
  2049. X        return (TRUE);
  2050. X}
  2051. X
  2052. X/*
  2053. X * Take a file name, and from it
  2054. X * fabricate a buffer name. This routine knows
  2055. X * about the syntax of file names on the target system.
  2056. X * I suppose that this information could be put in
  2057. X * a better place than a line of code.
  2058. X */
  2059. Xmakename(bname, fname)
  2060. Xchar    bname[];
  2061. Xchar    fname[];
  2062. X{
  2063. X        register char *cp1;
  2064. X        register char *cp2;
  2065. X
  2066. X        cp1 = &fname[0];
  2067. X        while (*cp1 != 0)
  2068. X                ++cp1;
  2069. X
  2070. X#if     AMIGA
  2071. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
  2072. X                --cp1;
  2073. X#endif
  2074. X#if     VMS
  2075. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
  2076. X                --cp1;
  2077. X#endif
  2078. X#if     CPM
  2079. X        while (cp1!=&fname[0] && cp1[-1]!=':')
  2080. X                --cp1;
  2081. X#endif
  2082. X#if     MSDOS
  2083. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  2084. X                --cp1;
  2085. X#endif
  2086. X#if     ST520
  2087. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
  2088. X                --cp1;
  2089. X#endif
  2090. X#if     FINDER
  2091. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  2092. X                --cp1;
  2093. X#endif
  2094. X#if     V7 | USG | BSD
  2095. X        while (cp1!=&fname[0] && cp1[-1]!='/')
  2096. X                --cp1;
  2097. X#endif
  2098. X        cp2 = &bname[0];
  2099. X        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  2100. X                *cp2++ = *cp1++;
  2101. X        *cp2 = 0;
  2102. X}
  2103. X
  2104. Xunqname(name)    /* make sure a buffer name is unique */
  2105. X
  2106. Xchar *name;    /* name to check on */
  2107. X
  2108. X{
  2109. X    register char *sp;
  2110. X
  2111. X    /* check to see if it is in the buffer list */
  2112. X    while (bfind(name, 0, FALSE) != NULL) {
  2113. X
  2114. X        /* go to the end of the name */
  2115. X        sp = name;
  2116. X        while (*sp)
  2117. X            ++sp;
  2118. X        if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
  2119. X            *sp++ = '0';
  2120. X            *sp = 0;
  2121. X        } else
  2122. X            *(--sp) += 1;
  2123. X    }
  2124. X}
  2125. X
  2126. X/*
  2127. X * Ask for a file name, and write the
  2128. X * contents of the current buffer to that file.
  2129. X * Update the remembered file name and clear the
  2130. X * buffer changed flag. This handling of file names
  2131. X * is different from the earlier versions, and
  2132. X * is more compatable with Gosling EMACS than
  2133. X * with ITS EMACS. Bound to "C-X C-W".
  2134. X */
  2135. Xfilewrite(f, n)
  2136. X{
  2137. X        register WINDOW *wp;
  2138. X        register int    s;
  2139. X        char            fname[NFILEN];
  2140. X
  2141. X    if (restflag)        /* don't allow this command if restricted */
  2142. X        return(resterr());
  2143. X        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
  2144. X                return (s);
  2145. X        if ((s=writeout(fname)) == TRUE) {
  2146. X                strcpy(curbp->b_fname, fname);
  2147. X                curbp->b_flag &= ~BFCHG;
  2148. X                wp = wheadp;                    /* Update mode lines.   */
  2149. X                while (wp != NULL) {
  2150. X                        if (wp->w_bufp == curbp)
  2151. X                                wp->w_flag |= WFMODE;
  2152. X                        wp = wp->w_wndp;
  2153. X                }
  2154. X        }
  2155. X        return (s);
  2156. X}
  2157. X
  2158. X/*
  2159. X * Save the contents of the current
  2160. X * buffer in its associatd file. No nothing
  2161. X * if nothing has changed (this may be a bug, not a
  2162. X * feature). Error if there is no remembered file
  2163. X * name for the buffer. Bound to "C-X C-S". May
  2164. X * get called by "C-Z".
  2165. X */
  2166. Xfilesave(f, n)
  2167. X{
  2168. X        register WINDOW *wp;
  2169. X        register int    s;
  2170. X
  2171. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  2172. X        return(rdonly());    /* we are in read only mode    */
  2173. X        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
  2174. X                return (TRUE);
  2175. X        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
  2176. X                mlwrite("No file name");
  2177. X                return (FALSE);
  2178. X        }
  2179. X        if ((s=writeout(curbp->b_fname)) == TRUE) {
  2180. X                curbp->b_flag &= ~BFCHG;
  2181. X                wp = wheadp;                    /* Update mode lines.   */
  2182. X                while (wp != NULL) {
  2183. X                        if (wp->w_bufp == curbp)
  2184. X                                wp->w_flag |= WFMODE;
  2185. X                        wp = wp->w_wndp;
  2186. X                }
  2187. X        }
  2188. X        return (s);
  2189. X}
  2190. X
  2191. X/*
  2192. X * This function performs the details of file
  2193. X * writing. Uses the file management routines in the
  2194. X * "fileio.c" package. The number of lines written is
  2195. X * displayed. Sadly, it looks inside a LINE; provide
  2196. X * a macro for this. Most of the grief is error
  2197. X * checking of some sort.
  2198. X */
  2199. Xwriteout(fn)
  2200. Xchar    *fn;
  2201. X{
  2202. X        register int    s;
  2203. X        register LINE   *lp;
  2204. X        register int    nline;
  2205. X
  2206. X#if    CRYPT
  2207. X    s = resetkey();
  2208. X    if (s != TRUE)
  2209. X        return(s);
  2210. X#endif
  2211. X    /* turn off ALL keyboard translation in case we get a dos error */
  2212. X    TTkclose();
  2213. X
  2214. X        if ((s=ffwopen(fn)) != FIOSUC) {        /* Open writes message. */
  2215. X        TTkopen();
  2216. X                return (FALSE);
  2217. X        }
  2218. X    mlwrite("[Writing..]");            /* tell us were writing */
  2219. X        lp = lforw(curbp->b_linep);             /* First line.          */
  2220. X        nline = 0;                              /* Number of lines.     */
  2221. X        while (lp != curbp->b_linep) {
  2222. X                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
  2223. X                        break;
  2224. X                ++nline;
  2225. X                lp = lforw(lp);
  2226. X        }
  2227. X        if (s == FIOSUC) {                      /* No write error.      */
  2228. X                s = ffclose();
  2229. X                if (s == FIOSUC) {              /* No close error.      */
  2230. X                        if (nline == 1)
  2231. X                                mlwrite("[Wrote 1 line]");
  2232. X                        else
  2233. X                                mlwrite("[Wrote %d lines]", nline);
  2234. X                }
  2235. X        } else                                  /* Ignore close error   */
  2236. X                ffclose();                      /* if a write error.    */
  2237. X    TTkopen();
  2238. X        if (s != FIOSUC)                        /* Some sort of error.  */
  2239. X                return (FALSE);
  2240. X        return (TRUE);
  2241. X}
  2242. X
  2243. X/*
  2244. X * The command allows the user
  2245. X * to modify the file name associated with
  2246. X * the current buffer. It is like the "f" command
  2247. X * in UNIX "ed". The operation is simple; just zap
  2248. X * the name in the BUFFER structure, and mark the windows
  2249. X * as needing an update. You can type a blank line at the
  2250. X * prompt if you wish.
  2251. X */
  2252. Xfilename(f, n)
  2253. X{
  2254. X        register WINDOW *wp;
  2255. X        register int    s;
  2256. X        char            fname[NFILEN];
  2257. X
  2258. X    if (restflag)        /* don't allow this command if restricted */
  2259. X        return(resterr());
  2260. X        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
  2261. X                return (s);
  2262. X        if (s == FALSE)
  2263. X                strcpy(curbp->b_fname, "");
  2264. X        else
  2265. X                strcpy(curbp->b_fname, fname);
  2266. X        wp = wheadp;                            /* Update mode lines.   */
  2267. X        while (wp != NULL) {
  2268. X                if (wp->w_bufp == curbp)
  2269. X                        wp->w_flag |= WFMODE;
  2270. X                wp = wp->w_wndp;
  2271. X        }
  2272. X    curbp->b_mode &= ~MDVIEW;    /* no longer read only mode */
  2273. X        return (TRUE);
  2274. X}
  2275. X
  2276. X/*
  2277. X * Insert file "fname" into the current
  2278. X * buffer, Called by insert file command. Return the final
  2279. X * status of the read.
  2280. X */
  2281. Xifile(fname)
  2282. Xchar    fname[];
  2283. X{
  2284. X        register LINE   *lp0;
  2285. X        register LINE   *lp1;
  2286. X        register LINE   *lp2;
  2287. X        register int    i;
  2288. X        register BUFFER *bp;
  2289. X        register int    s;
  2290. X        register int    nbytes;
  2291. X        register int    nline;
  2292. X    int        lflag;        /* any lines longer than allowed? */
  2293. X        char            line[NLINE];
  2294. X
  2295. X        bp = curbp;                             /* Cheap.               */
  2296. X        bp->b_flag |= BFCHG;            /* we have changed    */
  2297. X    bp->b_flag &= ~BFINVS;            /* and are not temporary*/
  2298. X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  2299. X                goto out;
  2300. X        if (s == FIOFNF) {                      /* File not found.      */
  2301. X                mlwrite("[No such file]");
  2302. X        return(FALSE);
  2303. X        }
  2304. X        mlwrite("[Inserting file]");
  2305. X
  2306. X#if    CRYPT
  2307. X    s = resetkey();
  2308. X    if (s != TRUE)
  2309. X        return(s);
  2310. X#endif
  2311. X    /* back up a line and save the mark here */
  2312. X    curwp->w_dotp = lback(curwp->w_dotp);
  2313. X    curwp->w_doto = 0;
  2314. X    curwp->w_markp = curwp->w_dotp;
  2315. X    curwp->w_marko = 0;
  2316. X
  2317. X        nline = 0;
  2318. X    lflag = FALSE;
  2319. X        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
  2320. X            || s == FIOFUN) {
  2321. X        if (s == FIOLNG) {
  2322. X            lflag = TRUE;
  2323. X            --nline;
  2324. X        }
  2325. X                nbytes = strlen(line);
  2326. X                if ((lp1=lalloc(nbytes)) == NULL) {
  2327. X                        s = FIOERR;             /* Keep message on the  */
  2328. X                        break;                  /* display.             */
  2329. X                }
  2330. X        lp0 = curwp->w_dotp;    /* line previous to insert */
  2331. X        lp2 = lp0->l_fp;    /* line after insert */
  2332. X
  2333. X        /* re-link new line between lp0 and lp2 */
  2334. X        lp2->l_bp = lp1;
  2335. X        lp0->l_fp = lp1;
  2336. X        lp1->l_bp = lp0;
  2337. X        lp1->l_fp = lp2;
  2338. X
  2339. X        /* and advance and write out the current line */
  2340. X        curwp->w_dotp = lp1;
  2341. X                for (i=0; i<nbytes; ++i)
  2342. X                        lputc(lp1, i, line[i]);
  2343. X                ++nline;
  2344. X                if (s == FIOFUN)
  2345. X                    break;
  2346. X        }
  2347. X        ffclose();                              /* Ignore errors.       */
  2348. X    curwp->w_markp = lforw(curwp->w_markp);
  2349. X    strcpy(line, "[");
  2350. X    if (lflag)
  2351. X        strcat(line, "Long lines wrapped, ");
  2352. X    if (s == FIOFUN)
  2353. X        strcat(line, "Funny line at EOF, ");
  2354. X        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!   */
  2355. X        sprintf(&line[strlen(line)], "Inserted %d line", nline);
  2356. X                if (nline > 1)
  2357. X            strcat(line, "s");
  2358. X        strcat(line, "]");
  2359. X        }
  2360. X    if (s != FIOERR)
  2361. X        mlwrite(line);
  2362. Xout:
  2363. X    /* advance to the next line and mark the window for changes */
  2364. X    curwp->w_dotp = lforw(curwp->w_dotp);
  2365. X    curwp->w_flag |= WFHARD | WFMODE;
  2366. X
  2367. X    /* copy window parameters back to the buffer structure */
  2368. X    curbp->b_dotp = curwp->w_dotp;
  2369. X    curbp->b_doto = curwp->w_doto;
  2370. X    curbp->b_markp = curwp->w_markp;
  2371. X    curbp->b_marko = curwp->w_marko;
  2372. X
  2373. X        if (s == FIOERR)                        /* False if error.      */
  2374. X                return (FALSE);
  2375. X        return (TRUE);
  2376. X}
  2377. E!O!F
  2378. newsize=`wc -c < file.c`
  2379. if [ $newsize -ne 18793 ]
  2380. then echo "File file.c was $newsize bytes, 18793 expected"
  2381. fi
  2382. echo 'x - fileio.c (text)'
  2383. sed << 'E!O!F' 's/^X//' > fileio.c
  2384. X/*
  2385. X * The routines in this file read and write ASCII files from the disk. All of
  2386. X * the knowledge about files are here. A better message writing scheme should
  2387. X * be used.
  2388. X */
  2389. X#include        <stdio.h>
  2390. X#include    "estruct.h"
  2391. X#include        "edef.h"
  2392. X
  2393. XFILE    *ffp;                           /* File pointer, all functions. */
  2394. X
  2395. X/*
  2396. X * Open a file for reading.
  2397. X */
  2398. Xffropen(fn)
  2399. Xchar    *fn;
  2400. X{
  2401. X        if ((ffp=fopen(fn, "r")) == NULL)
  2402. X                return (FIOFNF);
  2403. X        return (FIOSUC);
  2404. X}
  2405. X
  2406. X/*
  2407. X * Open a file for writing. Return TRUE if all is well, and FALSE on error
  2408. X * (cannot create).
  2409. X */
  2410. Xffwopen(fn)
  2411. Xchar    *fn;
  2412. X{
  2413. X#if     VMS
  2414. X        register int    fd;
  2415. X
  2416. X        if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
  2417. X        || (ffp=fdopen(fd, "w")) == NULL) {
  2418. X#else
  2419. X        if ((ffp=fopen(fn, "w")) == NULL) {
  2420. X#endif
  2421. X                mlwrite("Cannot open file for writing");
  2422. X                return (FIOERR);
  2423. X        }
  2424. X        return (FIOSUC);
  2425. X}
  2426. X
  2427. X/*
  2428. X * Close a file. Should look at the status in all systems.
  2429. X */
  2430. Xffclose()
  2431. X{
  2432. X#if    MSDOS & CTRLZ
  2433. X    fputc(26, ffp);        /* add a ^Z at the end of the file */
  2434. X#endif
  2435. X    
  2436. X#if     V7 | USG | BSD | (MSDOS & (LATTICE | MSC))
  2437. X        if (fclose(ffp) != FALSE) {
  2438. X                mlwrite("Error closing file");
  2439. X                return(FIOERR);
  2440. X        }
  2441. X        return(FIOSUC);
  2442. X#else
  2443. X        fclose(ffp);
  2444. X        return (FIOSUC);
  2445. X#endif
  2446. X}
  2447. X
  2448. X/*
  2449. X * Write a line to the already opened file. The "buf" points to the buffer,
  2450. X * and the "nbuf" is its length, less the free newline. Return the status.
  2451. X * Check only at the newline.
  2452. X */
  2453. Xffputline(buf, nbuf)
  2454. Xchar    buf[];
  2455. X{
  2456. X        register int    i;
  2457. X#if    CRYPT
  2458. X    char c;        /* character to translate */
  2459. X
  2460. X    if (cryptflag) {
  2461. X            for (i = 0; i < nbuf; ++i) {
  2462. X            c = buf[i] & 0xff;
  2463. X            crypt(&c, 1);
  2464. X            fputc(c, ffp);
  2465. X        }
  2466. X    } else
  2467. X            for (i = 0; i < nbuf; ++i)
  2468. X                    fputc(buf[i]&0xFF, ffp);
  2469. X#else
  2470. X        for (i = 0; i < nbuf; ++i)
  2471. X                fputc(buf[i]&0xFF, ffp);
  2472. X#endif
  2473. X
  2474. X#if    ST520
  2475. X        fputc('\r', ffp);
  2476. X#endif        
  2477. X        fputc('\n', ffp);
  2478. X
  2479. X        if (ferror(ffp)) {
  2480. X                mlwrite("Write I/O error");
  2481. X                return (FIOERR);
  2482. X        }
  2483. X
  2484. X        return (FIOSUC);
  2485. X}
  2486. X
  2487. X/*
  2488. X * Read a line from a file, and store the bytes in the supplied buffer. The
  2489. X * "nbuf" is the length of the buffer. Complain about long lines and lines
  2490. X * at the end of the file that don't have a newline present. Check for I/O
  2491. X * errors too. Return status.
  2492. X */
  2493. Xffgetline(buf, nbuf)
  2494. Xregister char   buf[];
  2495. X{
  2496. X        register int    c;
  2497. X        register int    i;
  2498. X
  2499. X        i = 0;
  2500. X
  2501. X        while ((c = fgetc(ffp)) != EOF && c != '\n') {
  2502. X                if (i >= nbuf-2) {
  2503. X            buf[nbuf - 2] = c;    /* store last char read */
  2504. X            buf[nbuf - 1] = 0;    /* and terminate it */
  2505. X                        mlwrite("File has long line");
  2506. X#if    CRYPT
  2507. X            if (cryptflag)
  2508. X                crypt(buf, strlen(buf));
  2509. X#endif
  2510. X                        return (FIOLNG);
  2511. X                }
  2512. X                buf[i++] = c;
  2513. X        }
  2514. X
  2515. X#if    ST520
  2516. X    if(buf[i-1] == '\r')
  2517. X        i--;
  2518. X#endif
  2519. X        if (c == EOF) {
  2520. X                if (ferror(ffp)) {
  2521. X                        mlwrite("File read error");
  2522. X                        return (FIOERR);
  2523. X                }
  2524. X
  2525. X                if (i != 0) {
  2526. X                    buf[i] = 0;
  2527. X                        return(FIOFUN);
  2528. X                }
  2529. X
  2530. X                return (FIOEOF);
  2531. X        }
  2532. X
  2533. X        buf[i] = 0;
  2534. X#if    CRYPT
  2535. X    if (cryptflag)
  2536. X        crypt(buf, strlen(buf));
  2537. X#endif
  2538. X        return (FIOSUC);
  2539. X}
  2540. X
  2541. X#if    AZTEC & MSDOS
  2542. X#undef    fgetc
  2543. X/*    a1getc:        Get an ascii char from the file input stream
  2544. X            but DO NOT strip the high bit
  2545. X*/
  2546. X
  2547. Xint a1getc(fp)
  2548. X
  2549. XFILE *fp;
  2550. X
  2551. X{
  2552. X    int c;        /* translated character */
  2553. X
  2554. X    c = getc(fp);    /* get the character */
  2555. X
  2556. X    /* if its a <LF> char, throw it out  */
  2557. X    while (c == 10)
  2558. X        c = getc(fp);
  2559. X
  2560. X    /* if its a <RETURN> char, change it to a LF */
  2561. X    if (c == '\r')
  2562. X        c = '\n';
  2563. X
  2564. X    /* if its a ^Z, its an EOF */
  2565. X    if (c == 26)
  2566. X        c = EOF;
  2567. X
  2568. X    return(c);
  2569. X}
  2570. X#endif
  2571. E!O!F
  2572. newsize=`wc -c < fileio.c`
  2573. if [ $newsize -ne 3918 ]
  2574. then echo "File fileio.c was $newsize bytes, 3918 expected"
  2575. fi
  2576. echo 'x - files (text)'
  2577. sed << 'E!O!F' 's/^X//' > files
  2578. XANSI.C
  2579. XBASIC.C
  2580. XBIND.C
  2581. XBUFFER.C
  2582. XCRYPT.C
  2583. XDG10.C
  2584. XDISPLAY.C
  2585. XDOLOCK.C
  2586. XEBIND.H
  2587. XEDEF.H
  2588. XEFUNC.H
  2589. XEMACS.HLP
  2590. XEPATH.H
  2591. XESTRUCT.H
  2592. XEVAL.C
  2593. XEVAR.H
  2594. XEXEC.C
  2595. XFILE.C
  2596. XFILEIO.C
  2597. XHP110.C
  2598. XHP150.C
  2599. XIBMPC.C
  2600. XINPUT.C
  2601. XISEARCH.C
  2602. XLINE.C
  2603. XLOCK.C
  2604. XMAIN.C
  2605. XMAKEFILE
  2606. XRANDOM.C
  2607. XREGION.C
  2608. XSEARCH.C
  2609. XSPAWN.C
  2610. XST520.C
  2611. XTCAP.C
  2612. XTERMIO.C
  2613. XTIPC.C
  2614. XVMSVT.C
  2615. XVT52.C
  2616. XWINDOW.C
  2617. XWORD.C
  2618. XZ309.C
  2619. E!O!F
  2620. newsize=`wc -c < files`
  2621. if [ $newsize -ne 329 ]
  2622. then echo "File files was $newsize bytes, 329 expected"
  2623. fi
  2624.     bill davidsen        (wedu@ge-crd.arpa)
  2625.   {chinet | philabs | sesimo}!steinmetz!crdos1!davidsen
  2626. "Stupidity, like virtue, is its own reward" -me
  2627.  
  2628.  
  2629.