home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume7 / basic / part03 < prev    next >
Text File  |  1986-12-03  |  60KB  |  2,662 lines

  1. Subject:  v07i075:  A BASIC Interpreter, Part03/06
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: phil@Cs.Ucl.AC.UK
  6. Mod.sources: Volume 7, Issue 75
  7. Archive-name: basic/Part03
  8.  
  9. # Shar file shar03 (of 6)
  10. #
  11. # This is a shell archive containing the following files :-
  12. #    bas7.c
  13. #    bas8.c
  14. #    bas9.c
  15. #    gen
  16. # ------------------------------
  17. # This is a shell archive, shar, format file.
  18. # To unarchive, feed this text into /bin/sh in the directory
  19. # you wish the files to be in.
  20.  
  21. echo x - bas7.c 1>&2
  22. sed 's/^X//' > bas7.c << 'End of bas7.c'
  23. X/*
  24. X * BASIC by Phil Cockcroft
  25. X */
  26. X#include        "bas.h"
  27. X
  28. X#define         COMPILE
  29. X#include        "cursor.c"
  30. X#undef          COMPILE
  31. X
  32. X/*
  33. X *     this file conatins the user interface e.g. the line editor
  34. X */
  35. X
  36. X#define PADC    0400    /* the character output for padding */
  37. X            /* more than 0377 but can still be passed to putc */
  38. X
  39. X/*      read a single character */
  40. X
  41. Xreadc()
  42. X{
  43. X    char    c=RETURN;
  44. X
  45. X#ifdef  BSD42
  46. X    if(!setjmp(ecall)){
  47. X        ecalling = 1;
  48. X        if(!read(0,&c,1)){
  49. X            ecalling = 0;
  50. X            quit();
  51. X        }
  52. X        ecalling = 0;
  53. X    }
  54. X#else
  55. X    if(!read(0,&c,1))               /* reading from a pipe exit on eof */
  56. X        quit();
  57. X#endif
  58. X    return(c&0177);
  59. X}
  60. X
  61. X/*      sets up the terminal structures so that the editor is in rare
  62. X *    with no paging or line boundries and no echo
  63. X *      Also sets up the user modes so that they are sensible when
  64. X *    we exit. ( friendly ).
  65. X */
  66. X
  67. Xsetupterm()
  68. X{
  69. X    set_cap();
  70. X    setu_term();
  71. X}
  72. X
  73. X
  74. X/*   the actual editor pretty straight forward but.. */
  75. X
  76. Xedit(fl,fi,fc)
  77. X{
  78. X    register int    cursr;
  79. X    register char   *q;
  80. X    register char   *p;
  81. X    int     c;
  82. X    int     quitf=0;        /* say we have finished the edit */
  83. X    int     special;
  84. X    int     lastc;
  85. X    int     inschar =1;
  86. X
  87. X    set_term();
  88. X    for(p= &line[fi]; p<= &line[MAXLIN] ;)
  89. X        *p++ = ' ';
  90. X    *p=0;
  91. X    write(1,line,fi);
  92. X    cursr=fi;
  93. X    if(noedit){
  94. X        for(p= &line[cursr];p< &line[MAXLIN] ; ){
  95. X            c=readc();
  96. X            if(c=='\n' || trapped)
  97. X                break;
  98. X            else if(c >=' ' )
  99. X                *p++ =c;
  100. X            else if(c == ESCAPE)
  101. X                break;
  102. X        }
  103. X        while(c != '\n' && c != ESCAPE && !trapped)
  104. X            c=readc();
  105. X    }
  106. X    else
  107. X    do{
  108. X        putch(0);       /* flush the buffers */
  109. X        lastc = lastch(fl);
  110. X        c=readc();
  111. X        if(c >= ' ' && c < '\177'){
  112. X            if( cursr < MAXLIN && ( inschar && lastc < MAXLIN || !inschar) ){
  113. X                if(cursr < lastc && inschar){
  114. X                    p= &line[MAXLIN];
  115. X                    q= p-1;
  116. X                    while(p> &line[cursr])
  117. X                        *--p= *--q;
  118. X                    if(*o_INSCHAR)
  119. X                        puts(o_INSCHAR);
  120. X                    else
  121. X                        inchar(cursr,lastc,c);
  122. X                }
  123. X                putch(c);
  124. X                line[cursr++]=c;
  125. X                continue;
  126. X            }
  127. X        }
  128. X        else switch( (c <' ') ? _in_char[c] : _in_char[32] ){
  129. Xcase    i_LEFT:
  130. X        if(cursr==fl)
  131. X            break;
  132. X        cursr--;
  133. X        puts(o_LEFT);
  134. X        continue;
  135. Xcase    i_CLEAR:                /* control l  - redraw  */
  136. X        puts(o_RETURN);
  137. X        cursr=lastc;
  138. X        for(p= line; p< &line[cursr];)
  139. X            putch(*p++);
  140. X        deol(cursr);
  141. X        continue;
  142. Xcase    i_DELLINE:              /* control b - zap line */
  143. X        if(cursr==fl && lastc == fl)
  144. X            break;
  145. X        puts(o_RETURN);
  146. X        p=line;
  147. X        while(p<&line[fl])
  148. X            putch(*p++);
  149. X        deol(cursr);
  150. X        p= &line[fl];
  151. X        while(p<&line[MAXLIN])
  152. X            *p++ = ' ';
  153. X        cursr=fl;
  154. X        continue;
  155. Xcase    i_DELCHAR:
  156. X        if(cursr >= lastc )
  157. X            break;
  158. X        goto rubit;
  159. Xcase    i_RUBOUT:
  160. X        if(cursr==fl)
  161. X            break;
  162. X        puts(o_LEFT);
  163. X        cursr--;
  164. X        if(!inschar)
  165. X            continue;
  166. X    rubit:
  167. X        if(cursr <= lastc ){
  168. X            if(*o_DELCHAR)
  169. X                puts(o_DELCHAR);
  170. X            p= &line[cursr];
  171. X            q= p+1;
  172. X            while(q < &line[MAXLIN] )
  173. X                *p++ = *q++;
  174. X            *p= ' ';
  175. X        }
  176. X        if(!*o_DELCHAR)
  177. X            delchar(cursr,lastc);
  178. X        continue;
  179. Xcase    i_UP:
  180. X        if(cursr-ter_width< fl)
  181. X            break;
  182. X        if(*o_UP)
  183. X            puts(o_UP);
  184. X        else for(special = 0; special < ter_width ; special++)
  185. X            puts(o_LEFT);
  186. X        cursr -= ter_width;
  187. X        continue;
  188. Xcase    i_DOWN1:
  189. X        if(cursr+ter_width > MAXLIN )
  190. X            break;
  191. X        puts(o_DOWN2);
  192. X        cursr+=ter_width;
  193. X        continue;
  194. Xcase    i_CNTRLD:
  195. X        if( (c = readc()) >= ' ' || _in_char[c] != i_CNTRLD)
  196. X            break;
  197. X        putch(0);
  198. X        cursor= (cursor+cursr)%ter_width;
  199. X        quit();
  200. Xcase    i_INSCHAR:
  201. X        inschar = !inschar;
  202. X        continue;
  203. Xcase    i_RIGHT:
  204. X        if(cursr>= MAXLIN)
  205. X            break;
  206. X        putch(line[cursr++]);
  207. X        continue;
  208. Xcase    i_LLEFT:
  209. X        if(cursr <= fl)
  210. X            break;
  211. X        do{
  212. X            puts(o_LEFT);
  213. X        }while(((--cursr) &07) && cursr > fl);
  214. X        continue;
  215. Xcase    i_RRIGHT:
  216. X        if(cursr>= MAXLIN)
  217. X            break;
  218. X        do{
  219. X            putch(line[cursr++]);
  220. X        }while((cursr&07) && cursr < MAXLIN);
  221. X        continue;
  222. Xcase    i_DELSOL:       /* delete to start of line */
  223. X        if(cursr==fl)
  224. X            break;
  225. X        special = cursr;
  226. X        cursr = fl;
  227. X        goto delit;     /* same code as del word almost */
  228. Xcase    i_DELWORD:         /* control w - del word */
  229. X        if(cursr==fl)
  230. X            break;
  231. X        special=cursr;
  232. X        do{
  233. X            cursr--;
  234. X        }while(cursr>fl &&(line[cursr-1]!=' ' || line[cursr]==' '));
  235. X    delit:
  236. X        q= &line[special];
  237. X        p= &line[cursr];
  238. X        while(q < &line[MAXLIN] )
  239. X            *p++ = *q++;
  240. X        while(p < &line[MAXLIN]){
  241. X            puts(o_LEFT);
  242. X            *p++ = ' ';
  243. X            if(*o_DELCHAR && --special <= lastc )
  244. X                puts(o_DELCHAR);
  245. X        }
  246. X        if(!*o_DELCHAR)
  247. X            delchar(cursr,lastc);
  248. X        continue;
  249. Xcase    i_BACKWORD:             /* back word */
  250. X        if(cursr==fl)
  251. X            break;
  252. X        do{
  253. X            puts(o_LEFT);
  254. X            cursr--;
  255. X        }while(cursr>fl && (line[cursr-1]!=' ' || line[cursr]==' ' ));
  256. X        continue;
  257. Xcase    i_NEXTWORD:     /* next word */
  258. X        if(cursr >= MAXLIN || cursr > lastc  || lastc == fl)
  259. X            break;
  260. X        do{
  261. X            putch(line[cursr++]);
  262. X        }while(cursr < MAXLIN && cursr <= lastc &&
  263. X             (line[cursr]==' '|| line[cursr-1]!=' ' ) );
  264. X        continue;
  265. Xcase    i_DEOL:
  266. X        if(cursr >= lastc )
  267. X            break;
  268. X        for(p= &line[cursr];p < &line[MAXLIN];)
  269. X            *p++ = ' ';
  270. X        deol(cursr);
  271. X        continue;
  272. Xcase    i_ESCAPE:
  273. Xcase    i_RETURN:
  274. Xcase    i_DOWN2:
  275. X        while(cursr< lastc)
  276. X            putch(line[cursr++]);
  277. X        puts(o_RETURN);
  278. X        puts(o_DOWN2);
  279. X        quitf++;
  280. X        continue;
  281. Xdefault:
  282. X        break;
  283. X        }
  284. X        puts(o_PING);
  285. X    }while(!quitf && !trapped);
  286. X    putch(0);
  287. X    line[lastch(fl)]=0;
  288. X/*   special characters are dealt with here- null is never returned */
  289. X    for(p=line,q=line,special=0;*p;p++){
  290. X        if(special){
  291. X            special=0;
  292. X            if(*p>='a' && *p<='~')
  293. X                *q++ = *p -('a'-1);
  294. X            else *q++ = *p;
  295. X        }
  296. X        else if(*p=='\\')
  297. X            special++;
  298. X        else *q++ = *p;
  299. X    }
  300. X    *q=0;
  301. X    cursor=0;
  302. X    rset_term(0);
  303. X    return(c);
  304. X}
  305. X
  306. X/*
  307. X *      put a string out ( using putch )
  308. X */
  309. X
  310. Xputs(s)
  311. Xregister char    *s;
  312. X{
  313. X    /*
  314. X     * now cope with padding
  315. X     */
  316. X    if(*s >='0' && *s <= '9'){
  317. X        register i = 0;
  318. X        do{
  319. X            i = i * 10 + *s++ -'0';
  320. X        }while(*s >= '0' && *s <= '9');
  321. X        if(*s == '.')
  322. X            s++, i++;
  323. X        if(*s == '*')   /* should only affect 1 line */
  324. X            s++;
  325. X        while(i-- > 0)
  326. X            putch(PADC);
  327. X    }
  328. X    while(*s)
  329. X        putch(*s++);
  330. X}
  331. X
  332. X/*      put out a character uses buffere output of up to 256 characters
  333. X *    It used to use a static buffer but this is a waste of space so
  334. X *    it now uses gblock as this is never used during an edit.
  335. X *      A value of zero for the parameter will flush the buffer.
  336. X */
  337. X
  338. Xputch(c)
  339. X{
  340. X    static  nleft=0;
  341. X
  342. X    if(!c || nleft>=256){
  343. X        if(nleft)
  344. X            write(1,gblock,nleft);
  345. X        nleft=0;
  346. X    }
  347. X    if(!c)
  348. X        return;
  349. X    gblock[nleft++]= c;
  350. X}
  351. X
  352. X/*      lastch() returns the last character on the line used in the
  353. X *    editor to see if any more characters can be placed on the line and
  354. X *    by the redraw key.
  355. X */
  356. X
  357. Xlastch(f)
  358. X{
  359. X    register char   *p;
  360. X    register char   *q;
  361. X    p= &line[f];
  362. X    q= &line[MAXLIN];
  363. X    while(*q==' ' && q>=p)
  364. X        q--;
  365. X    return(q-line+1);
  366. X}
  367. X
  368. X/* delete from current cursor position to end of line. */
  369. X
  370. Xdeol(cursr)
  371. X{
  372. X    register cc,i;
  373. X    if(*o_DEOL){
  374. X        puts(o_DEOL);
  375. X        return;
  376. X    }
  377. X    i = ter_width - (cursr % ter_width);
  378. X    for(cc = i ; cc ; cc--)
  379. X        putch(' ');
  380. X    for(; i ; i--)
  381. X        puts(o_LEFT);
  382. X}
  383. X
  384. X/* delete nchar characters from cursr */
  385. X
  386. Xdelchar(cursr,lc)
  387. X{
  388. X    register char   *p;
  389. X    register char   *q;
  390. X    p = &line[cursr];
  391. X    q = &line[lc];
  392. X    while(p < q )
  393. X        putch(*p++);
  394. X    q = &line[cursr];
  395. X    while(p > q ){
  396. X        if( *o_UP && p - q > ter_width ){
  397. X            puts(o_UP);
  398. X            p -= ter_width;
  399. X        }
  400. X        else {
  401. X            p--;
  402. X            puts(o_LEFT);
  403. X        }
  404. X    }
  405. X}
  406. X
  407. X/* display a new character */
  408. X
  409. Xinchar(cursr,lastc,c)
  410. X{
  411. X    register char   *p,*q;
  412. X    p = &line[cursr+1];
  413. X    q = &line[lastc+1];
  414. X    putch(c);
  415. X    while(p < q)
  416. X        putch(*p++);
  417. X    q = &line[cursr];
  418. X    while(p > q ){
  419. X        if( *o_UP && p - q > ter_width ){
  420. X            puts(o_UP);
  421. X            p -= ter_width;
  422. X        }
  423. X        else {
  424. X            p--;
  425. X            puts(o_LEFT);
  426. X        }
  427. X    }
  428. X}
  429. End of bas7.c
  430. chmod u=rw-,g=r,o=r bas7.c
  431. echo x - bas8.c 1>&2
  432. sed 's/^X//' > bas8.c << 'End of bas8.c'
  433. X/*
  434. X * BASIC by Phil Cockcroft
  435. X */
  436. X#include        "bas.h"
  437. X
  438. X/*
  439. X *      This file contains all the standard commands that are not placed
  440. X *    anywhere else for any reason.
  441. X */
  442. X
  443. X/*
  444. X *      The 'for' command , this is fairly straight forward , but
  445. X *    the way that the variable is not allowed to be indexed is
  446. X *    dependent on the layout of variables in core.
  447. X *      Most of the fiddly bits of code are so that all the variables
  448. X *    are of the right type (real / integer ). The code for putting
  449. X *    a '1' in the step for default cases is not very good and could be
  450. X *    improved.
  451. X *      A variable is accessed by its displacement from 'earray'
  452. X *    it is this index that speeds execution ( no need to search through
  453. X *    the variables for a name ) and that enables the next routine to be
  454. X *    so efficient.
  455. X */
  456. X
  457. Xforr()
  458. X{
  459. X    register struct forst *p;
  460. X    register memp   l;
  461. X    register char   *r;
  462. X    char    vty;
  463. X    value   start;
  464. X    value   end;
  465. X    value   step;
  466. X
  467. X    l=getname();
  468. X    vty=vartype;
  469. X    if(l<earray)                    /* string or array element */
  470. X        error(2);               /* variable required */
  471. X    if(getch()!='=')
  472. X        error(SYNTAX);
  473. X    r= (char *)(l - earray);        /* index */
  474. X    eval();                         /* get the from part */
  475. X    putin(&start,vty);              /* convert and move the right type */
  476. X    if(getch()!=TO)
  477. X        error(SYNTAX);
  478. X    eval();                         /* the to part */
  479. X    putin(&end,vty);
  480. X    if(getch()==STEP)
  481. X        eval();                 /* the step part */
  482. X    else {
  483. X        point--;                /* default case */
  484. X        res.i=1;
  485. X        vartype = 01;
  486. X    }
  487. X    putin(&step,vty);
  488. X    check();                                /* syntax check */
  489. X    for(p=(forstp)vvend,p--;p>=(forstp)bstk;p--) /* have we had it */
  490. X        if(p->fr && p->fnnm == r)       /* in a for loop before */
  491. X            goto got;          /* if so then reset its limits */
  492. X    p= (forstp)vvend;
  493. X    vvend += sizeof(struct forst);  /* no then allocate a */
  494. X    mtest(vvend);                   /* new structure on the stack */
  495. X    p->fnnm=r;
  496. X    p->fr= 01+vty;
  497. Xgot:    p->elses=elsecount;             /* set up all information for the */
  498. X    p->stolin=stocurlin;            /* next routine */
  499. X    p->pt=point;
  500. X    vartype=vty;
  501. X#ifndef V6C
  502. X    p->final = end;
  503. X    p->step = step;
  504. X    res = start;
  505. X#else
  506. X    movein(&end,&p->final);        /* move the variables to the correct */
  507. X    movein(&step,&p->step);         /* positions */
  508. X    movein(&start,&res);
  509. X#endif
  510. X#ifdef  LNAMES
  511. X    l = (int)r + earray;                    /* force it back */
  512. X#endif
  513. X    putin(l,vty);
  514. X    normret;
  515. X}
  516. X
  517. X/*
  518. X *      the 'next' command , this does not need an argument , if there is
  519. X *    none then the most deeply nested 'next' is accessed. If there is
  520. X *    a list of arguments then the variable name is accessed and a search
  521. X *    is made for it. ( next_without_for error ). Then the step is added
  522. X *    to the varable and the result is compared to the final. If the loop
  523. X *    is not ended then the stack is set to the end of this 'for' structure
  524. X *    and a return is executed. Otherwise the stack is popped and a return
  525. X *    to the required line is performed.
  526. X */
  527. X
  528. X
  529. Xnext()
  530. X{
  531. X    register struct forst *p;
  532. X    register value  *l;
  533. X    register char   *r;
  534. X    register int    c;
  535. X
  536. X    c=getch();
  537. X    point--;
  538. X    if(istermin(c)){                /* no argument */
  539. X        for( p = (forstp)vvend , p-- ; p >= (forstp)bstk ; p--)
  540. X            if(p->fr){
  541. X                l =  (value *)(p->fnnm + (int) earray);
  542. X                goto got;
  543. X            }
  544. X        error(18);      /* no next */
  545. X    }
  546. Xfor(;;){
  547. X    l= (value *)getname();
  548. X    r= (memp)((memp)l - earray);
  549. X    for(p= (forstp)vvend , p-- ; p >= (forstp)bstk ; p--)
  550. X        if(p->fr &&p->fnnm == r)
  551. X            goto got;
  552. X    error(18);                      /* next without for */
  553. Xgot:    vartype=p->fr-1;
  554. X    if(vartype){
  555. X#ifndef pdp11
  556. X#ifdef  VAX_ASSEM                       /* if want to use assembler */
  557. X        l->i += p->step.i;
  558. X        asm("        bvc nov");         /* it is a lot faster.... */
  559. X            error(35);
  560. X        asm("nov:");
  561. X#else
  562. X        register long   m = p->step.i;
  563. X        if( (m += l->i) > 32767 || m < -32768 )
  564. X            error(35);
  565. X        else l->i = m;
  566. X#endif
  567. X#else
  568. X        foreadd(p->step.i,l);
  569. X#endif
  570. X        if(p->step.i < 0){
  571. X            if( l->i >= p->final.i)
  572. X                goto nort;
  573. X            else goto rt;
  574. X        }
  575. X        else if( l->i <= p->final.i)
  576. X            goto nort;
  577. X    }
  578. X    else {
  579. X        fadd(&p->step, l );
  580. X        if(p->step.i <0){               /* bit twiddling */
  581. X#ifndef SOFTFP
  582. X            if( l->f >= p->final.f)
  583. X                goto nort;
  584. X            else goto rt;
  585. X        }
  586. X        else if( l->f <= p->final.f)
  587. X            goto nort;
  588. X#else
  589. X            if(cmp(l,&p->final)>=0 )
  590. X                goto nort;
  591. X            goto rt;
  592. X        }
  593. X        else  if(cmp(l,&p->final)<= 0)
  594. X            goto nort;
  595. X#endif
  596. X    }
  597. Xrt:     vvend=(memp)p;                  /* don't loop - pop the stack */
  598. X    if(getch()==',')
  599. X        continue;
  600. X    else point--;
  601. X    break;
  602. Xnort:
  603. X    if(stocurlin=p->stolin)                 /* go back to the 'for' */
  604. X        curline=stocurlin->linnumb;     /* need this for very */
  605. X    else runmode=0;                         /* obscure reasons */
  606. X    point = p->pt;
  607. X    elsecount=p->elses;
  608. X    vvend = (memp) (p+1);
  609. X    break;
  610. X    }
  611. X    normret;
  612. X}
  613. X
  614. X/*
  615. X *      The 'gosub' command , This uses the same structure as 'for' for
  616. X *    the storage of data. A gosub is identified by the flag 'fr' in
  617. X *    the 'for' structure being zero. This just gets the line on which
  618. X *    we are on and sets up th structure. Gosubs from immeadiate mode
  619. X *    are dealt with and this is one of the obscure reasons for the
  620. X *    the comment and code in 'return' and 'next'.
  621. X */
  622. X
  623. Xgosub()
  624. X{
  625. X    register struct forst   *p;
  626. X    register lpoint l;
  627. X
  628. X    l=getline();
  629. X    check();
  630. X    p = (forstp) vvend;
  631. X    vvend += sizeof(struct forst);
  632. X    mtest(vvend);
  633. X    runmode=1;
  634. X    p->fr=0;
  635. X    p->fnnm=0;
  636. X    p->elses=elsecount;
  637. X    p->pt=point;
  638. X    p->stolin=stocurlin;
  639. X    stocurlin=l;
  640. X    curline=l->linnumb;
  641. X    point= l->lin;
  642. X    elsecount=0;
  643. X    return(-1);     /* return to execute the next instruction */
  644. X}
  645. X
  646. X/*
  647. X *      The 'return' command this just searches the stack for the
  648. X *    first gosub/return it can find, pops the stack to that level
  649. X *    and returns to the correct point. Deals with returns to
  650. X *    immeadiate mode, as well.
  651. X */
  652. X
  653. Xretn()
  654. X{
  655. X    register struct forst   *p;
  656. X
  657. X    check();
  658. X    for(p= (forstp)vvend , p-- ; p >= (forstp)bstk ; p--)
  659. X        if(!p->fr && !p->fnnm)
  660. X            goto got;
  661. X    error(21);              /* return without gosub */
  662. Xgot:
  663. X    elsecount=p->elses;
  664. X    point=p->pt;
  665. X    if(stocurlin=p->stolin)
  666. X        curline=stocurlin->linnumb;
  667. X    else runmode=0;                 /* return to immeadiate mode */
  668. X    vvend= (memp)p;
  669. X    normret;
  670. X}
  671. X
  672. X/*
  673. X *      The 'run' command , run will execute a program by putting it in
  674. X *    runmode and setting the start address to the start of the program
  675. X *    or to the optional line number. It clears all the variables and
  676. X *    closes all files.
  677. X */
  678. X
  679. Xrunn()
  680. X{
  681. X    register lpoint p;
  682. X    register unsigned l;
  683. X
  684. X    l=getlin();
  685. X    check();
  686. X    p = (lpoint)fendcore;
  687. X    if(l== (unsigned)(-1) )
  688. X        goto got;
  689. X    else for(;p->linnumb; p = (lpoint)((memp) p + lenv(p)) )
  690. X        if(l== p->linnumb)
  691. X            goto got;
  692. X    error(6);               /* undefined line */
  693. Xgot:
  694. X    clear(DEFAULTSTRING);   /* zap the variables */
  695. X    closeall();
  696. X    if(!p->linnumb)                 /* no program so return */
  697. X        reset();
  698. X    curline=p->linnumb;     /* set up all the standard pointers */
  699. X    stocurlin=p;
  700. X    point=p->lin;
  701. X    elsecount=0;
  702. X    runmode=1;
  703. X    return(-1);             /* return to execute the next instruction */
  704. X}
  705. X
  706. X/*
  707. X *      The 'end' command , checks its syntax ( no parameters ) then
  708. X *    gets out of what we were doing.
  709. X */
  710. X
  711. Xendd()
  712. X{
  713. X    check();
  714. X    reset();
  715. X}
  716. X
  717. X/*
  718. X *      The 'goto' command , simply gets the required line number
  719. X *    and sets the pointers to it. If in immeadiate mode , go into
  720. X *    runmode and zap the stack .
  721. X */
  722. X
  723. Xgotos()
  724. X{
  725. X    register lpoint p;
  726. X    p=getline();
  727. X    check();
  728. X    curline=p->linnumb;
  729. X    point=p->lin;
  730. X    stocurlin=p;
  731. X    elsecount=0;
  732. X    if(!runmode){
  733. X        runmode++;
  734. X        vvend=bstk;     /* zap the stack */
  735. X    }
  736. X    return(-1);
  737. X}
  738. X
  739. X/*
  740. X *      The 'print' command , The code for this routine is rather weird.
  741. X *    It works ( well ) for all types of printing ( including files ),
  742. X *    but it is a bit 'kludgy' and could be done better ( I don't know
  743. X *    how ). Every expression must be followed by a comma a semicolon
  744. X *    or the end of a statement. To get it all to work was tricky but it
  745. X *    now does and that is all that can be said for it.
  746. X *      The use of filedes assumes that an integer has the same size as
  747. X *      a structure pointer. If this is not the case. This system will not
  748. X *      work ( nor will most of the rest of the interpreter ).
  749. X */
  750. X
  751. Xprint()
  752. X{
  753. X    int     i;
  754. X    register int     c;
  755. X    extern  write(),putfile();
  756. X    static  char    spaces[]="                ";    /* 16 spaces */
  757. X    register int    (*outfunc)();   /* pointer to the output function */
  758. X    register int    *curcursor;     /* pointer to the current cursor */
  759. X                    /* 'posn' if a file, or 'cursor' */
  760. X    int     Twidth;                 /* width of the screen or of the */
  761. X    filebufp filedes;               /* file. BLOCKSIZ if a file */
  762. X
  763. X    c=getch();
  764. X    if(c=='#'){
  765. X        i=evalint();
  766. X        if(getch()!=',')
  767. X            error(SYNTAX);
  768. X        filedes=getf(i,_WRITE);
  769. X        outfunc= putfile;               /* see bas6.c */
  770. X        curcursor= &filedes->posn;
  771. X        Twidth = BLOCKSIZ;
  772. X        c=getch();
  773. X    }
  774. X    else {
  775. X        outfunc= write;
  776. X        curcursor= &cursor;
  777. X        filedes = (filebufp)1;
  778. X        Twidth = ter_width;
  779. X    }
  780. X    point--;
  781. X
  782. Xfor(;;){
  783. X    if(istermin(c))
  784. X        break;
  785. X    else if(c==TABB){                       /* tabing */
  786. X        point++;
  787. X        if(*point++!='(')
  788. X            error(SYNTAX);
  789. X        i=evalint();
  790. X        if(getch()!=')')
  791. X            error(SYNTAX);
  792. X        while(i > *curcursor+16 && !trapped){
  793. X            (*outfunc)(filedes,spaces,16);
  794. X            *curcursor+=16;
  795. X        }
  796. X        if(i> *curcursor && !trapped){
  797. X            (*outfunc)(filedes,spaces,i- *curcursor);
  798. X            *curcursor = i;
  799. X        }
  800. X        *curcursor %= Twidth;
  801. X        c=getch();
  802. X        goto outtab;
  803. X    }
  804. X    else if(c==',' || c==';'){
  805. X        point++;
  806. X        goto outtab;
  807. X    }
  808. X    else if(checktype())
  809. X        stringeval(gblock);
  810. X    else {
  811. X        eval();
  812. X        gcvt();
  813. X    }
  814. X    (*outfunc)(filedes,gblock,gcursiz);
  815. X    *curcursor = (*curcursor + gcursiz) % Twidth;
  816. X    c=getch();
  817. Xouttab: if(c==',' ||c==';'){
  818. X        if(c==','){
  819. X            (*outfunc)(filedes,spaces,16-(*curcursor%16));
  820. X            *curcursor=(*curcursor+(16- *curcursor%16)) % Twidth;
  821. X        }
  822. X        c=getch();
  823. X        point--;
  824. X        if(istermin(c))
  825. X            normret;
  826. X    }
  827. X    else if(istermin(c)){
  828. X        point--;
  829. X        break;
  830. X    }
  831. X    else error(SYNTAX);
  832. X    }
  833. X
  834. X    (*outfunc)(filedes,nl,1);
  835. X    *curcursor=0;
  836. X    normret;
  837. X}
  838. X
  839. X/*
  840. X *      The 'if' command , no real problems here but the 'else' part
  841. X *    could do with a bit more checking of what it's going over.
  842. X */
  843. X
  844. Xiff()
  845. X{
  846. X    register int    elsees;
  847. X    register int    c;
  848. X    register char   *p;
  849. X
  850. X    eval();
  851. X    if(getch()!=THEN)
  852. X        error(SYNTAX);
  853. X#ifdef  PORTABLE
  854. X    if(vartype ? res.i : res.f){
  855. X#else
  856. X    if(res.i ){                     /* naughty bit twiddleing */
  857. X#endif
  858. X        c=getch();              /* true */
  859. X        point--;
  860. X        elsecount++;            /* say `else`s are allowed */
  861. X        if(isnumber(c))         /* if it's a number then */
  862. X            gotos();        /* execute a goto */
  863. X        return(-1);             /* return to execute another ins. */
  864. X    }
  865. X    for(elsees = 0, p= point; *p ; p++) /* skip all nested 'if'-'else' */
  866. X        if(*p==(char)ELSE){         /* pairs */
  867. X            if(--elsees < 0){
  868. X                p++;
  869. X                break;
  870. X            }
  871. X        }
  872. X        else if(*p==(char)IF)
  873. X            elsees++;
  874. X    point = p;                      /* we are after the else or at */
  875. X    if(!*p)
  876. X        normret;
  877. X    while(*p++ == ' ');             /* end of line */
  878. X    p--;                            /* ignore the space after else */
  879. X    if(isnumber(*p))                /* if number then do a goto */
  880. X        gotos();
  881. X    return(-1);
  882. X}
  883. X
  884. X/*
  885. X *      The 'on' command , this deals with everything , it has to do
  886. X *    its own searching so that undefined lines are not accessed until
  887. X *    a 'goto' to that line is actually required.
  888. X *    Deals with on_gosubs from immeadiate mode.
  889. X */
  890. X
  891. Xonn()
  892. X{
  893. X    unsigned lnm[128];
  894. X    register unsigned *l;
  895. X    register lpoint p;
  896. X    register forstp pt;
  897. X    int     m;
  898. X    int     i;
  899. X    int     c;
  900. X    int     k;
  901. X
  902. X    if(getch()==ERROR){
  903. X        if(getch()!=GOTO)
  904. X            error(SYNTAX);
  905. X        errtrap();      /* do the trapping of errors */
  906. X        normret;
  907. X    }
  908. X    else point--;
  909. X    m=evalint();
  910. X    if((k=getch())!= GOTO && k != GOSUB)
  911. X        error(SYNTAX);
  912. X    for(l=lnm,i=1;;l++,i++){        /* get the line numbers */
  913. X        if( (*l = getlin()) == (unsigned)(-1) )
  914. X            error(5);       /* line number required */
  915. X        if(getch()!=',')
  916. X            break;
  917. X    }
  918. X    point--;
  919. X    check();
  920. X    if(m<1 || m> i)                 /* index is out of bounds */
  921. X        normret;                /* so return */
  922. X    c= lnm[m-1];
  923. X    for(p = (lpoint)fendcore ; p->linnumb ;
  924. X                    p = (lpoint)((memp)p + lenv(p)) )
  925. X        if(p->linnumb==c)
  926. X            goto got;
  927. X    error(6);                       /* undefined line */
  928. Xgot:    if(k== GOSUB) {
  929. X        pt=(forstp)vvend;               /* fix the gosub stack */
  930. X        vvend += sizeof(struct forst);
  931. X        mtest(vvend);
  932. X        pt->fnnm=0;
  933. X        pt->fr=0;
  934. X        pt->elses=elsecount;
  935. X        pt->pt=point;
  936. X        pt->stolin=stocurlin;
  937. X    }
  938. X    if(!runmode){
  939. X        runmode++;
  940. X        if(k==GOTO)             /* gotos in immeadiate mode */
  941. X            vvend=bstk;
  942. X    }
  943. X    stocurlin=p;
  944. X    curline=p->linnumb;
  945. X    point= p->lin;
  946. X    elsecount=0;
  947. X    return(-1);
  948. X}
  949. X
  950. X/*
  951. X *      The 'cls' command , neads to set the terminal into 'rare' mode
  952. X *    so that there is no waiting on the page clearing ( form feed ).
  953. X */
  954. X
  955. Xcls()
  956. X{
  957. X    extern  char    o_CLEARSCR[];
  958. X
  959. X    set_term();
  960. X    puts(o_CLEARSCR);
  961. X    putch(0);       /* flush it out */
  962. X    rset_term(0);
  963. X    cursor = 0;
  964. X    normret;
  965. X}
  966. X
  967. X/*
  968. X *      The 'base' command , sets the start index for arrays to either
  969. X *      '0' or '1' , simple.
  970. X */
  971. X
  972. Xbase()
  973. X{
  974. X    register int    i;
  975. X    i=evalint();
  976. X    check();
  977. X    if(i && i!=1)
  978. X        error(28);      /* bad base value */
  979. X    baseval=i;
  980. X    normret;
  981. X}
  982. X
  983. X/*
  984. X *      The 'rem' and '\'' command , ignore the rest of the line
  985. X */
  986. X
  987. Xrem() {  return(GTO); }
  988. X
  989. X/*
  990. X *      The 'let' command , all the work is done in assign , the first
  991. X *    getch() is to get the pointer in the right place for assign().
  992. X */
  993. X
  994. Xlets()
  995. X{
  996. X    assign();
  997. X    normret;
  998. X}
  999. X
  1000. X/*
  1001. X *      The 'clear' command , clears all variables , closes all files
  1002. X *    and allocates the required amount of storage for strings,
  1003. X *    maximum is 32K.
  1004. X */
  1005. X
  1006. Xclearl()
  1007. X{
  1008. X    register int    i;
  1009. X
  1010. X    i=evalint();
  1011. X    check();
  1012. X    if(i < 0 || i + ecore > MAXMEM)
  1013. X        error(12);      /* bad core size */
  1014. X    clear(i);
  1015. X    closeall();
  1016. X    normret;
  1017. X}
  1018. X
  1019. X/*
  1020. X *      The 'list' command , can have an optional two arguments and
  1021. X *    a dash is also used.
  1022. X *      Most of this routine is the getting of the arguments. All the
  1023. X *    actual listing is done in listl() , This routine should call write()
  1024. X *    and not clr(), but then the world is not perfect.
  1025. X */
  1026. X
  1027. Xlist()
  1028. X{
  1029. X    register unsigned l1,l2;
  1030. X    register lpoint p;
  1031. X    l1=getlin();
  1032. X    if(l1== (unsigned)(-1) ){
  1033. X        l1=0;
  1034. X        l2= -1;
  1035. X        if(getch()=='-'){
  1036. X            if( (l2 = getlin()) == (unsigned)(-1) )
  1037. X                error(SYNTAX);
  1038. X        }
  1039. X        else point--;
  1040. X    }
  1041. X    else  {
  1042. X        if(getch()!='-'){
  1043. X            l2= l1;
  1044. X            point--;
  1045. X        }
  1046. X        else
  1047. X            l2 = getlin();
  1048. X    }
  1049. X    check();
  1050. X    for(p= (lpoint)fendcore ; p->linnumb < l1 ;
  1051. X                    p = (lpoint)((memp)p + lenv(p)) )
  1052. X        if(!p->linnumb)
  1053. X            reset();
  1054. X    if(l1== l2 && l1 != p->linnumb )
  1055. X            reset();
  1056. X    while(p->linnumb && p->linnumb <=l2 && !trapped){
  1057. X        l1=listl(p);
  1058. X        line[l1++] = '\n';
  1059. X        write(1,line,(int)l1);
  1060. X        p = (lpoint)((memp)p + lenv(p));
  1061. X    }
  1062. X    reset();
  1063. X}
  1064. X
  1065. X/*
  1066. X *      The routine that does the listing of a line , it searches through
  1067. X *    the table of reserved words if it find a byte with the top bit set,
  1068. X *    It should ( ha ha ) find it.
  1069. X *      This routine could run off the end of line[] since line is followed
  1070. X *    by nline[] this should not cause any problems.
  1071. X *      The result is in line[].
  1072. X */
  1073. X
  1074. Xlistl(p)
  1075. Xlpoint p;
  1076. X{
  1077. X    register char   *q;
  1078. X    register struct tabl *l;
  1079. X    register char    *r;
  1080. X
  1081. X    r=strcpy(printlin(p->linnumb) ,line);  /* do the linenumber */
  1082. X    for(q= p->lin; *q && r < &line[MAXLIN]; q++){
  1083. X        if(*q &(char)0200)              /* reserved words */
  1084. X            for(l=table;l->chval;l++){
  1085. X                if((char)(l->chval) == *q){
  1086. X                    r=strcpy(l->string,r);
  1087. X                    break;
  1088. X                }
  1089. X            }
  1090. X        else if(*q<' '){                /* do special characters */
  1091. X            *r++ ='\\';
  1092. X            *r++ = *q+ ('a'-1);
  1093. X        }
  1094. X        else {
  1095. X            if(*q == '\\')          /* the special character */
  1096. X                *r++ = *q;
  1097. X            *r++ = *q;              /* non special characters */
  1098. X        }
  1099. X    }
  1100. X    if(r >= &line[MAXLIN])                  /* get it back a bit */
  1101. X        r = &line[MAXLIN-1];
  1102. X    *r=0;
  1103. X    return(r-line);                 /* length of line */
  1104. X}
  1105. X
  1106. X/*
  1107. X *      The 'stop' command , prints the message that it has stopped
  1108. X *    and then exits the 'user' program.
  1109. X */
  1110. X
  1111. Xstop()
  1112. X{
  1113. X    check();
  1114. X    dostop(0);
  1115. X}
  1116. X
  1117. X/*
  1118. X *      Called if trapped is set (by control-c ) and just calls dostop
  1119. X *    with a different parameter to print a slightly different message
  1120. X */
  1121. X
  1122. Xdobreak()
  1123. X{
  1124. X    dostop(1);
  1125. X}
  1126. X
  1127. X/*
  1128. X *      prints out the 'stopped' or 'breaking' message then exits.
  1129. X *    These two functions were lumped together so that it might be
  1130. X *    possible to add a 'cont'inue command at a latter date ( not
  1131. X *    implemented yet ) - ( it is now ).
  1132. X */
  1133. X
  1134. Xdostop(i)
  1135. X{
  1136. X    if(cursor){
  1137. X        cursor=0;
  1138. X        prints(nl);
  1139. X    }
  1140. X    prints( (i) ? "breaking" : "stopped" );
  1141. X    if(runmode){
  1142. X        prints(" at line ");
  1143. X        prints(printlin(curline));
  1144. X        if(!intrap){            /* save environment */
  1145. X            cancont=i+1;
  1146. X            conpoint=point;
  1147. X            constolin=stocurlin;
  1148. X            concurlin=curline;
  1149. X            contelse=elsecount;
  1150. X            conerp=errortrap;
  1151. X        }
  1152. X    }
  1153. X    prints(nl);
  1154. X    reset();
  1155. X}
  1156. X
  1157. X/*      the 'cont' command - it seems to work ?? */
  1158. X
  1159. Xcont()
  1160. X{
  1161. X    check();
  1162. X    if( contpos && !runmode){
  1163. X        point = conpoint;       /* restore environment */
  1164. X        stocurlin =constolin;
  1165. X        curline = concurlin;
  1166. X        elsecount = contelse;
  1167. X        errortrap = conerp;
  1168. X        vvend= bstk;
  1169. X        bstk = vend;
  1170. X        mtest(vvend);           /* yeuch */
  1171. X        runmode =1;
  1172. X        if(contpos==1){
  1173. X            contpos=0;
  1174. X            normret;        /* stopped */
  1175. X        }
  1176. X        contpos=0;              /* ctrl-c ed */
  1177. X        return(-1);
  1178. X    }
  1179. X    contpos=0;
  1180. X    error(CANTCONT);
  1181. X}
  1182. X
  1183. X/*
  1184. X *      The 'delete' command , will only delete the required lines if it
  1185. X *    can find the two end lines. stops ' delete 1' etc. as a slip up.
  1186. X *      very slow algorithm. But who cares ??
  1187. X */
  1188. X
  1189. Xdelete()
  1190. X{
  1191. X    register lpoint p1,p2;
  1192. X    register unsigned i2;
  1193. X
  1194. X    p1=getline();
  1195. X    if(getch()!='-')
  1196. X        error(SYNTAX);
  1197. X    p2=getline();
  1198. X    check();
  1199. X    if(p1>p2)
  1200. X        reset();
  1201. X    i2 = p2->linnumb;
  1202. X    do{
  1203. X        linenumber = p1->linnumb;
  1204. X        insert(0);
  1205. X    }while(p1->linnumb && p1->linnumb <= i2 );
  1206. X    reset();
  1207. X}
  1208. X
  1209. X/*
  1210. X *      The 'shell' command , calls the v7 shell as an entry into unix
  1211. X *    without going out of basic. Has to set the terminal in a decent
  1212. X *    mode , else 'ded' doesn't like it.
  1213. X *      Clears out all buffered file output , so that you can see what
  1214. X *    you have done so far, and sets your userid to your real-id
  1215. X *    this stops people becoming unauthorised users if basic is made
  1216. X *    setuid ( for games via runfile of the command file ).
  1217. X */
  1218. X
  1219. Xshell()
  1220. X{
  1221. X    register int    i;
  1222. X    register int    (*q)() , (*p)();
  1223. X    int     (*signal())();
  1224. X    char    *s;
  1225. X#ifdef  SIGTSTP
  1226. X    int     (*t)();
  1227. X#endif
  1228. X
  1229. X    check();
  1230. X    flushall();
  1231. X#ifdef  SIGTSTP
  1232. X    t = signal(SIGTSTP, SIG_DFL);
  1233. X#endif
  1234. X#ifdef  VFORK
  1235. X    i = vfork();
  1236. X#else
  1237. X    i=fork();
  1238. X#endif
  1239. X    if(i==0){
  1240. X        rset_term(1);
  1241. X        setuid(getuid());               /* stop user getting clever */
  1242. X#ifdef  V7
  1243. X        s = getenv("SHELL");
  1244. X        if(!s || !*s)
  1245. X            s = "/bin/sh";
  1246. X#else
  1247. X        s = "/bin/sh";
  1248. X#endif
  1249. X        execl(s,"sh (from basic)",0);
  1250. X        exit(-1);                       /* problem */
  1251. X    }
  1252. X    else if(i== -1)
  1253. X        prints("cannot shell out\n");
  1254. X    else {                                  /* daddy */
  1255. X        p=signal(SIGINT,SIG_IGN);       /* ignore some signals */
  1256. X        q=signal(SIGQUIT, SIG_IGN);
  1257. X        while(i != wait(0) && i != -1); /* wait on the 'child' */
  1258. X        signal(SIGINT,p);               /* resignal to what they */
  1259. X        signal(SIGQUIT,q);              /* were before */
  1260. X    }                                       /* in a mode fit for basic */
  1261. X#ifdef  SIGTSTP
  1262. X    signal(SIGTSTP, t);
  1263. X#endif
  1264. X    normret;
  1265. X}
  1266. X
  1267. X/*
  1268. X *      The 'edit' command , can only edit in immeadiate mode , and with the
  1269. X *    specified line ( maybe could be more friendly here , no real need to
  1270. X *    since the editor is the same as on line input.
  1271. X */
  1272. X
  1273. Xeditl()
  1274. X{
  1275. X    register lpoint p;
  1276. X    register int    i;
  1277. X
  1278. X    p= getline();
  1279. X    check();
  1280. X    if(runmode || noedit)
  1281. X        error(13);      /* illegal edit */
  1282. X    i=listl(p);
  1283. X    edit(0,i,0);            /* do the edit */
  1284. X    if(trapped)             /* ignore it if exited via cntrl-c */
  1285. X        reset();
  1286. X    i=compile(0);
  1287. X    if(linenumber)          /* ignore it if there is no line number */
  1288. X        insert(i);
  1289. X    reset();                /* return to 'ready' */
  1290. X}
  1291. X
  1292. X/*
  1293. X *      The 'auto' command , allows input of lines with automatic line
  1294. X *    numbering. Most of the code is to do with getting the arguments
  1295. X *    otherwise the loop is fairly simple. There are three ways of getting
  1296. X *    out of this routine. cntrl-c will exit the routine immeadiately
  1297. X *    If there is no linenumber then it also exits. If the line typed in is
  1298. X *    terminated by an ESCAPE character the line is inserted and the routine
  1299. X *    is terminated.
  1300. X */
  1301. X
  1302. Xdauto()
  1303. X{
  1304. X    register unsigned start , end , i1;
  1305. X    unsigned int      i2;
  1306. X    long    l;
  1307. X    int     c;
  1308. X    i2=autoincr;
  1309. X    i1=getlin();
  1310. X    if( i1 != (unsigned)(-1) ){
  1311. X        if(getch()!= ','){
  1312. X            point--;
  1313. X            i2=autoincr;
  1314. X        }
  1315. X        else {
  1316. X            i2=getlin();
  1317. X            if(i2 == (unsigned)(-1) )
  1318. X                error(SYNTAX);
  1319. X        }
  1320. X    }
  1321. X    else
  1322. X        i1=autostart;
  1323. X    check();
  1324. X    start=i1;
  1325. X    autoincr=i2;
  1326. X    end=i2;
  1327. X    for(;;){
  1328. X        i1= strcpy(printlin(start),line) - line;
  1329. X        line[i1++]=' ';
  1330. X        c=edit(0,i1,i1);
  1331. X        if(trapped)
  1332. X            break;
  1333. X        i1=compile(0);
  1334. X        if(!linenumber)
  1335. X            break;
  1336. X        insert(i1);
  1337. X        if( (l= (long)start+end) >=65530){
  1338. X            autostart=10;
  1339. X            autoincr=10;
  1340. X            error(6);       /* undefined line number */
  1341. X        }
  1342. X        start+=end;
  1343. X        autostart=l;
  1344. X        if(c == ESCAPE )
  1345. X            break;
  1346. X    }
  1347. X    reset();
  1348. X}
  1349. X
  1350. X/*
  1351. X *      The 'save' command , saves a basic program on a file.
  1352. X *    It just lists the lines adds a newline then writes them out
  1353. X */
  1354. X
  1355. Xsave()
  1356. X{
  1357. X    register lpoint p;
  1358. X    register int    fp;
  1359. X    register int    i;
  1360. X
  1361. X    stringeval(gblock);     /* get the name */
  1362. X    gblock[gcursiz]=0;
  1363. X    check();
  1364. X    if((fp=creat(gblock,0644))== -1)
  1365. X        error(14);              /* cannot creat file */
  1366. X    for(p= (lpoint)fendcore ; p->linnumb ;
  1367. X                    p = (lpoint)((memp) p + lenv(p)) ){
  1368. X        i=listl(p);
  1369. X        line[i++]='\n';
  1370. X        write(fp,line,i);       /* could be buffered ???? */
  1371. X    }
  1372. X    close(fp);
  1373. X    normret;
  1374. X}
  1375. X
  1376. X/*
  1377. X *      The 'old' command , loads a program from a file. The old
  1378. X *    program (if any ) is wiped.
  1379. X *      Most of the work is done in readfi, ( see also error ).
  1380. X */
  1381. X
  1382. Xold()
  1383. X{
  1384. X    register int    fp;
  1385. X
  1386. X    stringeval(gblock);
  1387. X    gblock[gcursiz]=0;              /* get the file name */
  1388. X    check();
  1389. X    if((fp=open(gblock,0))== -1)
  1390. X        error(15);              /* can't open file */
  1391. X    ecore= fendcore+sizeof(xlinnumb);       /* zap old program */
  1392. X    ( (lpoint) fendcore)->linnumb=0;
  1393. X    readfi(fp);                     /* read the new file */
  1394. X    reset();
  1395. X}
  1396. X
  1397. X/*
  1398. X *      The 'merge' command , similar to 'old' but does not zap the old
  1399. X *    program so the two files are 'merged' .
  1400. X */
  1401. X
  1402. Xmerge()
  1403. X{
  1404. X    register int    fp;
  1405. X
  1406. X    stringeval(gblock);
  1407. X    gblock[gcursiz]=0;
  1408. X    check();
  1409. X    if((fp=open(gblock,0))== -1)
  1410. X        error(15);
  1411. X    readfi(fp);
  1412. X    reset();
  1413. X}
  1414. X
  1415. X/*
  1416. X *      The routine that actually reads in a file. It sets up readfile
  1417. X *    so that if there is an error ( linenumber overflow ) , then error
  1418. X *    can pick up the pieces , else the number of file descriptors are
  1419. X *    reduced and can ( unlikely ), run out of them so stopping any file
  1420. X *    being saved or restored , ( This is the reason that all files are
  1421. X *    closed so meticulacly ( see 'chain' and its  pipes ).
  1422. X */
  1423. X
  1424. Xreadfi(fp)
  1425. X{
  1426. X    register char   *p;
  1427. X    int     i;
  1428. X    char    chblock[BLOCKSIZ];
  1429. X    int     nleft=0;
  1430. X    register int    special=0;
  1431. X    register char   *q;
  1432. X
  1433. X    readfile=fp;
  1434. X    inserted=1;     /* make certain variables are cleared */
  1435. X    p=line;         /* input into line[] */
  1436. X    for(;;){
  1437. X        if(!nleft){
  1438. X            q=chblock;
  1439. X            if( (nleft=read(fp,q,BLOCKSIZ)) <= 0)
  1440. X                break;
  1441. X        }
  1442. X        *p= *q++;
  1443. X        nleft--;
  1444. X        if(special){
  1445. X            special=0;
  1446. X            if(*p>='a' && *p<='~'){
  1447. X                *p -= ('a'-1);
  1448. X                continue;
  1449. X            }
  1450. X        }
  1451. X        if(*p =='\n'){
  1452. X            *p=0;
  1453. X            i=compile(0);
  1454. X            if(!linenumber)
  1455. X                goto bad;
  1456. X            insert(i);
  1457. X            p=line;
  1458. X            continue;
  1459. X        }
  1460. X        else if(*p<' ')
  1461. X            goto bad;
  1462. X        else if(*p=='\\')
  1463. X            special++;
  1464. X        if(++p > &line[MAXLIN])
  1465. X            goto bad;
  1466. X    }
  1467. X    if(p!=line)
  1468. X        goto bad;
  1469. X    close(fp);
  1470. X    readfile=0;
  1471. X    return;
  1472. X
  1473. Xbad:    close(fp);              /* come here if there is an error */
  1474. X    readfile=0;             /* that readfi() has detected */
  1475. X    error(23);              /* stops error() having to tidy up */
  1476. X}
  1477. X
  1478. X/*
  1479. X *      The 'new' command , This deletes any program and clears all
  1480. X *    variables , can take an extra parameter to say how many files are
  1481. X *    needed. If so then clears the number of buffers ( default 2 ).
  1482. X */
  1483. X
  1484. Xneww()
  1485. X{
  1486. X    register int    i,c;
  1487. X    register struct filebuf *p;
  1488. X    register memp   size;
  1489. X
  1490. X    c=getch();
  1491. X    point--;
  1492. X    if(!istermin(c)){
  1493. X        i=evalint();
  1494. X        check();
  1495. X        closeall();             /* flush the buffers */
  1496. X        if(i<0 || i> MAXFILES)
  1497. X            i=2;
  1498. X        fendcore= filestart + (sizeof(struct filebuf) * i );
  1499. X        size = fendcore + sizeof(xlinnumb);
  1500. X        size = (char *) ( ((int)size + MEMINC) & ~MEMINC);
  1501. X        brk(size);
  1502. X        for(p = (filebufp)filestart ; p < (filebufp)fendcore ; p++){
  1503. X            p->filedes=0;
  1504. X            p->userfiledes=0;
  1505. X            p->use=0;
  1506. X            p->nleft=0;
  1507. X        }
  1508. X    }
  1509. X    else
  1510. X        check();
  1511. X    autostart=10;
  1512. X    autoincr=10;
  1513. X    baseval=1;
  1514. X    ecore= fendcore + sizeof(xlinnumb);
  1515. X    ( (lpoint)fendcore )->linnumb=0;
  1516. X    clear(DEFAULTSTRING);
  1517. X    closeall();
  1518. X    reset();
  1519. X}
  1520. X
  1521. X/*
  1522. X *      The 'chain' command , This routine chains the program.
  1523. X *      all simple numeric variables are kept. ( max of 4 k ).
  1524. X *      all other variables are cleared.
  1525. X *      runs the loaded file
  1526. X *      files are kept open
  1527. X *
  1528. X *      error need only check pipe[0] to see if it is to be closed.
  1529. X */
  1530. X
  1531. Xchain()
  1532. X{
  1533. X    register int     fp;
  1534. X    register int     size;
  1535. X    register char    *p;
  1536. X    int     ssize,nsize;
  1537. X#ifdef  LNAMES
  1538. X    register struct  entry  *ep,*np;
  1539. X    register int    *xp;
  1540. X#endif
  1541. X
  1542. X    stringeval(gblock);
  1543. X    check();
  1544. X    gblock[gcursiz]=0;
  1545. X    size= vend- earray;
  1546. X#ifdef  LNAMES
  1547. X    nsize = enames - estring;               /* can only save offsets */
  1548. X    if(nsize + size >= 4096)                /* cos ecore/estring might */
  1549. X#else                                           /* change */
  1550. X    if(size >= 4096 )
  1551. X#endif
  1552. X        error(42);              /* out of space for varibles */
  1553. X    if((fp=open(gblock,0))== -1)
  1554. X        error(15);
  1555. X    ssize= estring- ecore;          /* amount of string space */
  1556. X    pipe(pipes);
  1557. X    write(pipes[1],earray,size);    /* check this */
  1558. X#ifdef  LNAMES
  1559. X    write(pipes[1],estring,nsize);
  1560. X#endif
  1561. X    close(pipes[1]);
  1562. X    pipes[1]=0;
  1563. X    ecore= fendcore + sizeof(xlinnumb);     /* bye bye old file */
  1564. X    ( (lpoint)fendcore )->linnumb=0; /* commited to new file now */
  1565. X    readfi(fp);
  1566. X    clear(ssize);
  1567. X    errortrap=0;
  1568. X    inserted=0;                     /* say we don't actually want to */
  1569. X    p= xpand(&vend,size);           /* clear variables on return */
  1570. X    read(pipes[0],p,size);
  1571. X#ifdef  LNAMES
  1572. X    p = xpand(&enames,nsize);
  1573. X    read(pipes[0],p,nsize);
  1574. X    /*
  1575. X     * now rehash the symbol table
  1576. X     * cos it gets munged when it moves
  1577. X     */
  1578. X    for(ep = (struct entry *)estring; ep < (struct entry *)enames; ep++){
  1579. X        ep->link = 0;
  1580. X        for(p = ep->_name,size = 0; *p ; size += *p++);
  1581. X        ep->ln_hash = size;
  1582. X        if(np = hshtab[size %= HSHTABSIZ]){
  1583. X            for(;np->link ;np = np->link);
  1584. X            np->link = ep;
  1585. X        }
  1586. X        else
  1587. X            hshtab[size] = ep;
  1588. X    }
  1589. X    /*
  1590. X     * must zap varshash - because of above
  1591. X     */
  1592. X    for( xp = varshash ; xp < &varshash[HSHTABSIZ] ; *xp++ = -1);
  1593. X    chained = 1;
  1594. X#endif
  1595. X    close(pipes[0]);                /* now have data back from pipe */
  1596. X    pipes[0]=0;
  1597. X    stocurlin= (lpoint)fendcore;
  1598. X    if(!(curline=stocurlin->linnumb))
  1599. X        reset();
  1600. X    point= stocurlin->lin;
  1601. X    elsecount=0;
  1602. X    runmode=1;
  1603. X    return(-1);                     /* now run the file */
  1604. X}
  1605. X
  1606. X/* define a function def fna() - can have up to 3 parameters */
  1607. X
  1608. Xdeffunc()
  1609. X{
  1610. X    struct  deffn   fn;     /* temporary place for evaluation */
  1611. X    register struct deffn *p;
  1612. X    register int     i=0;
  1613. X    int     c;
  1614. X    char    *j;
  1615. X    register char   *l;
  1616. X
  1617. X    if(getch() != FN)
  1618. X        error(SYNTAX);
  1619. X    if(!isletter(*point))
  1620. X        error(SYNTAX);
  1621. X    getnm();
  1622. X    if(vartype == 02)
  1623. X        error(VARREQD);
  1624. X    fn.dnm = nm;
  1625. X#ifdef  LNAMES
  1626. X    for(p = (deffnp)enames ; p < (deffnp)edefns ;
  1627. X#else
  1628. X    for(p = (deffnp)estring ; p < (deffnp)edefns ;
  1629. X#endif
  1630. X                    p = (deffnp)( (memp)p + p->offs) )
  1631. X        if(p->dnm == nm )
  1632. X            error(REDEFFN); /* redefined functions */
  1633. X    fn.vtys=vartype<<4;     /* save return type of function */
  1634. X    if(*point=='('){        /* get arguments */
  1635. X        point++;
  1636. X        for(;i<3;i++){
  1637. X            l=getname();
  1638. X            if( l < earray)
  1639. X                error(VARREQD);
  1640. X            fn.vargs[i]= l - earray;
  1641. X            fn.vtys |= vartype <<i;  /* save type of arguments */
  1642. X            if((c=getch())!=',')
  1643. X                break;
  1644. X        }
  1645. X        if(c!= ')')
  1646. X            error(SYNTAX);
  1647. X        i++;
  1648. X    }
  1649. X    if(getch()!='=')
  1650. X        error(SYNTAX);
  1651. X    fn.narg=i;
  1652. X    l = point;
  1653. X    while(*l++ == ' ');
  1654. X    point = --l;
  1655. X    while(!istermin(*l))    /* get rest of expression */
  1656. X        l++;
  1657. X    if(l==point)
  1658. X        error(SYNTAX);
  1659. X    i= l - point + sizeof(struct deffn);
  1660. X#ifdef  ALIGN4
  1661. X    i = (i + 03) & ~03;
  1662. X#else
  1663. X    if(i&01)                /* even up space requirement */
  1664. X        i++;
  1665. X#endif
  1666. X    p= (deffnp) xpand(&edefns,i );          /* get the space */
  1667. X#ifndef V6C
  1668. X    *p = fn;
  1669. X    p->offs = i;
  1670. X#else
  1671. X    p->dnm = fn.dnm;                    /* put all values in */
  1672. X    p->offs=i;
  1673. X    p->narg=fn.narg;
  1674. X    p->vtys= fn.vtys;
  1675. X    p->vargs[0]=fn.vargs[0];
  1676. X    p->vargs[1]=fn.vargs[1];
  1677. X    p->vargs[2]=fn.vargs[2];
  1678. X#endif
  1679. X    j= p->exp;
  1680. X    while( point<l)         /* store away line */
  1681. X        *j++ = *point++;
  1682. X    *j=0;
  1683. X    normret;
  1684. X}
  1685. X
  1686. X/* the repeat part of the repeat - until loop */
  1687. X/* now can have a construct like  'repeat until eof(1)'. */
  1688. X/* It might be of use ?? it's a special case */
  1689. X
  1690. X
  1691. Xrept()
  1692. X{
  1693. X    register struct forst   *p;
  1694. X    register int    c;
  1695. X    register char   *tp;
  1696. X
  1697. X    if(getch() == UNTIL){
  1698. X        tp = point;     /* save point */
  1699. X        eval();         /* calculate the value */
  1700. X        check();        /* check syntax */
  1701. X#ifdef  PORTABLE
  1702. X        while((vartype ? (!res.i) :(res.f == 0)) && !trapped){
  1703. X#else
  1704. X        while(!res.i && !trapped){ /* now repeat the loop until <>0 */
  1705. X#endif
  1706. X            point = tp;
  1707. X            eval();
  1708. X        }
  1709. X        normret;
  1710. X    }
  1711. X    point--;
  1712. X    check();
  1713. X    p= (forstp)vvend;
  1714. X    vvend += sizeof(struct forst);
  1715. X    mtest(vvend);
  1716. X    p->pt = point;
  1717. X    p->stolin = stocurlin;
  1718. X    p->elses = elsecount;
  1719. X    p->fr = 0;              /* make it look like a gosub like */
  1720. X    p->fnnm = (char *)01;   /* distinguish from gosub's */
  1721. X    normret;
  1722. X}
  1723. X
  1724. X/* the until bit of the command */
  1725. X
  1726. Xuntilf()
  1727. X{
  1728. X    register struct forst   *p;
  1729. X    eval();
  1730. X    check();
  1731. X    for(p= (forstp)vvend , p-- ; p >= (forstp)bstk ; p--)
  1732. X        if(!p->fr)
  1733. X            goto got;
  1734. X    error(48);
  1735. Xgot:
  1736. X    if(p->fnnm != (char *)01 )
  1737. X        error(51);
  1738. X#ifdef  PORTABLE
  1739. X    if(vartype ? (!res.i) : (res.f == 0)){
  1740. X#else
  1741. X    if(!res.i){             /* not true so repeat loop */
  1742. X#endif
  1743. X        elsecount = p->elses;
  1744. X        point = p->pt;
  1745. X        if(stocurlin = p->stolin)
  1746. X            curline = stocurlin->linnumb;
  1747. X        else runmode =0;
  1748. X        vvend = (memp)(p+1);    /* pop all off stack up until here */
  1749. X    }
  1750. X    else
  1751. X        vvend = (memp)p;        /* pop stack if finished here. */
  1752. X    normret;
  1753. X}
  1754. X
  1755. X/* while part of while - wend construct. This is like repeat until unless
  1756. X * loop fails on the first time. (Yeuch - next we need syntax checking on
  1757. X * input ).
  1758. X */
  1759. X
  1760. Xwhilef()
  1761. X{
  1762. X    register char    *spoint = point;
  1763. X    register lpoint lp;
  1764. X    register struct forst   *p;
  1765. X    lpoint  get_end();
  1766. X    eval();
  1767. X    check();
  1768. X#ifdef  PORTABLE
  1769. X    if(vartype ? res.i : res.f){
  1770. X#else
  1771. X    if(res.i){  /* got to go through it once so make it look like a */
  1772. X            /* repeat - until */
  1773. X#endif
  1774. X        p= (forstp)vvend;
  1775. X        vvend += sizeof(struct forst);
  1776. X        mtest(vvend);
  1777. X        p->pt = spoint;
  1778. X        p->stolin = stocurlin;
  1779. X        p->elses = elsecount;
  1780. X        p->fr = 0;              /* make it look like a gosub like */
  1781. X        p->fnnm = (char *)02;   /* distinguish from gosub's */
  1782. X        normret;
  1783. X    }
  1784. X    lp=get_end();                   /* otherwise find a wend */
  1785. X    check();
  1786. X    if(runmode){
  1787. X        stocurlin =lp;
  1788. X        curline = lp->linnumb;
  1789. X    }
  1790. X    normret;
  1791. X}
  1792. X
  1793. X/* the end part of a while loop - wend */
  1794. X
  1795. Xwendf()
  1796. X{
  1797. X    register struct forst   *p;
  1798. X    char    *spoint =point;
  1799. X    check();
  1800. X    for(p= (forstp)vvend , p-- ; p >= (forstp)bstk ; p--)
  1801. X        if(!p->fr)
  1802. X            goto got;
  1803. X    error(49);
  1804. Xgot:
  1805. X    if( p->fnnm != (char *)02 )
  1806. X        error(51);
  1807. X    point = p->pt;
  1808. X    eval();
  1809. X#ifdef  PORTABLE
  1810. X    if(vartype ? (!res.i) : (res.f == 0)){
  1811. X#else
  1812. X    if(!res.i){                     /* failure of the loop */
  1813. X#endif
  1814. X        vvend= (memp)p;
  1815. X        point = spoint;
  1816. X        normret;
  1817. X    }
  1818. X    vvend = (memp)(p+1);            /* pop stack after an iteration */
  1819. X    elsecount = p->elses;
  1820. X    if(stocurlin = p->stolin)
  1821. X        curline = stocurlin->linnumb;
  1822. X    else runmode=0;
  1823. X    normret;
  1824. X}
  1825. X
  1826. X/* get_end - search from current position until found a wend statement - of
  1827. X * the correct nesting. Keeping track of elses + if's(Yeuch ).
  1828. X */
  1829. X
  1830. Xlpoint
  1831. Xget_end()
  1832. X{
  1833. X    register lpoint lp;
  1834. X    register char   *p;
  1835. X    register int    c;
  1836. X    int     wcount=0;
  1837. X    int     rcount=0;
  1838. X    int     flag=0;
  1839. X
  1840. X    p= point;
  1841. X    lp= stocurlin;
  1842. X    if(getch()!=':'){
  1843. X        if(!runmode)
  1844. X            error(50);
  1845. X        lp = (lpoint)((memp)lp +lenv(lp));
  1846. X        if(!lp->linnumb)
  1847. X            error(50);
  1848. X        point = lp->lin;
  1849. X        elsecount=0;
  1850. X    }
  1851. X    for(;;){
  1852. X        c=getch();
  1853. X        if(c==WHILE)
  1854. X            wcount++;
  1855. X        else if(c==WEND){
  1856. X            if(--wcount <0)
  1857. X                break;  /* only get out point in loop */
  1858. X        }
  1859. X        else if(c==REPEAT)
  1860. X            rcount++;
  1861. X        else if(c==UNTIL){
  1862. X            if(--rcount<0)
  1863. X                error(51);      /* bad nesting */
  1864. X        }
  1865. X        else if(c==IF){
  1866. X            flag++;
  1867. X            elsecount++;
  1868. X        }
  1869. X        else if(c==ELSE){
  1870. X            flag++;
  1871. X            if(elsecount)
  1872. X                elsecount--;
  1873. X        }
  1874. X        else if(c==REM || c==DATA || c==QUOTE){
  1875. X            if(!runmode)
  1876. X                error(50);      /* no wend */
  1877. X            lp = (lpoint)((memp)lp +lenv(lp));
  1878. X            if(!lp->linnumb)
  1879. X                error(50);      /* no wend */
  1880. X            point =lp->lin;
  1881. X            elsecount=0;
  1882. X            flag=0;
  1883. X            continue;
  1884. X        }
  1885. X        else for(p=point;!istermin(*p);p++)
  1886. X            if(*p=='"' || *p=='`'){
  1887. X                c= *p++;
  1888. X                while(*p && *p != (char) c)
  1889. X                    p++;
  1890. X                if(!*p)
  1891. X                    break;
  1892. X            }
  1893. X        if(!*p++){
  1894. X            if(!runmode)
  1895. X                error(50);
  1896. X            lp = (lpoint)((memp)lp +lenv(lp));
  1897. X            if(!lp->linnumb)
  1898. X                error(50);
  1899. X            point =lp->lin;
  1900. X            elsecount=0;
  1901. X            flag=0;
  1902. X        }
  1903. X        else
  1904. X            point = p;
  1905. X    }
  1906. X    /* we have found it at this point - end of loop */
  1907. X    if(rcount || (lp!=stocurlin && flag) )
  1908. X        error(51);      /* bad nesting or wend after an if */
  1909. X    return(lp);             /* not on same line */
  1910. X}
  1911. X
  1912. X#ifdef  RENUMB
  1913. X
  1914. X/*
  1915. X * the renumber routine. It is a three pass algorithm.
  1916. X *      1) Find all line numbers that are in text.
  1917. X *         Save in table.
  1918. X *      2) Renumber all lines.
  1919. X *         Fill in table with lines that are found
  1920. X *      3) Find all line numbers and update to new values.
  1921. X *
  1922. X *      This routine eats stack space and also some code space
  1923. X *      If you don't want it don't define RENUMB.
  1924. X *      Could run out of stack if on V7 PDP-11's
  1925. X *      ( On vax's it does not matter. Also can increase MAXRLINES.)
  1926. X *      MAXRLINES can be reduced if not got split i-d. If this is
  1927. X *      the case then probarbly do not want this code anyway.
  1928. X */
  1929. X
  1930. X#define MAXRLINES       500     /* the maximum number of lines that */
  1931. X                /* can be changed. Change if neccasary */
  1932. X
  1933. Xrenumb()
  1934. X{
  1935. X    struct  ta {
  1936. X        unsigned linn;
  1937. X        unsigned toli;
  1938. X        } ta[MAXRLINES];
  1939. X
  1940. X    struct  ta      *eta = ta;
  1941. X    register struct ta *tp;
  1942. X    register char   *q;
  1943. X    register lpoint p;
  1944. X
  1945. X    unsigned l1,start,inc;
  1946. X    int     size,sl,pl;
  1947. X    char    onfl,chg,*r,*s;
  1948. X    long    numb;
  1949. X
  1950. X    start = 10;
  1951. X    inc = 10;
  1952. X    l1 = getlin();
  1953. X    if(l1 != (unsigned)(-1) ){              /* get start line number */
  1954. X        start = l1;
  1955. X        if(getch() != ',')
  1956. X            point--;
  1957. X        else {
  1958. X            l1 = getlin();          /* get increment */
  1959. X            if(l1 == (unsigned)(-1))
  1960. X                error(5);
  1961. X            inc = l1;
  1962. X        }
  1963. X    }
  1964. X    check();                /* check rest of line */
  1965. X    numb = start;           /* set start counter */
  1966. X    for(p=(lpoint)fendcore; p->linnumb ;p=(lpoint)((char *)p+lenv(p))){
  1967. X        numb += inc;
  1968. X        if(numb >= 65530 )      /* check line numbers */
  1969. X            error(7);       /* line number overflow */
  1970. X        onfl = 0;               /* flag to deal with on_goto */
  1971. X        for(q = p->lin; *q ; q++){      /* now find keywords */
  1972. X            if( !(*q & (char)0200 ))        /* not one */
  1973. X                continue;               /* ignore */
  1974. X            if(*q == (char) ON){            /* the on keyword */
  1975. X                onfl++;                 /* set flag */
  1976. X                continue;
  1977. X            }               /* check items with optional numbers*/
  1978. X            if(*q == (char)ELSE || *q == (char)THEN ||
  1979. X                *q == (char)RESUME || *q == (char)RESTORE
  1980. X                    || *q == (char) RUNN ){
  1981. X                q++;
  1982. X                while(*q++ == ' ');
  1983. X                q--;
  1984. X                if(isnumber(*q))        /* got one ok */
  1985. X                    goto ok1;
  1986. X            }
  1987. X            if(*q != (char) GOTO && *q != (char)GOSUB)
  1988. X                continue;       /* can't be anything else */
  1989. X            q++;
  1990. X        ok1:                            /* have a label */
  1991. X            do{
  1992. X                while(*q++ == ' ');
  1993. X                q--;                    /* look for number */
  1994. X                if( !isnumber(*q) ){
  1995. X                      prints("Line number required on line ");
  1996. X                    prints(printlin(p->linnumb));
  1997. X                    prints(nl);             /* missing */
  1998. X                    goto out1;
  1999. X                }
  2000. X                for(l1 = 0; isnumber(*q) ; q++) /* get it */
  2001. X                    if(l1 >= 6553)
  2002. X                        error(7);
  2003. X                    else l1 = l1 * 10 + *q - '0';
  2004. X                for(tp  = ta ; tp < eta ; tp++) /* already */
  2005. X                    if(tp->linn == l1)      /* got it ? */
  2006. X                        break;
  2007. X                if(tp >= eta ){        /* add another entry */
  2008. X                    tp->linn = l1;
  2009. X                    tp->toli = -1;
  2010. X                    if(++eta >= &ta[MAXRLINES])
  2011. X                        error(24);   /* out of core */
  2012. X                }
  2013. X                if(!onfl)               /* check flag */
  2014. X                    break;          /* get next item */
  2015. X                while(*q++== ' ');      /* if ON and comma */
  2016. X            }while( *(q-1) ==',');
  2017. X            if(onfl)
  2018. X                q--;
  2019. X            onfl =0;
  2020. X            q--;
  2021. X        }
  2022. X    out1:   ;
  2023. X    }
  2024. X    numb = start;           /* reset counter */
  2025. X    for(p= (lpoint)fendcore ; p->linnumb ;p=(lpoint)((char *)p+lenv(p)) ){
  2026. X        for(tp = ta ; tp < eta ; tp++)          /* change numbers */
  2027. X            if(tp->linn == p->linnumb){
  2028. X                tp->toli = numb;  /* inform of new number */
  2029. X                break;
  2030. X            }
  2031. X        p->linnumb = numb;
  2032. X        numb += inc;
  2033. X    }
  2034. X    for(p= (lpoint)fendcore ; p->linnumb ;p=(lpoint)((char *)p+lenv(p)) ){
  2035. X        onfl = 0;
  2036. X        chg = 0;                        /* set if line changed */
  2037. X        for(r = nline, q = p->lin ; *q ; *r++ = *q++){
  2038. X            if(  r >= &nline[MAXLIN])  /* overflow of line */
  2039. X                break;
  2040. X            if( !(*q & (char) 0200 )) /* repeat search for */
  2041. X                continue;         /* keywords */
  2042. X            if(*q == (char) ON){
  2043. X                onfl++;
  2044. X                continue;
  2045. X            }
  2046. X            if(*q == (char)ELSE || *q == (char)THEN ||
  2047. X                *q == (char)RESUME || *q == (char)RESTORE
  2048. X                    || *q == (char) RUNN ){
  2049. X                *r++ = *q++;
  2050. X                while(*q == ' ' && r < &nline[MAXLIN] )
  2051. X                    *r++ = *q++;
  2052. X                if(isnumber(*q)) /* got optional line number*/
  2053. X                    goto ok2;
  2054. X            }
  2055. X            if(*q != (char) GOTO && *q != (char)GOSUB)
  2056. X                continue;
  2057. X            *r++ = *q++;
  2058. X            for(;;){
  2059. X                while(*q == ' ' && r < &nline[MAXLIN] )
  2060. X                    *r++ = *q++;
  2061. X            ok2: ;
  2062. X                if(r>= &nline[MAXLIN] )
  2063. X                    break;
  2064. X                for(l1 = 0 ; isnumber(*q) ; q++) /* get numb*/
  2065. X                    l1 = l1 * 10 + *q - '0';
  2066. X                if(l1 == 0)         /* skip if not found */
  2067. X                    goto out;   /* never happen ?? */
  2068. X                for(tp = ta ; tp < eta ; tp++)
  2069. X                    if(tp->linn == l1)
  2070. X                        break;
  2071. X                if(tp->linn != tp->toli)
  2072. X                    chg++;       /* number has changed */
  2073. X                if(tp >= eta || tp->toli == (unsigned)(-1) ){
  2074. X                    prints("undefined line: ");
  2075. X                    prints(printlin(l1));
  2076. X                    prints(" on line ");
  2077. X                    prints(printlin(p->linnumb));
  2078. X                    prints(nl);     /* can't find it */
  2079. X                    goto out;
  2080. X                }
  2081. X                s = printlin(tp->toli); /* get new number */
  2082. X                while( *s && r < &nline[MAXLIN])
  2083. X                    *r++ = *s++;
  2084. X                if(r >= &nline[MAXLIN] )
  2085. X                    break;
  2086. X                if(onfl){       /* repeat if ON statement */
  2087. X                    while(*q == ' ' && r < &nline[MAXLIN])
  2088. X                        *r++ = *q++;
  2089. X                    if(*q == ','){
  2090. X                        *r++ = *q++;
  2091. X                        continue;
  2092. X                    }
  2093. X                }
  2094. X                break;
  2095. X            }
  2096. X            onfl = 0;
  2097. X            if(r >= &nline[MAXLIN])
  2098. X                error(32);      /* line length overflow */
  2099. X        }
  2100. X        if(!chg)                /* not changed so don't put back */
  2101. X            continue;
  2102. X        inserted =1;            /* say we have changed it */
  2103. X        for(*r = 0, r = nline; *r++ ;);
  2104. X        r--;
  2105. X        size = (r - nline) + sizeof(struct olin); /* get size */
  2106. X#ifdef  ALIGN4
  2107. X        size = (size + 03) & ~03;
  2108. X#else
  2109. X        if(size & 01)                   /* even it up */
  2110. X            size++;
  2111. X#endif
  2112. X        if(size != lenv(p) ){           /* size changed. insert */
  2113. X            pl = p->linnumb;        /* save line number */
  2114. X            sl = lenv(p);           /* save length */
  2115. X            bmov((short *)p,sl);    /* compress core */
  2116. X            ecore -= sl;            /* shrink it */
  2117. X            mtest(ecore+size);      /* get more core */
  2118. X            ecore += size;          /* add it */
  2119. X            bmovu((short *)p,size);   /* expand core */
  2120. X            p->linnumb = pl;        /* restore line number */
  2121. X            lenv(p) = size;         /* set size */
  2122. X        }
  2123. X        strcpy(nline,p->lin);   /* copy back new line */
  2124. X    out:    ;
  2125. X    }
  2126. X    reset();
  2127. X}
  2128. X#else
  2129. Xrenumb(){}
  2130. X#endif  /* RENUMB */
  2131. X
  2132. X/* the load command. Load a dump image. Works fastwer than save/old */
  2133. X
  2134. X#define MAGIC1          013121
  2135. X#define MAGIC2          027212
  2136. X
  2137. Xloadd()
  2138. X{
  2139. X    register int     nsize;
  2140. X    register fp;
  2141. X    int     header[3];
  2142. X
  2143. X    stringeval(gblock);
  2144. X    check();
  2145. X    gblock[gcursiz] = 0;
  2146. X    if( (fp = open(gblock,0))< 0)
  2147. X        error(14);
  2148. X    if(read(fp,(char *)header,sizeof(int)*3) != sizeof(int)*3){
  2149. X        close(fp);
  2150. X        error(23);      /* bad load / format file */
  2151. X    }
  2152. X    if(header[0] != MAGIC1 && header[1] != MAGIC2){
  2153. X        close(fp);
  2154. X        error(23);
  2155. X    }
  2156. X    ecore = fendcore + sizeof(xlinnumb);
  2157. X    mtest(ecore);           /* good bye old image */
  2158. X    ((lpoint)fendcore)->linnumb = 0;
  2159. X    inserted = 1;
  2160. X    readfile = fp;
  2161. X    mtest(ecore+header[2]);
  2162. X    readfile = 0;
  2163. X    ecore += header[2];
  2164. X    nsize = read(fp,fendcore,header[2]);
  2165. X    close(fp);
  2166. X    if(nsize != header[2]){
  2167. X        ecore = fendcore + sizeof(xlinnumb);
  2168. X        mtest(ecore);
  2169. X        ((lpoint)fendcore)->linnumb = 0;
  2170. X        error(23);
  2171. X    }
  2172. X    reset();
  2173. X}
  2174. X
  2175. X/* write out the core to the file */
  2176. X
  2177. Xdump()
  2178. X{
  2179. X    register int     nsize;
  2180. X    register fp;
  2181. X    int     header[3];
  2182. X
  2183. X    stringeval(gblock);
  2184. X    check();
  2185. X    gblock[gcursiz] = 0;
  2186. X    if( (fp = creat(gblock,0644))< 0)
  2187. X        error(15);
  2188. X    header[0] = MAGIC1;
  2189. X    header[1] = MAGIC2;
  2190. X    nsize = ecore - fendcore;
  2191. X    header[2] = nsize;
  2192. X    write(fp,(char *)header,sizeof(int)*3);
  2193. X    write(fp,fendcore,nsize);
  2194. X    close(fp);
  2195. X    normret;
  2196. X}
  2197. End of bas8.c
  2198. chmod u=rw-,g=r,o=r bas8.c
  2199. echo x - bas9.c 1>&2
  2200. sed 's/^X//' > bas9.c << 'End of bas9.c'
  2201. X/*
  2202. X * BASIC by Phil Cockcroft
  2203. X */
  2204. X#include        "bas.h"
  2205. X
  2206. X/*
  2207. X *      This file contains subroutines used by many commands
  2208. X */
  2209. X
  2210. X/*      stringcompare will compare two strings and return a valid
  2211. X *    logical value
  2212. X */
  2213. X
  2214. Xstringcompare()
  2215. X{
  2216. X    char    chblock[256];
  2217. X    register int    i;
  2218. X    register char   *p,*q;
  2219. X    int     cursiz;
  2220. X    int     reslt=0;
  2221. X    int     c;
  2222. X
  2223. X    checksp();
  2224. X    stringeval(chblock);
  2225. X    cursiz=gcursiz;
  2226. X    if(! (c=getch()) )
  2227. X        error(SYNTAX);
  2228. X    stringeval(gblock);
  2229. X    if(i = ((cursiz > gcursiz) ? gcursiz : cursiz) ){
  2230. X        /*
  2231. X         * make i the minimum of gcursiz and cursiz
  2232. X         */
  2233. X        gcursiz -= i; cursiz -= i;
  2234. X        p=chblock; q=gblock;    /* set pointers */
  2235. X        do{
  2236. X            if(*p++ != *q++){       /* do the compare */
  2237. X                if( (*(p-1) & 0377) > (*(q-1) & 0377) )
  2238. X                    reslt++;
  2239. X                else
  2240. X                    reslt--;
  2241. X                compare(c,reslt);
  2242. X                return;
  2243. X            }
  2244. X        }while(--i);
  2245. X    }
  2246. X    if(cursiz)
  2247. X        reslt++;
  2248. X    else if(gcursiz)
  2249. X        reslt--;
  2250. X    compare(c,reslt);
  2251. X}
  2252. X
  2253. X/*      given the comparison operator 'c' then returns a value
  2254. X *    given that 'reslt' has a value of:-
  2255. X *              0:      equal
  2256. X *              1:      greater than
  2257. X *             -1:      less than
  2258. X */
  2259. X
  2260. Xcompare(c,reslt)
  2261. Xregister int     c;
  2262. Xregister int    reslt;
  2263. X{
  2264. X    vartype=01;
  2265. X    if(c==EQL){
  2266. X        if(!reslt)
  2267. X            goto true;
  2268. X    }
  2269. X    else if(c==LTEQ){
  2270. X        if( reslt<=0)
  2271. X            goto true;
  2272. X    }
  2273. X    else if(c==NEQE){
  2274. X        if( reslt)
  2275. X            goto true;
  2276. X    }
  2277. X    else if(c==LTTH){
  2278. X        if( reslt<0)
  2279. X            goto true;
  2280. X    }
  2281. X    else if(c==GTEQ){
  2282. X        if( reslt>=0)
  2283. X            goto true;
  2284. X    }
  2285. X    else if(c==GRTH){
  2286. X        if( reslt>0)
  2287. X            goto true;
  2288. X    }
  2289. X    else
  2290. X        error(SYNTAX);
  2291. X    res.i=0;        /* false */
  2292. X    return;
  2293. Xtrue:
  2294. X    res.i = -1;
  2295. X}
  2296. X
  2297. X/*      converts a number in 'res' to a string in gblock
  2298. X *    the string will have a space at the start if it is positive
  2299. X */
  2300. X
  2301. Xgcvt()
  2302. X{
  2303. X    int     sign, decpt;
  2304. X    int     ndigit=9;
  2305. X    register char   *p1, *p2;
  2306. X    register int    i;
  2307. X#ifndef SOFTFP
  2308. X    char    *ecvt();
  2309. X#else
  2310. X    char    *necvt();
  2311. X#endif
  2312. X
  2313. X#ifdef  PORTABLE
  2314. X    if(vartype==01 || !res.f){
  2315. X#else
  2316. X    if(vartype==01 || !res.i){ /* integer deal with them separately */
  2317. X#endif
  2318. X        lgcvt();
  2319. X        return;
  2320. X    }
  2321. X#ifndef SOFTFP
  2322. X    p1 = ecvt(res.f, ndigit+2, &decpt, &sign);
  2323. X#else
  2324. X    p1 = necvt(&res, ndigit+2, &decpt, &sign);
  2325. X#endif
  2326. X    if (sign)
  2327. X        *gblock = '-';
  2328. X    else
  2329. X        *gblock = ' ';
  2330. X    if(ndigit > 1){
  2331. X        p2 = p1 + ndigit-1;
  2332. X        do {
  2333. X            if(*p2 != '0')
  2334. X                break;
  2335. X            ndigit--;
  2336. X        }while(--p2 > p1);
  2337. X    }
  2338. X    p2 = &gblock[1];
  2339. X/*
  2340. X    for (i=ndigit-1; i>0 && *(p1+i) =='0'; i--)
  2341. X        ndigit--;
  2342. X*/
  2343. X    if (decpt < 0 || decpt > 9){
  2344. X        decpt--;
  2345. X        *p2++ = *p1++;
  2346. X        if(ndigit != 1){
  2347. X            *p2++ = '.';
  2348. X            for (i=1; i<ndigit; i++)
  2349. X                *p2++ = *p1++;
  2350. X        }
  2351. X        *p2++ = 'e';
  2352. X        if (decpt<0) {
  2353. X            decpt = -decpt;
  2354. X            *p2++ = '-';
  2355. X        }
  2356. X        if(decpt >= 10){
  2357. X            *p2++ = decpt/10 + '0';
  2358. X            decpt %= 10;
  2359. X        }
  2360. X        *p2++ = decpt + '0';
  2361. X    }
  2362. X    else {
  2363. X        if (!decpt) {
  2364. X            *p2++ = '0';
  2365. X            *p2++ = '.';
  2366. X        }
  2367. X        for (i=1; i<=ndigit; i++) {
  2368. X            *p2++ = *p1++;
  2369. X            if (i==decpt && i != ndigit)
  2370. X                *p2++ = '.';
  2371. X        }
  2372. X        while (ndigit++<decpt)
  2373. X            *p2++ = '0';
  2374. X    }
  2375. X    *p2 =0;
  2376. X    gcursiz= p2 -gblock;
  2377. X}
  2378. X
  2379. X/* integer version of above - a very simple algorithm */
  2380. X
  2381. Xlgcvt()
  2382. X{
  2383. X    static  char    s[7];
  2384. X    register char   *p,*q;
  2385. X    int     fl=0;
  2386. X    register unsigned l;
  2387. X
  2388. X    l=  res.i;
  2389. X    p= &s[6];
  2390. X    if((int)l <0){
  2391. X        fl++;
  2392. X        l= -l;
  2393. X    }
  2394. X    do{
  2395. X        *p-- = l%10 +'0';
  2396. X    }while(l/=10 );
  2397. X    if(fl)
  2398. X        *p ='-';
  2399. X    else
  2400. X        *p =' ';
  2401. X    q=gblock;
  2402. X    while(*q++ = *p++);
  2403. X    gcursiz= --q - gblock;
  2404. X}
  2405. X
  2406. X/*      get a linenumber or if no linenumber return a -1
  2407. X *    used by all routines with optional linenumbers
  2408. X */
  2409. X
  2410. Xgetlin()
  2411. X{
  2412. X    register unsigned l=0;
  2413. X    register int    c;
  2414. X
  2415. X    c=getch();
  2416. X    if(!isnumber(c)){
  2417. X        point--;
  2418. X        return(-1);
  2419. X    }
  2420. X    do{
  2421. X        if(l>=6553 )
  2422. X            error(7);
  2423. X        l= l*10 + (c-'0');
  2424. X        c= *point++;
  2425. X    }while(isnumber(c));
  2426. X    point--;
  2427. X    return(l);
  2428. X}
  2429. X
  2430. X/*      getline() gets a line number and returns a valid pointer
  2431. X *    to it, if there is no linenumber or the line is not there
  2432. X *    then there is an error. Used by 'goto' etc.
  2433. X */
  2434. X
  2435. Xlpoint
  2436. Xgetline()
  2437. X{
  2438. X    register unsigned l=0;
  2439. X    register lpoint p;
  2440. X    register int    c;
  2441. X
  2442. X    c=getch();
  2443. X    if(!isnumber(c))
  2444. X        error(5);
  2445. X    do{
  2446. X        if(l>=6553)
  2447. X            error(7);
  2448. X        l= l*10+(c-'0');
  2449. X        c= *point++;
  2450. X    }while(isnumber(c));
  2451. X    point--;
  2452. X    if(runmode && l >= curline)     /* speed it up a bit */
  2453. X        p = stocurlin;          /* no need to search the whole lot */
  2454. X    else
  2455. X        p = (lpoint)fendcore;
  2456. X    for(; p->linnumb ;p = (lpoint)((memp)p + lenv(p)))
  2457. X        if(p->linnumb == l)
  2458. X            return(p);
  2459. X    error(6);
  2460. X}
  2461. X
  2462. X/*      printlin() returns a pointer to a string representing the
  2463. X *    the numeric value of the linenumber.  linenumbers are unsigned
  2464. X *    quantities.
  2465. X */
  2466. X
  2467. Xchar    *
  2468. Xprintlin(l)
  2469. Xregister unsigned l;
  2470. X{
  2471. X    static char   ln[7];
  2472. X    register char   *p;
  2473. X
  2474. X    p = &ln[5];
  2475. X    do{
  2476. X        *p-- = l %10 + '0';
  2477. X    }while(l/=10);
  2478. X    p++;
  2479. X    return(p);
  2480. X}
  2481. X
  2482. X/*      routine used to check the type of expression being evaluated
  2483. X *    used by print and eval.
  2484. X *      A string expression returns a value of '1'
  2485. X *      A numeric expression returns a value of '0'
  2486. X */
  2487. X
  2488. Xchecktype()
  2489. X{
  2490. X    register char   *tpoint;
  2491. X    register int    c;
  2492. X
  2493. X    if( (c= *point) & 0200){
  2494. X        if( (c&0377) >= MINFUNC)
  2495. X            goto data;
  2496. X        else  goto string;
  2497. X    }
  2498. X    if(isnumber(c) || c=='.' || c== '-' || c=='(')
  2499. X        goto data;
  2500. X    if(c=='"' || c=='`')
  2501. X        goto string;
  2502. X    if(!isletter(c))
  2503. X        error(SYNTAX);
  2504. X    tpoint= point;
  2505. X    do{
  2506. X        c= *++tpoint;
  2507. X    }while(isletter(c) || isnumber(c));
  2508. X    if(c!='$')
  2509. Xdata:           return(0);
  2510. Xstring: return(1);
  2511. X}
  2512. X
  2513. X/*      print out a message , used for all types of 'basic' messages
  2514. X */
  2515. X
  2516. Xprints(s)
  2517. Xchar    *s;
  2518. X{
  2519. X    register char   *i;
  2520. X
  2521. X    i=s;
  2522. X    while(*i++);
  2523. X    write(1,s,--i-s);
  2524. X}
  2525. X
  2526. X/*      copy a string from a to b returning the last address used in b
  2527. X */
  2528. X
  2529. Xchar    *
  2530. Xstrcpy(a,b)
  2531. Xregister char   *a,*b;
  2532. X{
  2533. X    while(*b++ = *a++);
  2534. X    return(--b);
  2535. X}
  2536. X
  2537. X
  2538. X#ifndef SOFTFP
  2539. X
  2540. X/* convert an ascii string into a number. If it is possibly an integer
  2541. X * return an integer.
  2542. X * Otherwise return a double ( in res )
  2543. X * should never overflow. One day I may fix the non floating point one.
  2544. X */
  2545. X
  2546. X
  2547. X#define BIG     1.701411835e37
  2548. X
  2549. Xgetop()
  2550. X{
  2551. X    register double x = 0;
  2552. X    register int    exponent = 0;
  2553. X    register int    ndigits = 0;
  2554. X    register int    c;
  2555. X    register int    exp;
  2556. X    char    decp = 0;
  2557. X    char    lzeros = 0;
  2558. X    int     minus;
  2559. X    short   xx;
  2560. X
  2561. Xdot:    for(c = *point ; isnumber(c) ; c = *++point){
  2562. X        if(!lzeros){
  2563. X            if(c == '0'){ /* ignore leading zeros */
  2564. X                if(decp)
  2565. X                    exponent--;
  2566. X                continue;
  2567. X            }
  2568. X            lzeros++;
  2569. X        }
  2570. X        if(ndigits >= 15){      /* ignore insignificant digits */
  2571. X            if(!decp)
  2572. X                exponent++;
  2573. X            continue;
  2574. X        }
  2575. X        if(decp)
  2576. X            exponent--;
  2577. X        ndigits++;
  2578. X        x = x * 10 + c - '0';
  2579. X    }
  2580. X    if(c == '.'){
  2581. X        point++;
  2582. X        if(decp)
  2583. X            return(0);
  2584. X        decp++;
  2585. X        goto dot;
  2586. X    }
  2587. X    if(c == 'e' || c == 'E'){
  2588. X        minus = 0;
  2589. X        if( (c = *++point) == '+')
  2590. X            point++;
  2591. X        else if(c =='-'){
  2592. X            minus++;
  2593. X            point++;
  2594. X        }
  2595. X        else if(c < '0' || c > '9')
  2596. X            return(0);
  2597. X        for(exp = 0, c = *point; c >= '0' && c <= '9' ; c = *++point){
  2598. X            if(exp < 1000)
  2599. X                exp = exp * 10 + c - '0';
  2600. X        }
  2601. X        if(minus)
  2602. X            exponent -= exp;
  2603. X        else
  2604. X            exponent += exp;
  2605. X    }
  2606. X    while(exponent < 0){
  2607. X        exponent++;
  2608. X        x /= 10;
  2609. X    }
  2610. X    while(exponent > 0){
  2611. X        exponent--;
  2612. X        if(x > BIG)
  2613. X            return(0);
  2614. X        x *= 10;
  2615. X    }
  2616. X    xx = x;                 /* see if x is == an integer */
  2617. X    /*
  2618. X     * shouldn't need a cast below but there is a bug in the 68000
  2619. X     * compiler which does the comparison wrong without it.
  2620. X     */
  2621. X    if( (double) xx == x){
  2622. X        vartype= 01;
  2623. X        res.i = xx;
  2624. X    } else {
  2625. X        vartype = 0;
  2626. X        res.f = x;
  2627. X    }
  2628. X    return(1);
  2629. X}
  2630. X#endif
  2631. End of bas9.c
  2632. chmod u=rw-,g=r,o=r bas9.c
  2633. echo x - gen 1>&2
  2634. sed 's/^X//' > gen << 'End of gen'
  2635. Xcase $1 in
  2636. X    vax)
  2637. X        make -f vax/Makefile ;;
  2638. X    pdp11)
  2639. X        echo "Please specify pdp11fp or pdp11nofp" ;;
  2640. X
  2641. X    pdp11fp)
  2642. X        make -f pdp11/Makefile.fp ;;
  2643. X
  2644. X    pdp11nofp)
  2645. X        make -f pdp11/Makefile.nofp ;;
  2646. X
  2647. X    m68000)
  2648. X        make -f m68000/Makefile ;;
  2649. X
  2650. X    pyramid)
  2651. X        make -f pyramid/Makefile ;;
  2652. X
  2653. X    clean)
  2654. X        rm -f *.o cursor.c term.c core basic ;;
  2655. X
  2656. X    *)
  2657. X      echo "please specify one of vax pdp11fp pdp11nofp m68000 pyramid" ;;
  2658. Xesac
  2659. End of gen
  2660. chmod u=rwx,g=xr,o=xr gen
  2661.  
  2662.