home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume7 / basic / part02 < prev    next >
Encoding:
Internet Message Format  |  1986-12-03  |  54.6 KB

  1. Subject:  v07i074:  A BASIC Interpreter, Part02/06
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: phil@Cs.Ucl.AC.UK
  6. Mod.sources: Volume 7, Issue 74
  7. Archive-name: basic/Part02
  8.  
  9. # Shar file shar02 (of 6)
  10. #
  11. # This is a shell archive containing the following files :-
  12. #    bas2.c
  13. #    bas3.c
  14. #    bas4.c
  15. #    bas5.c
  16. #    bas6.c
  17. # ------------------------------
  18. # This is a shell archive, shar, format file.
  19. # To unarchive, feed this text into /bin/sh in the directory
  20. # you wish the files to be in.
  21.  
  22. echo x - bas2.c 1>&2
  23. sed 's/^X//' > bas2.c << 'End of bas2.c'
  24. X/*
  25. X * BASIC by Phil Cockcroft
  26. X */
  27. X#include        "bas.h"
  28. X
  29. X/*
  30. X *  This file contains the routines to get a variable from its name
  31. X *  To dimension arrays and assignment to a variable.
  32. X *
  33. X *      A variable name consists of a letter followed by an optional
  34. X *    letter or digit followed by the type specifier.
  35. X *      A type specifier is a '%' for an integer a '$' for a string
  36. X *    or is absent if the variable is a real ( Default ).
  37. X *      An integer variable also has the top bit of its second letter
  38. X *    set this is used to distinguish between real and integer variables.
  39. X *      A variable name can be optionally followed by a subscript
  40. X *    turning the variable into a subscripted variable.
  41. X *    A subscript is specified by a list of indexes in square brackets
  42. X *    e.g.  [1,2,3] , a maximum of three subscripts may be used.
  43. X *    All arrays must be specified before use.
  44. X *
  45. X *      The variable to be accessed has its name in the array nm[],
  46. X *    and its type in the variable 'vartype'.
  47. X *
  48. X *      'vartype' is very important as it is used all over the place
  49. X *
  50. X *      The value in 'vartype' can have the following values:-
  51. X *              0:      real variable (Default ).
  52. X *              1:      integer variable.
  53. X *              2:      string variable.
  54. X *
  55. X */
  56. X
  57. X#ifdef  V6
  58. X#define LBRACK  '['
  59. X#define RBRACK  ']'
  60. X#else
  61. X#define LBRACK  '('
  62. X#define RBRACK  ')'
  63. X#endif
  64. X
  65. X/*
  66. X * getnm will return with nm[] and vartype set appropriately but without
  67. X * any regard for subscript parameters. Called by dimensio() only.
  68. X */
  69. X
  70. Xgetnm()
  71. X{
  72. X#ifdef  LNAMES
  73. X    register char   *p,*q;
  74. X    register struct entry   *ep,*np;
  75. X    register int    c;
  76. X    register int    l;
  77. X    nam[0]=c=getch();
  78. X    if(!isletter(c))
  79. X        error(VARREQD);
  80. X    p = &nam[1];
  81. X    for(l =c,c = *point;isletter(c) || isnumber(c) ; c = *++point)
  82. X        if(p < &nam[MAXNAME-1] ){
  83. X            l +=c;
  84. X            *p++ = c;
  85. X        }
  86. X    *p = 0;
  87. X    for(np = 0,ep=hshtab[l%HSHTABSIZ]; ep ; np = ep,ep=ep->link)
  88. X        if(l == ep->ln_hash)
  89. X            for(p = ep->_name,q = nam ; *q == *p++ ; )
  90. X                if(!*q++)
  91. X                    goto got;
  92. X    ep = (struct entry *)xpand(&enames,sizeof(struct entry));
  93. X    if(!np)
  94. X        hshtab[l%HSHTABSIZ] = ep;
  95. X    else
  96. X        np->link = ep;
  97. X    for(p = ep->_name , q = nam ; *p++ = *q++ ; );
  98. X    ep->ln_hash = l;
  99. Xgot:
  100. X    nm = (char *)ep - estring;
  101. X#else
  102. X    register int    c;
  103. X    nm=c=getch();
  104. X    if(!isletter(c))
  105. X        error(VARREQD);
  106. X    c= *point;
  107. X    if(isletter(c) ||isnumber(c)){
  108. X        nm |= c<<8;
  109. X        do
  110. X            c= *++point;
  111. X        while(isletter(c) || isnumber(c));
  112. X    }
  113. X#endif
  114. X    vartype=0;
  115. X    if(c=='$'){
  116. X        point++;
  117. X        vartype=02;
  118. X    }
  119. X    else if(c=='%'){
  120. X        point++;
  121. X        vartype++;
  122. X        nm |=0200<<8;
  123. X    }
  124. X}
  125. X
  126. X/*
  127. X *      getname() will return a pointer to a variable with vartype
  128. X *    set to the correct type. If the variable is subscripted getarray
  129. X *    is called and the subscripts are evaluated and depending upon
  130. X *    the type of variable the index into that array is returned.
  131. X *      Any simple variable that is not already declared is defined
  132. X *    and has a value of 0 or null (for strings) assigned to it.
  133. X *      In all instances a valid pointer is returned.
  134. X */
  135. Xmemp getname()
  136. X{
  137. X    memp    getstring();
  138. X#ifdef  LNAMES
  139. X    register char   *p,*q;
  140. X    register struct entry   *ep;
  141. X    register int    c;
  142. X    register struct vardata *pt;
  143. X    struct  entry   *np;
  144. X    register int    l;
  145. X    nam[0]=c=getch();
  146. X    if(!isletter(c))
  147. X        error(VARREQD);
  148. X    p = &nam[1];
  149. X    for(l =c,c = *point;isletter(c) || isnumber(c) ; c = *++point)
  150. X        if(p < &nam[MAXNAME-1] ){
  151. X            l +=c;
  152. X            *p++ = c;
  153. X        }
  154. X    *p = 0;
  155. X    for(np = 0,ep=hshtab[l%HSHTABSIZ]; ep ; np = ep,ep=ep->link)
  156. X        if(l == ep->ln_hash)
  157. X            for(p = ep->_name,q = nam ; *q == *p++ ; )
  158. X                if(!*q++)
  159. X                    goto got;
  160. X    ep = (struct entry *)xpand(&enames,sizeof(struct entry));
  161. X    if(!np)
  162. X        hshtab[l%HSHTABSIZ] = ep;
  163. X    else
  164. X        np->link = ep;
  165. X    for(p = ep->_name ,q = nam ; *p++ = *q++ ; );
  166. X    ep->ln_hash = l;
  167. Xgot:
  168. X    nm = (char *)ep - estring;
  169. X#else
  170. X    register int    c;
  171. X    register struct vardata *pt;
  172. X
  173. X    nm=c=getch();
  174. X    if(!isletter(c))
  175. X        error(VARREQD);
  176. X    c= *point;
  177. X    if(isletter(c) ||isnumber(c)){
  178. X        nm |=c<<8;
  179. X        do{ c= *++point; }while(isletter(c) || isnumber(c));
  180. X    }
  181. X#endif
  182. X    vartype=0;
  183. X    if(c=='$'){
  184. X        vartype=02;
  185. X        if(*++point==LBRACK)
  186. X            getarray();
  187. X        return(getstring());
  188. X    }
  189. X    else if(c=='%'){
  190. X        point++;
  191. X        vartype++;
  192. X        nm |= 0200<<8;
  193. X    }
  194. X    if(*point==LBRACK)
  195. X        return( (memp) getarray());
  196. X#ifdef  LNAMES
  197. X    /*
  198. X     * now do hashing of the variables
  199. X     */
  200. X    if( (c = varshash[l % HSHTABSIZ]) >= 0){
  201. X        pt = (vardp)earray;
  202. X        for(pt += c; pt < (vardp) vend;pt++)
  203. X            if(pt->nam ==nm )
  204. X                return( (memp) &pt->dt);
  205. X        /*
  206. X         * not found ****
  207. X         */
  208. X    }
  209. X    /*
  210. X     * really look for it - will force varshash to be the lowest
  211. X     * value. The hassle of chaining.
  212. X     */
  213. X    if(chained)
  214. X        for(pt = (vardp)earray; pt < (vardp) vend;pt++)
  215. X            if(pt->nam ==nm ){
  216. X                varshash[l % HSHTABSIZ] = pt - (vardp)earray;
  217. X                return((memp) &pt->dt);
  218. X            }
  219. X        /*
  220. X         * not found ****
  221. X         */
  222. X    pt= (vardp) xpand(&vend,sizeof(struct vardata));
  223. X    if(c < 0)
  224. X        varshash[l % HSHTABSIZ] = pt - (vardp)earray;
  225. X#else
  226. X    for(pt = (vardp)earray;  pt < (vardp) vend;pt++)
  227. X        if(pt->nam ==nm )
  228. X            return( (memp) &pt->dt);
  229. X    pt= (vardp) xpand(&vend,sizeof(struct vardata));
  230. X#endif
  231. X    pt->nam=nm;
  232. X    return( (memp) &pt->dt);
  233. X}
  234. X
  235. X/*
  236. X *      getstring() returns a pointer to a string structure if the string
  237. X *    is not declared then it is defined.
  238. X */
  239. X
  240. Xmemp
  241. Xgetstring()
  242. X{
  243. X    register struct stdata  *p;
  244. X    vartype=02;
  245. X    for(p= (stdatap)estdt ; p < (stdatap)estring ; p++)
  246. X        if(p->snam == nm )
  247. X            return( (memp) p);
  248. X    if( estdt - sizeof(struct stdata) < eostring){
  249. X        garbage();
  250. X        if(estdt - sizeof(struct stdata) <eostring)
  251. X            error(OUTOFSTRINGSPACE);
  252. X    }
  253. X    p = (stdatap)estdt;
  254. X    --p; estdt = (memp)p;
  255. X    p->snam = nm;
  256. X    p->stpt=0;
  257. X    return( (memp) p);
  258. X}
  259. X
  260. X/*
  261. X *      getarray() evaluates the subscripts of an array and the tries
  262. X *    to access it. getarray() returns different things dependent
  263. X *    on the type of variable. For an integer or real then the pointer to
  264. X *    the element of the array is returned.
  265. X *      For a string array element then the nm[] array is filled out
  266. X *    with a unique number and then getstring() is called to access it.
  267. X *      The variable hash (in the strarr structure ) is used as the
  268. X *    offset to the next array if the array is real or integer, but
  269. X *    is the base for the unique number to access the string structure.
  270. X *
  271. X *      This is a piece of 'hairy' codeing.
  272. X */
  273. X
  274. Xgetarray()
  275. X{
  276. X    register struct strarr  *p;
  277. X    register int     l;
  278. X    short   *m;
  279. X    int     c;
  280. X    int     i=1;
  281. X    register int     j=0;
  282. X    char    vty;
  283. X#ifdef  LNAMES
  284. X    memp    savee;
  285. X#endif
  286. X
  287. X    point++;
  288. X    vty=vartype;
  289. X    if(vty==02){
  290. X        for(p= (strarrp) edefns ; p < (strarrp) estarr ; p++)
  291. X            if(p->snm ==nm )
  292. X                goto got;
  293. X    }
  294. X    else {
  295. X        for( p = (strarrp) estarr ; p < (strarrp)earray ;
  296. X                    p = (strarrp)((memp)p + p->hash) )
  297. X            if(p->snm ==nm )
  298. X                goto got;
  299. X    }
  300. X    error(19);
  301. Xgot:    m = p->dim;
  302. X    i=1;
  303. X    do{
  304. X#ifdef  LNAMES
  305. X        savee = edefns;
  306. X#endif
  307. X        l=evalint()-baseval;
  308. X#ifdef  LNAMES
  309. X        p = (strarrp)((memp)p + (edefns - savee));
  310. X#endif
  311. X        if(l >= *m || l <0)
  312. X            error(17);
  313. X        j= l + j * *m;
  314. X        if((c=getch())!=',')
  315. X            break;
  316. X        m++,i++;
  317. X    } while(i <= p->dimens);
  318. X    if(i!=p->dimens || c!=RBRACK)
  319. X        error(16);
  320. X    vartype=vty;
  321. X    if(vty==02){
  322. X        j += p->hash;
  323. X        j |= 0100000;
  324. X        nm = j;
  325. X    }
  326. X    else {
  327. X        j <<= (vty ? 1 : 3 );
  328. X        p++;
  329. X        return( (int) ((char *)p+j) );
  330. X    }
  331. X}
  332. X
  333. X/*
  334. X *      dimensio() executes the dim command. It sets up the strarr structure
  335. X *    as needed. If the array is a string array then only the structure
  336. X *    is filled in. This means that elements of a string array do not have
  337. X *    storage allocated until assigned to. If the array is real or integer
  338. X *    then the array is allocated space as well as the strarr array.
  339. X *      This is why the hash element is needed so as to be able to access
  340. X *    the next array.
  341. X */
  342. X
  343. X
  344. Xdimensio()
  345. X{
  346. X    int     dims[3];
  347. X    int     nmm;
  348. X    long    j;
  349. X    int     c;
  350. X    char    vty;
  351. X    register int     i;
  352. X    register int    *r;
  353. X    register struct strarr *p;
  354. Xfor(;;){
  355. X    r=dims;
  356. X    i=0;
  357. X    j=1;
  358. X    getnm();
  359. X    nmm = nm;
  360. X    vty=vartype;            /* save copy of type of array */
  361. X    if(*point++!=LBRACK)
  362. X        error(SYNTAX);
  363. X    do{
  364. X        *r=evalint() + 1 - baseval;
  365. X#ifndef pdp11
  366. X        if( (j *= *r) <= 0 || j > 32767)
  367. X#else
  368. X        if( (j=dimmul( (int)j , *r)) <= 0)
  369. X#endif
  370. X            error(17);
  371. X        if((c=getch())!=',')
  372. X            break;
  373. X        r++;i++;
  374. X    }while(i<3);
  375. X    if(i ==3 || c!=RBRACK)
  376. X        error(16);
  377. X    i++;
  378. X    if(vty== 02){
  379. X        for(p= (strarrp) edefns ;p < (strarrp) estarr;p++)
  380. X            if(p->snm == nmm )
  381. X                error(20);
  382. X        if(j+shash > 32767)
  383. X            error(17);
  384. X        p = (strarrp) xpand(&estarr,sizeof(struct strarr));
  385. X        p->hash= shash;
  386. X        shash+=j;
  387. X    }
  388. X    else   {
  389. X        for(p = (strarrp)estarr ; p < (strarrp)earray ;
  390. X                    p = (strarrp)((memp)p + p->hash) )
  391. X            if(p->snm == nmm )
  392. X                error(20);
  393. X        j<<= (vty ? 1 : 3);
  394. X        j += sizeof(struct strarr);
  395. X#ifdef  ALIGN4
  396. X        j = (j + 3) & ~03;
  397. X#endif
  398. X        if(nospace(j))
  399. X            error(17);
  400. X        p = (strarrp) xpand(&earray,(int)j);
  401. X        p->hash = j;    /* offset to next array */
  402. X    }
  403. X    p->snm = nmm;       /* fill in common stuff */
  404. X    p->dimens=i;
  405. X    p->dim[0]=dims[0];
  406. X    p->dim[1]=dims[1];
  407. X    p->dim[2]=dims[2];
  408. X    if(getch()!=',')        /* any more arrays */
  409. X        break;
  410. X    }
  411. X    point--;
  412. X    normret;
  413. X}
  414. X
  415. X/*
  416. X *      Assign() is called if there is no keyword at the start of a
  417. X *    statement ( Default assignment statement ) and by let.
  418. X *    it just calls the relevent evaluation routine and leaves all the
  419. X *    hard work to stringassign() and putin() to actualy assign the variables.
  420. X */
  421. X
  422. Xassign()
  423. X{
  424. X    register memp   p;
  425. X    register char   vty;
  426. X    register int    c;
  427. X    int     i;
  428. X    value   t1;
  429. X    extern  int     (*mbin[])();
  430. X#ifdef  LNAMES
  431. X    memp    savee;
  432. X#endif
  433. X
  434. X    p= getname();
  435. X    vty=vartype;
  436. X    if(vty==02){
  437. X        if(getch()!='=')
  438. X            error(4);
  439. X        stringeval(gblock);
  440. X        stringassign( (stdatap)p );
  441. X        return;
  442. X    }
  443. X#ifdef  LNAMES
  444. X    savee = edefns;
  445. X#endif
  446. X    if((c = getch()) != '='){
  447. X        i = 6;
  448. X        switch(c){
  449. X        default:
  450. X            error(4);
  451. X        case '*':
  452. X        case '/':
  453. X            i += 2;
  454. X            break;
  455. X        case '+':
  456. X        case '-':
  457. X            break;
  458. X        }
  459. X        if(*point++ != '=')
  460. X            error(4);
  461. X#ifndef V6C
  462. X        t1 = *((value *)p);
  463. X#else
  464. X        movein(p,&t1);
  465. X#endif
  466. X        eval();
  467. X        if(vty != vartype){
  468. X            if(vty)
  469. X                cvt(&t1);
  470. X            else
  471. X                cvt(&res);
  472. X            vartype = 0;
  473. X        }
  474. X        (*mbin[i+vartype])(&t1,&res,c);
  475. X    }
  476. X    else
  477. X        eval();
  478. X#ifdef  LNAMES
  479. X    /*
  480. X     * cope with adding new names - pushes space up
  481. X     */
  482. X    p += edefns - savee;
  483. X#endif
  484. X    putin(p,vty);
  485. X}
  486. End of bas2.c
  487. chmod u=rw-,g=r,o=r bas2.c
  488. echo x - bas3.c 1>&2
  489. sed 's/^X//' > bas3.c << 'End of bas3.c'
  490. X/*
  491. X * BASIC by Phil Cockcroft
  492. X */
  493. X#include        "bas.h"
  494. X
  495. X/*
  496. X *      This file contains the numeric evaluation routines and some
  497. X *    of the numeric functions.
  498. X */
  499. X
  500. X/*
  501. X *      evalint() is called by a routine that requires an integer value
  502. X *    e.g. string functions. It will always return an integer. If
  503. X *    the result will not overflow an integer -1 is returned.
  504. X *      N.B. most ( all ) routines assume that a negative return is an
  505. X *    error.
  506. X */
  507. X
  508. X
  509. Xevalint()
  510. X{
  511. X    eval();
  512. X    if(vartype)
  513. X        return(res.i);
  514. X    if(conv(&res))
  515. X        return(-1);
  516. X    return(res.i);
  517. X}
  518. X
  519. X/*
  520. X *      This structure is only ever used by eval() and so is not declared
  521. X *    in 'bas.h' with the others.
  522. X */
  523. X
  524. X
  525. Xstruct  m {
  526. X    value   r1;
  527. X    int     lastop;
  528. X    char    value;
  529. X    char    vty;
  530. X    };
  531. X
  532. X/*
  533. X *      eval() will evaluate any numeric expression and return the result
  534. X *    in the UNION 'res'.
  535. X *      A valid expression can be any numeric expression or a string
  536. X *    comparison expression e.g. "as" <> "gh" . String expressions can
  537. X *    themselves be used in relational tests and also be used with the
  538. X *    logical operators. e.g. "a" <> "b" and "1" <> a$ is a valid
  539. X *    expression.
  540. X */
  541. X
  542. Xeval()
  543. X{
  544. X    extern   (*mbin[])();
  545. X    register int    i;
  546. X    register int    c;
  547. X    register struct    m    *j;
  548. X    value   *pp;
  549. X    char    firsttime=1;
  550. X    char    minus=0,noting=0;
  551. X    struct   m      restab[6];
  552. X
  553. X    checksp();
  554. X    j=restab;
  555. X    j->value=0;
  556. X
  557. Xfor(;;){
  558. X    c=getch();
  559. X    if(c=='-' && firsttime){
  560. X        if(minus)
  561. X            error(SYNTAX);
  562. X        minus++;
  563. X        continue;
  564. X    }
  565. X    else if(c==NOTT){
  566. X        if(noting)
  567. X            error(SYNTAX);
  568. X        noting++;
  569. X        firsttime++;
  570. X        continue;
  571. X    }
  572. X    else if(c&0200){
  573. X        if(c<MINFUNC || c>MAXFUNC)      /* we have a function */
  574. X            goto err1;      /* possibly a string function */
  575. X        if(c>= RND )                    /* functions that don't */
  576. X            (*functs[c-RND])();     /* require arguments */
  577. X        else  {
  578. X            if(*point++ !='(')
  579. X                error(SYNTAX);  /* functions that do */
  580. X            (*functb[c-MINFUNC])();
  581. X            if(getch()!=')')
  582. X                error(SYNTAX);
  583. X        }
  584. X    }
  585. X    else if(isletter(c)){
  586. X        char    *sp = --point;
  587. X
  588. X        pp= (value *)getname();         /* we have a variable */
  589. X        if(vartype== 02){       /* a string !!!!!! */
  590. X            if(firsttime){  /* no need for checktype() since */
  591. X                point = sp;     /* we know it's a string */
  592. X                stringcompare();
  593. X                goto ex;
  594. X            }
  595. X            else error(2);          /* variable required */
  596. X        }
  597. X#ifdef  V6C
  598. X        getv(pp);
  599. X#else
  600. X        res = *pp;
  601. X#endif
  602. X    }
  603. X    else if(isnumber(c) || c=='.'){
  604. X        point--;
  605. X        if(!getop())            /* we have a number */
  606. X            error(36);      /* bad number */
  607. X    }
  608. X    else if(c=='('){                /* bracketed expression */
  609. X        eval();                 /* recursive call of eval() */
  610. X        if(getch()!=')')
  611. X            error(SYNTAX);
  612. X    }
  613. X    else  {
  614. Xerr1:           /* get here if the function we tried to access was not   */
  615. X        /* a legal maths func. or a string variable */
  616. X        /* stringcompare() will give a syntax error if not a valid */
  617. X        /* string. therefore this works ok */
  618. X        point--;
  619. X        if(!firsttime)
  620. X            error(SYNTAX);
  621. X        stringcompare();
  622. X    }
  623. Xex:
  624. X    if(minus){                      /* do the unary minus */
  625. X        minus=0;
  626. X        negate();
  627. X    }
  628. X    if(noting){                     /* do the not */
  629. X        noting=0;
  630. X        notit();
  631. X    }
  632. X    i=0;
  633. X    switch(c=getch()){              /* get the precedence of the */
  634. X        case    '^':    i++;    /* operator */
  635. X        case    '*':
  636. X        case    '/':
  637. X        case    MODD:   i++;
  638. X        case    '+':
  639. X        case    '-':    i++;
  640. X        case    EQL:            /* comparison operators */
  641. X        case    LTEQ:
  642. X        case    NEQE:
  643. X        case    LTTH:
  644. X        case    GTEQ:
  645. X        case    GRTH:   i++;    /* logical operators */
  646. X        case    ANDD:
  647. X        case    ORR:
  648. X        case    XORR:   i++;
  649. X    }
  650. X    if(i>2)
  651. X        firsttime = 0;
  652. Xame:    if(j->value< (char)i){          /* current operator has higher */
  653. X        (++j)->lastop=c;                        /* precedence */
  654. X#ifndef V6C
  655. X        j->r1 = res;
  656. X#else
  657. X        push(&j->r1);  /* block moving */
  658. X#endif
  659. X        j->value=i;
  660. X        j->vty=vartype;
  661. X        continue;
  662. X    }
  663. X    if(! j->value ){                /* end of expression */
  664. X        point--;
  665. X        return;
  666. X    }
  667. X    if(j->vty!=vartype){            /* make both parameters */
  668. X        if(vartype)             /* the same type */
  669. X            cvt(&res);
  670. X        else
  671. X            cvt(&j->r1);    /* if changed then they must be */
  672. X        vartype=0;              /* changed to reals */
  673. X    }
  674. X    (*mbin[(j->value<<1)+vartype])(&j->r1,&res,j->lastop);
  675. X    j--;                    /* execute it then pop the stack and */
  676. X    goto ame;               /* deal with the next operator */
  677. X    }
  678. X}
  679. X
  680. X/*
  681. X *      The rest of the routines in this file evaluate functions and are
  682. X *    relatively straight forward.
  683. X */
  684. X
  685. Xtim()
  686. X{
  687. X    time(&overfl);
  688. X
  689. X#ifndef SOFTFP
  690. X    res.f = overfl;
  691. X    vartype = 0;
  692. X#else
  693. X    over(0,&res);           /* convert from long to real */
  694. X#endif
  695. X}
  696. X
  697. Xrnd()
  698. X{
  699. X    static  double  recip32 = 32767.0;
  700. X    value   temp;
  701. X    register int    rn;
  702. X
  703. X    rn = rand() & 077777;
  704. X    if(*point!='('){
  705. X        res.i=rn;
  706. X        vartype=01;
  707. X        return;
  708. X    }
  709. X    point++;
  710. X    eval();
  711. X    if(getch()!=')')
  712. X        error(SYNTAX);
  713. X#ifdef  PORTABLE
  714. X    if(vartype ? res.i : res.f){
  715. X#else
  716. X    if(res.i){
  717. X#endif
  718. X        if(!vartype && conv(&res))
  719. X            error(FUNCT);
  720. X        res.i= rn % res.i + 1;
  721. X        vartype=01;
  722. X        return;
  723. X    }
  724. X#ifndef SOFTFP
  725. X    res.f = (double)rn / recip32;
  726. X#else
  727. X    temp.i=rn;
  728. X    cvt(&temp);
  729. X#ifndef V6C
  730. X    res = *( (value *)( &recip32 ) );
  731. X#else
  732. X    movein(&recip32,&res);
  733. X#endif
  734. X    fdiv(&temp,&res);            /* horrible */
  735. X#endif
  736. X    vartype =0;
  737. X}
  738. X
  739. X/*
  740. X *      This routine is the command 'random' and is placed here for some
  741. X *    unknown reason it just sets the seed to rnd to the value from
  742. X *    the time system call ( is a random number ).
  743. X */
  744. X
  745. Xrandom()
  746. X{
  747. X    long    m;
  748. X    time(&m);
  749. X    srand((int)m);
  750. X    normret;
  751. X}
  752. X
  753. Xerlin()
  754. X{
  755. X    res.i = elinnumb;
  756. X    vartype=01;
  757. X    if(res.i < 0 ){                      /* make large linenumbers */
  758. X#ifndef SOFTFP
  759. X        res.f = (unsigned)elinnumb;
  760. X        vartype = 0;
  761. X#else
  762. X        overfl=(unsigned)elinnumb;      /* into reals as they */
  763. X        over(0,&res);                   /* overflow integers */
  764. X#endif
  765. X    }
  766. X}
  767. X
  768. Xerval()
  769. X{
  770. X    res.i =ecode;
  771. X    vartype=01;
  772. X}
  773. X
  774. Xsgn()
  775. X{
  776. X    eval();
  777. X#ifdef  PORTABLE
  778. X    if(!vartype){
  779. X        if(res.f < 0)
  780. X            res.i = -1;
  781. X        else if(res.f > 0)
  782. X            res.i = 1;
  783. X        else res.i = 0;
  784. X        vartype = 1;
  785. X        return;
  786. X    }
  787. X#endif
  788. X    if(res.i<0)             /* bit twiddling */
  789. X        res.i = -1;     /* real numbers have the top bit set if */
  790. X    else if(res.i>0)        /* negative and the top word is non-zero */
  791. X        res.i= 1;       /* for all non-zero numbers */
  792. X    vartype=01;
  793. X}
  794. X
  795. Xabs()
  796. X{
  797. X    eval();
  798. X#ifdef  PORTABLE
  799. X    if(!vartype){
  800. X        if(res.f < 0)
  801. X            negate();
  802. X        return;
  803. X    }
  804. X#endif
  805. X    if(res.i<0)
  806. X        negate();
  807. X}
  808. X
  809. Xlen()
  810. X{
  811. X    stringeval(gblock);
  812. X    res.i =gcursiz;
  813. X    vartype=01;
  814. X}
  815. X
  816. Xascval()
  817. X{
  818. X    stringeval(gblock);
  819. X    if(!gcursiz)
  820. X        error(FUNCT);
  821. X    res.i = *gblock & 0377;
  822. X    vartype=01;
  823. X}
  824. X
  825. Xsqrtf()
  826. X{
  827. X#ifndef SOFTFP
  828. X    double  sqrt();
  829. X#endif
  830. X    eval();
  831. X    if(vartype)
  832. X        cvt(&res);
  833. X    vartype=0;
  834. X#ifdef  PORTABLE
  835. X    if(res.f < 0)
  836. X#else
  837. X    if(res.i < 0)
  838. X#endif
  839. X        error(37);      /* negative square root */
  840. X#ifndef SOFTFP
  841. X    res.f = sqrt(res.f);
  842. X#else
  843. X    sqrt(&res);
  844. X#endif
  845. X}
  846. X
  847. Xlogf()
  848. X{
  849. X#ifndef SOFTFP
  850. X    double  log();
  851. X#endif
  852. X    eval();
  853. X    if(vartype)
  854. X        cvt(&res);
  855. X    vartype=0;
  856. X#ifdef  PORTABLE
  857. X    if(res.f <= 0)
  858. X#else
  859. X    if(res.i <= 0)
  860. X#endif
  861. X        error(38);      /* bad log value */
  862. X#ifndef SOFTFP
  863. X    res.f = log(res.f);
  864. X#else
  865. X    log(&res);
  866. X#endif
  867. X}
  868. X
  869. Xexpf()
  870. X{
  871. X#ifndef SOFTFP
  872. X    double  exp();
  873. X#endif
  874. X    eval();
  875. X    if(vartype)
  876. X        cvt(&res);
  877. X    vartype=0;
  878. X#ifndef SOFTFP
  879. X    if(res.f > 88.02969)
  880. X        error(39);
  881. X    res.f = exp(res.f);
  882. X#else
  883. X    if(!exp(&res))
  884. X        error(39);      /* overflow in exp */
  885. X#endif
  886. X}
  887. X
  888. Xpii()
  889. X{
  890. X#ifndef SOFTFP
  891. X    res.f = pivalue;
  892. X#else
  893. X    movein(&pivalue,&res);
  894. X#endif
  895. X    vartype=0;
  896. X}
  897. X
  898. X/*
  899. X *      This routine will deal with the eval() function. It has to do
  900. X *    a lot of moving of data. to enable it to 'compile' an expression
  901. X *    so that it can be evaluated.
  902. X */
  903. X
  904. X
  905. Xevalu()
  906. X{
  907. X    register char   *tmp;
  908. X    char    chblck1[256];
  909. X    char    chblck2[256];
  910. X
  911. X    checksp();
  912. X    if(evallock>5)
  913. X        error(43);      /* mutually recursive eval */
  914. X    evallock++;
  915. X    stringeval(gblock);
  916. X    gblock[gcursiz]=0;
  917. X    strcpy(nline,chblck2);          /* save nline */
  918. X    line[0]='\01';                  /* stop a line number being created */
  919. X    strcpy(gblock,&line[1]);
  920. X    compile(0);
  921. X    strcpy(&nline[1],chblck1);    /* restore nline ( eval in immeadiate */
  922. X    strcpy(chblck2,nline);        /* mode ). */
  923. X    tmp=point;
  924. X    point=chblck1;
  925. X    eval();
  926. X    if(getch())
  927. X        error(SYNTAX);
  928. X    point=tmp;
  929. X    evallock--;
  930. X}
  931. X
  932. Xffn()
  933. X{
  934. X    register struct  deffn   *p;
  935. X    value   ovrs[3];
  936. X    value   nvrs[3];
  937. X    char    vttys[3];
  938. X    char    *spoint;
  939. X    register int    i;
  940. X    if(!isletter(*point))
  941. X        error(SYNTAX);
  942. X    getnm();
  943. X#ifdef  LNAMES
  944. X    for(p = (deffnp)enames ; p < (deffnp)edefns ;
  945. X                    p = (deffnp)((memp)p + p->offs) )
  946. X#else
  947. X    for( p = (deffnp)estring ; p < (deffnp)edefns ;
  948. X                    p = (deffnp)((memp)p + p->offs) )
  949. X#endif
  950. X        if(p->dnm ==nm )
  951. X            goto got;
  952. X    error(UNDEFFN);
  953. Xgot:
  954. X    for(i=0;i<p->narg;i++)  /* save values */
  955. X#ifndef V6C
  956. X        ovrs[i] = *((value *) (p->vargs[i] + earray) );
  957. X#else
  958. X        movein( (double *)(p->vargs[i] + earray) ,&ovrs[i]);
  959. X#endif
  960. X    if(p->narg){
  961. X        if(*point++!='(')
  962. X            error(SYNTAX);
  963. X        for(i=0;;){
  964. X            eval();
  965. X#ifndef V6C
  966. X            nvrs[i] = res;
  967. X#else
  968. X            movein(&res,&nvrs[i]);
  969. X#endif
  970. X            vttys[i] = vartype;
  971. X            if(++i >= p->narg )
  972. X                break;
  973. X            if( getch() != ',' )
  974. X                error(SYNTAX);
  975. X        }
  976. X        if( getch() != ')' )
  977. X            error(SYNTAX);
  978. X    }                               /* got arguments in nvrs[] */
  979. X
  980. X    for(i=0;i<p->narg;i++){         /* put in new values */
  981. X#ifndef V6C
  982. X        res = nvrs[i];
  983. X#else
  984. X        movein(&nvrs[i],&res);
  985. X#endif
  986. X        vartype=vttys[i];
  987. X        putin((value *)(p->vargs[i] + earray),((p->vtys>>i)&01));
  988. X    }
  989. X    spoint=point;
  990. X    point=p->exp;
  991. X    eval();
  992. X    for(i=0;i<p->narg;i++)
  993. X#ifndef V6C
  994. X        *( (value *)(p->vargs[i] + earray)) = ovrs[i];
  995. X#else
  996. X        movein(&ovrs[i], (double *) (p->vargs[i] + earray) );
  997. X#endif
  998. X    if(getch())
  999. X        error(SYNTAX);
  1000. X    point= spoint;
  1001. X    i= p->vtys>>4;
  1002. X    if(vartype != (char)i){
  1003. X        if(vartype)
  1004. X            cvt(&res);
  1005. X        else if(conv(&res))
  1006. X            error(INTOVER);
  1007. X        vartype=i;
  1008. X    }
  1009. X}
  1010. X
  1011. X/* int() - return the greatest integer less than x */
  1012. X
  1013. Xintf()
  1014. X{
  1015. X#ifndef SOFTFP
  1016. X    double  floor();
  1017. X    eval();
  1018. X    if(!vartype)
  1019. X        res.f = floor(res.f);
  1020. X    if(!conv(&res))
  1021. X        vartype=01;
  1022. X#else
  1023. X    value   temp;
  1024. X    static  double  ONE = 1.0;
  1025. X
  1026. X    eval();
  1027. X    if(vartype)             /* conv and integ truncate not round */
  1028. X        return;
  1029. X#ifdef  PORTABLE
  1030. X    if(res.f>=0){
  1031. X#else
  1032. X    if(res.i>=0){                   /* positive easy */
  1033. X#endif
  1034. X        if(!conv(&res))
  1035. X            vartype=01;
  1036. X        else integ(&res);
  1037. X        return;
  1038. X    }
  1039. X#ifndef V6C
  1040. X    temp = res;
  1041. X#else
  1042. X    movein(&res,&temp);
  1043. X#endif
  1044. X    integ(&res);
  1045. X    if(cmp(&res,&temp)){            /* not got an integer subtract one */
  1046. X#ifndef V6C
  1047. X        res = *((value *)&ONE);
  1048. X#else
  1049. X        movein(&ONE,&res);
  1050. X#endif
  1051. X        fsub(&temp,&res);
  1052. X        integ(&res);
  1053. X    }
  1054. X    if(!conv(&res))
  1055. X        vartype=01;
  1056. X#endif                                  /* not floating point */
  1057. X}
  1058. X
  1059. Xpeekf(sp)
  1060. X{
  1061. X    register char   *p;
  1062. X#ifndef pdp11
  1063. X    register long   l;
  1064. X    eval();
  1065. X    if(vartype)
  1066. X        cvt(&res);
  1067. X    l = res.f;
  1068. X    if(res.f > 0x7fff000 || res.f < 0)      /* check this */
  1069. X        error(FUNCT);
  1070. X    p = (char *)l;
  1071. X#else
  1072. X    eval();
  1073. X    if(!vartype && conv(&res))
  1074. X        error(FUNCT);
  1075. X    p= (char *)res.i;               /* horrible - fix for a Vax */
  1076. X#endif
  1077. X    vartype=01;
  1078. X    if(p>vvend && p < (char *)&sp )
  1079. X        res.i=0;
  1080. X    else res.i = *p & 0377;
  1081. X}
  1082. X
  1083. Xpoke(sp)                /* sp = approx position of stack */
  1084. X{                                       /* can give bus errors */
  1085. X#ifndef pdp11                           /* why are you poking any way ??? */
  1086. X    register long   l;
  1087. X#endif
  1088. X    register char   *p;
  1089. X    register int    i;
  1090. X    eval();
  1091. X    if(getch()!=',')
  1092. X        error(SYNTAX);
  1093. X#ifndef pdp11
  1094. X    if(vartype)
  1095. X        cvt(&res);
  1096. X    l = res.f;
  1097. X    if(res.f > 0x7fff000 || res.f < 0)      /* check this */
  1098. X        error(FUNCT);
  1099. X    p = (char *)l;
  1100. X#else
  1101. X    if(!vartype && conv(&res))
  1102. X        error(FUNCT);
  1103. X    p= (char *)res.i;
  1104. X#endif
  1105. X    i= evalint();
  1106. X    check();
  1107. X    if(i<0)
  1108. X        error(FUNCT);
  1109. X    if(p< vvend || p > (char *)&sp)
  1110. X        *p = i;
  1111. X    normret;
  1112. X}
  1113. X
  1114. Xsinf()
  1115. X{
  1116. X#ifndef SOFTFP
  1117. X    double  sin();
  1118. X#endif
  1119. X    eval();
  1120. X    if(vartype)
  1121. X        cvt(&res);
  1122. X    vartype=0;
  1123. X#ifndef SOFTFP
  1124. X    res.f = sin(res.f);
  1125. X#else
  1126. X    sin(&res);
  1127. X#endif
  1128. X}
  1129. X
  1130. Xcosf()
  1131. X{
  1132. X#ifndef SOFTFP
  1133. X    double  cos();
  1134. X#endif
  1135. X    eval();
  1136. X    if(vartype)
  1137. X        cvt(&res);
  1138. X    vartype=0;
  1139. X#ifndef SOFTFP
  1140. X    res.f = cos(res.f);
  1141. X#else
  1142. X    cos(&res);
  1143. X#endif
  1144. X}
  1145. X
  1146. Xatanf()
  1147. X{
  1148. X#ifndef SOFTFP
  1149. X    double  atan();
  1150. X#endif
  1151. X    eval();
  1152. X    if(vartype)
  1153. X        cvt(&res);
  1154. X    vartype=0;
  1155. X#ifndef SOFTFP
  1156. X    res.f = atan(res.f);
  1157. X#else
  1158. X    atan(&res);
  1159. X#endif
  1160. X}
  1161. X
  1162. X/*
  1163. X * the "system" function, returns the status of the command it executes
  1164. X */
  1165. X
  1166. X
  1167. Xssystem()
  1168. X{
  1169. X    register int    i;
  1170. X    register int    (*q)() , (*p)();
  1171. X    int     (*signal())();
  1172. X    char    *s;
  1173. X    int     status;
  1174. X#ifdef  SIGTSTP
  1175. X    int     (*t)();
  1176. X#endif
  1177. X
  1178. X    stringeval(gblock);             /* get the command */
  1179. X    gblock[gcursiz] = 0;
  1180. X
  1181. X    flushall();
  1182. X#ifdef  SIGTSTP
  1183. X    t = signal(SIGTSTP, SIG_DFL);
  1184. X#endif
  1185. X#ifdef  VFORK
  1186. X    i = vfork();
  1187. X#else
  1188. X    i=fork();
  1189. X#endif
  1190. X    if(i==0){
  1191. X        rset_term(1);
  1192. X        setuid(getuid());               /* stop user getting clever */
  1193. X#ifdef  V7
  1194. X        s = getenv("SHELL");
  1195. X        if(!s || !*s)
  1196. X            s = "/bin/sh";
  1197. X#else
  1198. X        s = "/bin/sh";
  1199. X#endif
  1200. X        execl(s, "sh (from basic)", "-c", gblock, 0);
  1201. X        exit(-1);                       /* problem */
  1202. X    }
  1203. X    if(i != -1){
  1204. X        p=signal(SIGINT,SIG_IGN);       /* ignore some signals */
  1205. X        q=signal(SIGQUIT, SIG_IGN);
  1206. X        while(i != wait(&status) );     /* wait on the 'child' */
  1207. X        signal(SIGINT,p);               /* resignal to what they */
  1208. X        signal(SIGQUIT,q);              /* were before */
  1209. X                        /* in a mode fit for basic */
  1210. X        set_term();                     /* reset terminal modes */
  1211. X        rset_term(0);
  1212. X        i = status;
  1213. X    }
  1214. X#ifdef  SIGTSTP
  1215. X    signal(SIGTSTP, t);
  1216. X#endif
  1217. X    vartype = 1;
  1218. X    res.i = i;
  1219. X}
  1220. End of bas3.c
  1221. chmod u=rw-,g=r,o=r bas3.c
  1222. echo x - bas4.c 1>&2
  1223. sed 's/^X//' > bas4.c << 'End of bas4.c'
  1224. X/*
  1225. X * BASIC by Phil Cockcroft
  1226. X */
  1227. X#include        "bas.h"
  1228. X
  1229. X/*
  1230. X *      Stringeval() will evaluate a string expression of any
  1231. X *    form. '+' is used as the concatenation operator
  1232. X *
  1233. X *      gblock and gcursiz are used as global variables by the
  1234. X *    string routines. Gblock contains the resultant string while
  1235. X *    gcursiz holds the length of the resultant string ( even if not
  1236. X *    put in gblock ).
  1237. X *      For routines that need more than one result e.g. mid$ instr$
  1238. X *    then one result at least is put on the stack while the other
  1239. X *    ( possibly ) is put in gblock.
  1240. X */
  1241. X
  1242. X/*
  1243. X *      The parameter to stringeval() is a pointer to where the
  1244. X *    result will be put.
  1245. X */
  1246. X
  1247. X
  1248. Xstringeval(gblck)
  1249. Xchar    *gblck;
  1250. X{
  1251. X    int     cursiz=0;
  1252. X    memp    l;
  1253. X    int     c;
  1254. X    char    charac;
  1255. X    register char   *p,*q;
  1256. X    register int    i;
  1257. X    int     m[2];
  1258. X    char    chblock[256];
  1259. X    char    *ctime();
  1260. X    checksp();
  1261. X    q=chblock;
  1262. Xfor(;;){
  1263. X    gcursiz=0;
  1264. X    c=getch();
  1265. X    if(c&0200){             /* a string function */
  1266. X        if(c==DATE){            /* date does not want a parameter */
  1267. X            time(m);
  1268. X            p=ctime(m);
  1269. X            gcursiz=24;
  1270. X        }
  1271. X        else {
  1272. X            if(c<MINSTRING || c>MAXSTRING)
  1273. X                error(11);
  1274. X            if(*point++!='(')
  1275. X                error(1);
  1276. X            (*strngcommand[c-MINSTRING])();
  1277. X            if(getch()!=')')
  1278. X                error(1);
  1279. X            p=gblock;       /* string functions return with */
  1280. X        }                       /* result in gblock */
  1281. X    }
  1282. X    else if(c=='"' || c=='`'){      /* a quoted string */
  1283. X        charac=c;
  1284. X        p=point;
  1285. X        while(*point && *point!= charac){
  1286. X            gcursiz++;
  1287. X            point++;
  1288. X        }
  1289. X        if(*point)
  1290. X            point++;
  1291. X    }
  1292. X    else if(isletter(c)){           /* a string variable */
  1293. X        point--;
  1294. X        l=getname();
  1295. X        if(vartype!=02)
  1296. X            error(SYNTAX);
  1297. X        if(p= ((stdatap)l)->stpt)           /* newstring routines */
  1298. X            gcursiz= *p++ &0377;
  1299. X    }
  1300. X    else
  1301. X        error(SYNTAX);
  1302. X   /* all routines return to here with the string pointed to by p */
  1303. X    if(cursiz+gcursiz>255)
  1304. X        error(9);
  1305. X    i=gcursiz;
  1306. X    if(getch()!='+')
  1307. X        break;
  1308. X    cursiz += i;
  1309. X    if(i)  do
  1310. X         *q++ = *p++;
  1311. X           while(--i);
  1312. X    }
  1313. X    point--;                        /* the following code is */
  1314. X    if(!cursiz){                    /* horrible but it speeds */
  1315. X        if(p==gblck)            /* execution by reducing the amount */
  1316. X            return;         /* of movement of strings */
  1317. X        cursiz=gcursiz;
  1318. X    }
  1319. X    else {
  1320. X        cursiz+=gcursiz;
  1321. X        if(i) do
  1322. X            *q++ = *p++;
  1323. X              while(--i);
  1324. X        p=chblock;
  1325. X    }
  1326. X    q=gblck;
  1327. X    gcursiz=cursiz;
  1328. X    if(i=cursiz)
  1329. X          do
  1330. X        *q++ = *p++;
  1331. X          while(--i);
  1332. X}
  1333. X
  1334. X/*
  1335. X *      stringassign() will put the sting in gblock into the string
  1336. X *    pointed to by p.
  1337. X *      It will call the garbage collection routine as neccasary.
  1338. X */
  1339. X
  1340. Xstringassign(p)
  1341. Xstruct  stdata *p;
  1342. X{
  1343. X    register char   *q,*r;
  1344. X    register int    i;
  1345. X
  1346. X    p->stpt=0;
  1347. X    if(!gcursiz)
  1348. X        return;
  1349. X    if(estdt-eostring <gcursiz+1){
  1350. X        garbage();
  1351. X        if(estdt-eostring <gcursiz+1)
  1352. X            error(3);       /* out of string space */
  1353. X    }
  1354. X    p->stpt=eostring;
  1355. X    q=eostring;
  1356. X    i=gcursiz;
  1357. X    *q++ = i;
  1358. X    r= gblock;
  1359. X    do
  1360. X        *q++ = *r++;
  1361. X    while(--i);
  1362. X    eostring=q;
  1363. X}
  1364. X
  1365. X/*
  1366. X *      This will collect all unused strings and free the space
  1367. X *    It works that is about all tha can be said for it.
  1368. X */
  1369. X
  1370. Xgarbage()               /* new string routine */
  1371. X{
  1372. X    register char   *p,*q;
  1373. X    register struct stdata  *r;
  1374. X    register int     j;
  1375. X
  1376. X    p=ecore;
  1377. X    q=ecore;
  1378. X    while(p<eostring){
  1379. X        j= (*p&0377)+1;
  1380. X        for(r = (stdatap)estdt ; r < (stdatap)estring ; r++)
  1381. X            if(r->stpt==p)
  1382. X                if(q==p){
  1383. X                    p+=j;
  1384. X                    q=p;
  1385. X                    goto more;
  1386. X                }
  1387. X                else  {
  1388. X                    r->stpt=q;
  1389. X                    do{
  1390. X                        *q++ = *p++;
  1391. X                      }while(--j);
  1392. X                    goto more;
  1393. X                }
  1394. X        p+=j;
  1395. Xmore:           ;
  1396. X    }
  1397. X    eostring=q;
  1398. X}
  1399. X
  1400. X/*
  1401. X *      The following routines implement string functions they are all quite
  1402. X *    straight forward in operation.
  1403. X */
  1404. X
  1405. Xstrng()
  1406. X{
  1407. X    int     m;
  1408. X    register char   *q,*p;
  1409. X    int    cursiz=0;
  1410. X    int     siz;
  1411. X    register int     i;
  1412. X    char    chblock[256];
  1413. X
  1414. X    checksp();
  1415. X    stringeval(chblock);
  1416. X    cursiz=gcursiz;
  1417. X    if(getch()!=',')
  1418. X        error(1);
  1419. X    m=evalint();
  1420. X    if(m>255 || m <0)
  1421. X        error(10);
  1422. X    if(!cursiz){
  1423. X        gcursiz=0;
  1424. X        return;
  1425. X    }
  1426. X    siz=m;
  1427. X    if((unsigned)(cursiz * siz) >255)
  1428. X        error(9);
  1429. X    gcursiz= cursiz *siz;
  1430. X    p=gblock;
  1431. X    while(siz--)
  1432. X        for(q=chblock,i=cursiz;i--;)
  1433. X            *p++ = *q++;
  1434. X}
  1435. X
  1436. X/*      left$ string function */
  1437. X
  1438. Xleftst()
  1439. X{
  1440. X    int     l1;
  1441. X    register int    i;
  1442. X    register char   *p,*q;
  1443. X    int     cursiz;
  1444. X    char    chblock[256];
  1445. X
  1446. X    checksp();
  1447. X    stringeval(chblock);
  1448. X    cursiz=gcursiz;
  1449. X    if(getch()!=',')
  1450. X        error(SYNTAX);
  1451. X    l1=evalint();
  1452. X    if(l1<0 || l1 >255)
  1453. X        error(10);
  1454. X    i=l1;
  1455. X    if(l1>cursiz)
  1456. X        i=cursiz;
  1457. X    p=chblock;
  1458. X    q=gblock;
  1459. X    if(gcursiz=i) do
  1460. X           *q++ = *p++;
  1461. X          while(--i);
  1462. X}
  1463. X
  1464. X/*      right$ string function */
  1465. X
  1466. Xrightst()
  1467. X{
  1468. X    int     l1,l2;
  1469. X    register int    i;
  1470. X    register char   *p,*q;
  1471. X    int     cursiz;
  1472. X    char    chblock[256];
  1473. X
  1474. X    checksp();
  1475. X    stringeval(chblock);
  1476. X    cursiz=gcursiz;
  1477. X    if(getch()!=',')
  1478. X        error(SYNTAX);
  1479. X    l1=evalint();
  1480. X    if(l1<0 || l1 >255)
  1481. X        error(10);
  1482. X    l2= cursiz-l1;
  1483. X    i=l1;
  1484. X    if(i>cursiz){
  1485. X        i=cursiz;
  1486. X        l2=0;
  1487. X    }
  1488. X    p= &chblock[l2];
  1489. X    q= gblock;
  1490. X    if(gcursiz=i) do
  1491. X        *q++ = *p++;
  1492. X          while(--i);
  1493. X}
  1494. X
  1495. X/*
  1496. X *      midst$ string function:-
  1497. X *              can have two or three parameters , if third
  1498. X *              parameter is missing then a value of cursiz
  1499. X *              is used.
  1500. X */
  1501. X
  1502. Xmidst()
  1503. X{
  1504. X    int     l1,l2;
  1505. X    int    cursiz;
  1506. X    register int     i;
  1507. X    register char   *q,*p;
  1508. X    char    chblock[256];
  1509. X
  1510. X    checksp();
  1511. X    stringeval(chblock);
  1512. X    cursiz=gcursiz;
  1513. X    if(getch()!=',')
  1514. X        error(1);
  1515. X    l1=evalint()-1;
  1516. X    if(getch()!=','){
  1517. X        point--;
  1518. X        l2=255;
  1519. X    }
  1520. X    else
  1521. X        l2=evalint();
  1522. X    if(l1<0 || l2<0 || l1 >255 || l2 >255)
  1523. X        error(10);
  1524. X    l2+=l1;
  1525. X    if(l2>cursiz)
  1526. X        l2=cursiz;
  1527. X    if(l1>cursiz)
  1528. X        l1=cursiz;
  1529. X    i= l2-l1;
  1530. X    p=gblock;
  1531. X    q= &chblock[l1];
  1532. X    if(gcursiz=i) do
  1533. X          *p++ = *q++;
  1534. X          while(--i);
  1535. X}
  1536. X
  1537. X/*      ermsg$ string routine , returns the specified error message */
  1538. X
  1539. Xestrng()
  1540. X{
  1541. X    register char   *p,*q,*r;
  1542. X    int     l;
  1543. X
  1544. X    l=evalint();
  1545. X    if(l<1 || l> MAXERR)
  1546. X        error(22);
  1547. X    p=ermesg[l-1];
  1548. X    q=gblock;
  1549. X    r=p;
  1550. X    while(*q++ = *p++);
  1551. X    gcursiz= p-r-1;
  1552. X}
  1553. X
  1554. X/*      chr$ string function , returns character from the ascii value */
  1555. X
  1556. Xchrstr()
  1557. X{
  1558. X    register int    i;
  1559. X
  1560. X    i=evalint();
  1561. X    if(i<0 || i>255)
  1562. X        error(FUNCT);
  1563. X    *gblock= i;
  1564. X    gcursiz=1;
  1565. X}
  1566. X
  1567. X/*      str$ string routine , returns a string representation
  1568. X *      of the number given. There is NO leading space on positive
  1569. X *      numbers.
  1570. X */
  1571. X
  1572. Xnstrng()
  1573. X{
  1574. X    register char   *p,*q;
  1575. X
  1576. X    eval();
  1577. X    gcvt();
  1578. X    if(*gblock!=' ')
  1579. X        return;
  1580. X    q=gblock;
  1581. X    p= gblock+1;
  1582. X    while(*q++ = *p++);
  1583. X    gcursiz= --q -gblock;
  1584. X}
  1585. X
  1586. X/*      val() maths function , returns the value of a string. If
  1587. X *    no numeric value is used then a value of zero is returned.
  1588. X */
  1589. X
  1590. Xval()
  1591. X{
  1592. X    register char   *tmp,*p;
  1593. X    register minus=0;
  1594. X
  1595. X    stringeval(gblock);
  1596. X    gblock[gcursiz]=0;
  1597. X    p=gblock;
  1598. X    while(*p++ == ' ');
  1599. X    if(*--p=='-'){
  1600. X        p++;
  1601. X        minus++;
  1602. X    }
  1603. X    if(!isnumber(*p) && *p!='.'){
  1604. X        res.i=0;
  1605. X        vartype=01;
  1606. X        return;
  1607. X    }
  1608. X    tmp=point;
  1609. X    point=p;
  1610. X    if(!getop()){
  1611. X        point=tmp;
  1612. X        error(36);
  1613. X    }
  1614. X    point=tmp;
  1615. X    if(minus)
  1616. X        negate();
  1617. X}
  1618. X
  1619. X/*      instr() maths function , returns the index of the first string
  1620. X *    in the second. Starting either from the first character or from
  1621. X *    the optional third parameter position.
  1622. X */
  1623. X
  1624. Xinstr()
  1625. X{
  1626. X    int     cursiz1;
  1627. X    int     cursiz2;
  1628. X    register char   *p,*q,*r;
  1629. X    int     i=0;
  1630. X    char    chbl1ck[256];
  1631. X    char    chbl2ck[256];
  1632. X
  1633. X    checksp();
  1634. X    stringeval(chbl1ck);
  1635. X    cursiz1=gcursiz;
  1636. X    if(getch()!=',')
  1637. X        error(SYNTAX);
  1638. X    stringeval(chbl2ck);
  1639. X    cursiz2=gcursiz;
  1640. X    if(getch()==','){
  1641. X        i=evalint()-1;
  1642. X        if(i<0 || i>255)
  1643. X            error(10);
  1644. X    }
  1645. X    else
  1646. X        point--;
  1647. X    cursiz2-=cursiz1;
  1648. X    vartype=01;
  1649. X    r= &chbl2ck[cursiz1+i];
  1650. X    for(;i<=cursiz2;i++,r++){
  1651. X        p= chbl1ck;
  1652. X        q= &chbl2ck[i];
  1653. X        while(q < r && *p== *q)
  1654. X            p++,q++;
  1655. X        if( q == r ){
  1656. X            res.i = i+1;
  1657. X            return;
  1658. X        }
  1659. X    }
  1660. X    res.i = 0;
  1661. X}
  1662. X
  1663. X/*      space$ string function returns a string of spaces the number
  1664. X *    of which is the argument to the function
  1665. X */
  1666. X
  1667. Xspace()
  1668. X{
  1669. X    register int    i;
  1670. X    register char   *q;
  1671. X
  1672. X    i=evalint();
  1673. X    if(i<0 || i>255)
  1674. X        error(10);
  1675. X    if(gcursiz=i){
  1676. X        q= gblock;
  1677. X        do{
  1678. X            *q++ =' ';
  1679. X        }while(--i);
  1680. X    }
  1681. X}
  1682. X
  1683. X/* get$() read a single character from a file */
  1684. X
  1685. Xgetstf()
  1686. X{
  1687. X    register struct filebuf *p;
  1688. X    register i;
  1689. X
  1690. X    i=evalint();
  1691. X    if(!i){
  1692. X        if(noedit)        /* illegal function with silly terminals */
  1693. X            error(11);
  1694. X        if(!trapped){
  1695. X            set_term();
  1696. X            *gblock=readc();
  1697. X            rset_term(0);
  1698. X        }
  1699. X        if(!trapped)
  1700. X            gcursiz=1;
  1701. X        else
  1702. X            gcursiz =0;
  1703. X    }
  1704. X    else {
  1705. X        p=getf(i,_READ);
  1706. X        if(!(i = filein(p,gblock,1)) )
  1707. X            error(30);
  1708. X        gcursiz=i;
  1709. X    }
  1710. X}
  1711. X
  1712. X
  1713. X/*      mid$() when on the left of an assignment */
  1714. X/* can have optional third argument */
  1715. X
  1716. X/*      a$ = "this is me"
  1717. X * mid$(a$,2) = "hello"         ->   a$ = "thello"
  1718. X * mid$(a$,2,5) = "hello"       ->   a$ = "thellos me"
  1719. X */
  1720. X
  1721. Xlhmidst()
  1722. X{
  1723. X    char    chbl1ck[256];
  1724. X    char    chbl2ck[256];
  1725. X    int     cursiz,rhside,i1,i2;
  1726. X    memp    pt;
  1727. X    register char   *p,*q;
  1728. X    register int    i;
  1729. X
  1730. X    if(*point++ !='(')
  1731. X        error(SYNTAX);
  1732. X    pt=getname();
  1733. X    if(vartype!=02)
  1734. X        error(VARREQD);
  1735. X    if(getch()!=',')
  1736. X        error(SYNTAX);
  1737. X    i1=evalint()-1;
  1738. X    if(getch()!=','){
  1739. X        i2=255;
  1740. X        point--;
  1741. X    }
  1742. X    else
  1743. X        i2= evalint();
  1744. X    if(i2<0 || i2>255 || i1<0 || i1>255)
  1745. X        error(10);
  1746. X    if(getch()!=')' )
  1747. X        error(SYNTAX);
  1748. X    if(getch()!='=')
  1749. X        error(4);
  1750. X    cursiz=0;
  1751. X    if(p= ((stdatap)pt)->stpt){
  1752. X        cursiz=i= *p++ & 0377;
  1753. X        q=chbl1ck;
  1754. X        do{
  1755. X            *q++ = *p++;
  1756. X        }while(--i);
  1757. X    }
  1758. X    if(i1>cursiz)
  1759. X        i1=cursiz;
  1760. X    i2+=i1;
  1761. X    if(i2>cursiz)
  1762. X        i2=cursiz;
  1763. X    rhside= cursiz -i2;
  1764. X    if(i=rhside){
  1765. X        p=chbl2ck;
  1766. X        q= &chbl1ck[i2];
  1767. X        do{
  1768. X            *p++ = *q++;
  1769. X        }while(--i);
  1770. X    }
  1771. X    stringeval(gblock);
  1772. X    check();
  1773. X    if(gcursiz+rhside+i1>255)
  1774. X        error(9);
  1775. X    p= &chbl1ck[i1];
  1776. X    q= gblock;
  1777. X    if(i=gcursiz)
  1778. X        do{             /* what a lot of data movement */
  1779. X            *p++ = *q++;
  1780. X        }while(--i);
  1781. X    gcursiz+=i1;
  1782. X    q=chbl2ck;
  1783. X    if(i=rhside)
  1784. X        do{
  1785. X            *p++ = *q++;
  1786. X        }while(--i);
  1787. X    gcursiz+=rhside;
  1788. X    p=gblock;
  1789. X    q=chbl1ck;
  1790. X    if(i=gcursiz)
  1791. X        do{
  1792. X            *p++ = *q++;
  1793. X        }while(--i);
  1794. X    stringassign( (stdatap)pt );    /* done it !! */
  1795. X    normret;
  1796. X}
  1797. X
  1798. X#ifdef  _BLOCKED
  1799. X
  1800. X/* mkint(a$)
  1801. X * routine to make the first 2 bytes of string into a integer
  1802. X * for use with formatted files.
  1803. X */
  1804. X
  1805. Xmkint()
  1806. X{
  1807. X      register short  *p = (short *)gblock;
  1808. X      stringeval(gblock);
  1809. X      if(gcursiz < sizeof(short) )
  1810. X          error(10);
  1811. X      res.i = *p;
  1812. X      vartype = 01;
  1813. X}
  1814. X
  1815. X/* ditto for string to double */
  1816. X
  1817. Xmkdouble()
  1818. X{
  1819. X      stringeval(gblock);
  1820. X      if(gcursiz < sizeof(double) )
  1821. X          error(10);
  1822. X#ifndef V6C
  1823. X      res = *( (value *)gblock);
  1824. X#else
  1825. X      movein(gblock,&res);
  1826. X#endif
  1827. X      vartype = 0;
  1828. X}
  1829. X
  1830. X/*
  1831. X * mkistr$(x%)
  1832. X * convert an integer into a string for use with disk files
  1833. X */
  1834. X
  1835. Xmkistr()
  1836. X{
  1837. X      register short  *p = (short *)gblock;
  1838. X      eval();
  1839. X      if(!vartype && conv(&res))
  1840. X          error(FUNCT);
  1841. X      *p = res.i;
  1842. X      gcursiz = sizeof(short);
  1843. X}
  1844. X
  1845. X/* mkdstr$(x)
  1846. X * ditto for doubles.
  1847. X */
  1848. X
  1849. Xmkdstr()
  1850. X{
  1851. X      eval();
  1852. X      if(vartype)
  1853. X          cvt(&res);
  1854. X#ifndef V6C
  1855. X      *((value *)gblock) = res;
  1856. X#else
  1857. X      movein(&res,gblock);
  1858. X#endif
  1859. X      gcursiz = sizeof(double);
  1860. X}
  1861. X#else
  1862. Xmkdstr(){}
  1863. Xmkistr(){}
  1864. Xmkint(){}
  1865. Xmkdouble(){}
  1866. X#endif
  1867. End of bas4.c
  1868. chmod u=rw-,g=r,o=r bas4.c
  1869. echo x - bas5.c 1>&2
  1870. sed 's/^X//' > bas5.c << 'End of bas5.c'
  1871. X/*
  1872. X * BASIC by Phil Cockcroft
  1873. X */
  1874. X#include        "bas.h"
  1875. X
  1876. X/*
  1877. X *      This file contains the routines for input and read since they
  1878. X *    do almost the same they can use a lot of common code.
  1879. X */
  1880. X
  1881. X/*
  1882. X *      input can have a text string, which it outputs as a prompt
  1883. X *    instead of the usual '?'. If input is from a file this
  1884. X *    facility is not permitted ( what use anyway ? ).
  1885. X *
  1886. X *      added 28-oct-81
  1887. X */
  1888. X
  1889. Xinput()
  1890. X{
  1891. X    register char   *p;
  1892. X    register int    i;
  1893. X    memp    l;
  1894. X    register filebufp infile=0;
  1895. X    char    lblock[512];
  1896. X    int     firsttime=0;
  1897. X    int     c;
  1898. X    char    vty;
  1899. X    char    *getstrdt(),*getdata();
  1900. X
  1901. X    c=getch();
  1902. X    if(c=='"'){
  1903. X        i=0;
  1904. X        p=line;
  1905. X        while(*point && *point != '"'){
  1906. X            *p++ = *point++;
  1907. X            i++;
  1908. X        }
  1909. X        if(*point)
  1910. X            point++;
  1911. X        if(getch()!=';')
  1912. X            error(SYNTAX);
  1913. X        *p=0;
  1914. X        firsttime++;
  1915. X    }
  1916. X    else if(c=='#'){
  1917. X        i=evalint();
  1918. X        if(getch()!=',')
  1919. X            error(SYNTAX);
  1920. X        infile=getf(i,_READ);
  1921. X    }
  1922. X    else
  1923. X        point--;
  1924. X    l=getname();
  1925. X    vty=vartype;
  1926. Xfor(;;){
  1927. X    if(!infile){
  1928. X        if(!firsttime){
  1929. X            *line='?';
  1930. X            i=1;
  1931. X        }
  1932. X        firsttime=0;
  1933. X        edit(i,i,i);
  1934. X        if(trapped){
  1935. X            point=savepoint; /* restore point to start of in. */
  1936. X            return(-1);     /* will trap at start of this in. */
  1937. X        }
  1938. X        strcpy(&line[i],lblock);
  1939. X    }
  1940. X    else if(! filein(infile,lblock,512) )
  1941. X        error(30);
  1942. X    p= lblock;
  1943. Xex3:    while(*p++ ==' ');      /* ignore leading spaces */
  1944. X    if(!*--p && vty!=02)
  1945. X        continue;
  1946. X    p= ((vty==02)?(getstrdt(p)) :( getdata(p)));
  1947. X    if(p){
  1948. X        while(*p++ == ' ');
  1949. X        p--;
  1950. X    }
  1951. X    if(!p || (*p!=',' && *p)){
  1952. X        if(infile)
  1953. X            error(26);
  1954. X        prints("Bad data redo\n");
  1955. X        continue;
  1956. X    }
  1957. X    if(vartype == 02)
  1958. X        stringassign( (stdatap)l );
  1959. X    else
  1960. X        putin(l,vty);
  1961. X    if(getch()!=',')
  1962. X        break;
  1963. X    l=getname();
  1964. X    vty=vartype;
  1965. X    if(*p==','){
  1966. X        p++;
  1967. X        goto ex3;
  1968. X    }
  1969. X    }
  1970. X    point--;
  1971. X    normret;
  1972. X}
  1973. X
  1974. X/* valid types for string input :-
  1975. X * open quote followed by any character until another quote or the end of line
  1976. X * no quote followed by a sequence of characters except a quote
  1977. X * terminated by a comma (or end of line).
  1978. X */
  1979. X
  1980. X/*      the next two routines return zero on error and a pointer to
  1981. X *    rest of string on success.
  1982. X */
  1983. X
  1984. X/*      read string data routine */
  1985. X
  1986. Xchar    *
  1987. Xgetstrdt(p)
  1988. Xregister char   *p;
  1989. X{
  1990. X    register char *q;
  1991. X    register int    cursiz=0;
  1992. X    char    charac;
  1993. X
  1994. X    q=gblock;
  1995. X    if(*p=='"' || *p=='`' ){
  1996. X        charac= *p++;
  1997. X        while(*p!= charac && *p ){
  1998. X            *q++ = *p++;
  1999. X            if(++cursiz>255)
  2000. X                return(0);
  2001. X        }
  2002. X        if(*p)
  2003. X            p++;
  2004. X        gcursiz=cursiz;
  2005. X        return(p);
  2006. X    }
  2007. X    while( *p && *p!=',' && *p!='"' && *p!='`'){
  2008. X        *q++ = *p++;
  2009. X        if(++cursiz>255)
  2010. X            return(0);
  2011. X    }
  2012. X    gcursiz=cursiz;
  2013. X    return(p);
  2014. X}
  2015. X
  2016. X/*      read number routine */
  2017. X
  2018. Xchar    *
  2019. Xgetdata(p)
  2020. Xregister char   *p;
  2021. X{
  2022. X    register char    *tmp;
  2023. X    register int     minus=0;
  2024. X    if(*p=='-'){
  2025. X        p++;
  2026. X        minus++;
  2027. X    }
  2028. X    if(!isnumber(*p) && *p!='.')
  2029. X        return(0);
  2030. X    tmp=point;
  2031. X    point=p;
  2032. X    if(!getop()){
  2033. X        point=tmp;
  2034. X        return(0);
  2035. X    }
  2036. X    p=point;
  2037. X    point=tmp;
  2038. X    if(minus)
  2039. X        negate();
  2040. X    return(p);
  2041. X}
  2042. X
  2043. X/* input a whole line of text (into a string ) */
  2044. X
  2045. Xlinput()
  2046. X{
  2047. X
  2048. X    register char   *p;
  2049. X    register int    i;
  2050. X    memp    l;
  2051. X    register filebufp infile;
  2052. X    char    lblock[512];
  2053. X    int     c;
  2054. X
  2055. X    c=getch();
  2056. X    if(c=='#'){
  2057. X        i=evalint();
  2058. X        if(getch()!=',')
  2059. X            error(SYNTAX);
  2060. X        infile=getf(i,_READ);
  2061. X        l=getname();
  2062. X        if(vartype!=02)
  2063. X            error(VARREQD);
  2064. X        check();
  2065. X        if(!(i= filein(infile,lblock,512)) )
  2066. X            error(30);
  2067. X        if(i>255)
  2068. X            error(9);
  2069. X        p=strcpy(lblock,gblock);
  2070. X    }
  2071. X    else {
  2072. X        if(c=='"'){
  2073. X            i=0;
  2074. X            p=line;
  2075. X            while(*point && *point != '"'){
  2076. X                *p++ = *point++;
  2077. X                i++;
  2078. X            }
  2079. X            if(*point)
  2080. X                point++;
  2081. X            if(getch()!=';')
  2082. X                error(SYNTAX);
  2083. X            *p=0;
  2084. X        }
  2085. X        else {
  2086. X            point--;
  2087. X            *line='?';
  2088. X            i=1;
  2089. X        }
  2090. X        l=getname();
  2091. X        if(vartype!=02)
  2092. X            error(VARREQD);
  2093. X        check();
  2094. X        edit(i,i,i);
  2095. X        if(trapped){
  2096. X            point=savepoint; /* restore point to start of in. */
  2097. X            return(-1);     /* will trap at start of this in. */
  2098. X        }
  2099. X        p=strcpy(&line[i],gblock);
  2100. X    }
  2101. X    gcursiz= p-gblock;
  2102. X    stringassign( (stdatap)l );
  2103. X    normret;
  2104. X}
  2105. X
  2106. X/* read added 3-12-81 */
  2107. X
  2108. X/*
  2109. X * Read routine this should :-
  2110. X *      get variable then search for data then assign it
  2111. X *      repeating until end of command
  2112. X *              ( The easy bit. )
  2113. X */
  2114. X
  2115. X/*
  2116. X * Getting data :-
  2117. X *      if the data pointer points to anywhere then it points to a line
  2118. X *      to a point where getch would get an end of line or the next data item
  2119. X *      at the end of a line a null string must be implemented as
  2120. X *      a pair of quotes i.e. "" , on inputing data '"'`s are significant
  2121. X *      this is no problem normally .
  2122. X *      If the read routine finds an end of line then there is bad data
  2123. X *
  2124. X */
  2125. X
  2126. Xreadd()
  2127. X{
  2128. X    register memp   l;
  2129. X    register char   *p;
  2130. X    register char    vty;
  2131. X    if(!datapoint)
  2132. X        getmore();
  2133. X    for(;;){
  2134. X        l=getname();
  2135. X        vty=vartype;
  2136. X        p= datapoint;
  2137. X        while(*p++ == ' ');
  2138. X        datapoint= --p;
  2139. X        if(!*p){
  2140. X            getmore();
  2141. X            p=datapoint;
  2142. X            while(*p++ ==' ');
  2143. X            p--;
  2144. X        }
  2145. X    /* get here the next thing should be a data item or an error */
  2146. X        datapoint=p;
  2147. X        if(!*p)
  2148. X            error(BADDATA);
  2149. X        p= ((vty==02)?(getstrdt(p)) :( getdata(p)));
  2150. X        if(!p)
  2151. X            error(BADDATA);
  2152. X        while(*p++ == ' ');
  2153. X        p--;
  2154. X        if(*p!=',' && *p)
  2155. X            error(BADDATA);
  2156. X        if(vty == 02)
  2157. X            stringassign( (stdatap)l );
  2158. X        else  putin(l,vty);
  2159. X        if(*p)
  2160. X            p++;
  2161. X        datapoint=p;
  2162. X        if(getch()!=',')
  2163. X            break;
  2164. X    }
  2165. X    point--;
  2166. X    normret;
  2167. X}
  2168. X
  2169. X/*
  2170. X * This is only called when datapoint is at the end of the line
  2171. X * it is also called if datapoint is zero e.g. when this is the first call
  2172. X * to read.
  2173. X */
  2174. X
  2175. Xgetmore()
  2176. X{
  2177. X    register lpoint p;
  2178. X    register char   *q;
  2179. X    if(!datapoint)
  2180. X        p = (lpoint)fendcore;
  2181. X    else {
  2182. X        p=datastolin;
  2183. X        if(p->linnumb)
  2184. X            p = (lpoint)((memp)p + lenv(p));
  2185. X    }
  2186. X    for(;p->linnumb; p = (lpoint)((memp)p + lenv(p)) ){
  2187. X        q=p->lin;
  2188. X        while(*q++ == ' ');
  2189. X        if(*--q == (char)DATA){
  2190. X            datapoint= ++q;
  2191. X            datastolin=p;
  2192. X            return;
  2193. X        }
  2194. X    }
  2195. X    datastolin=p;
  2196. X    error(OUTOFDATA);
  2197. X}
  2198. X
  2199. X/*      the 'data' command it just checks things and sets up pointers
  2200. X *    as neccasary.
  2201. X */
  2202. X
  2203. Xdodata()
  2204. X{
  2205. X    register char    *p;
  2206. X    if(runmode){
  2207. X        p=stocurlin->lin;
  2208. X        while(*p++ ==' ');
  2209. X        if(*--p != (char) DATA)
  2210. X            error(BADDATA);
  2211. X        if(!datapoint){
  2212. X            datastolin= stocurlin;
  2213. X            datapoint= ++p;
  2214. X        }
  2215. X    }
  2216. X    return(GTO);    /* ignore rest of line */
  2217. X}
  2218. X
  2219. X/*      the 'restore' command , will reset the data pointer to
  2220. X *     the first bit of data it finds or to the start of the program
  2221. X *     if it doesn't find any. It will start searching from a line if
  2222. X *     tthat line is given as an optional parameter
  2223. X */
  2224. X
  2225. Xrestore()
  2226. X{
  2227. X    register unsigned i;
  2228. X    register lpoint p;
  2229. X    register char   *q;
  2230. X
  2231. X    i=getlin();
  2232. X    check();
  2233. X    p= (lpoint)fendcore;
  2234. X    if(i!= (unsigned)(-1) ){
  2235. X        for(;p->linnumb; p = (lpoint)( (memp)p + lenv(p)) )
  2236. X            if(p->linnumb== i)
  2237. X                goto got;
  2238. X        error(6);
  2239. X    }
  2240. Xgot:    datapoint=0;
  2241. X    for(;p->linnumb; p = (lpoint)((memp)p + lenv(p)) ){
  2242. X        q= p->lin;
  2243. X        while(*q++ ==' ');
  2244. X        if(*--q == (char)DATA){
  2245. X            datapoint= ++q;
  2246. X            break;
  2247. X        }
  2248. X    }
  2249. X    datastolin= p;
  2250. X    normret;
  2251. X}
  2252. End of bas5.c
  2253. chmod u=rw-,g=r,o=r bas5.c
  2254. echo x - bas6.c 1>&2
  2255. sed 's/^X//' > bas6.c << 'End of bas6.c'
  2256. X/*
  2257. X * BASIC by Phil Cockcroft
  2258. X */
  2259. X#include        "bas.h"
  2260. X#ifdef  V7
  2261. X#include <sys/ioctl.h>
  2262. X#endif
  2263. X
  2264. X/*
  2265. X *      This file contains all the routines to implement terminal
  2266. X *    like files.
  2267. X */
  2268. X
  2269. X/*
  2270. X *      setupfiles is called only once, it finds out how many files are
  2271. X *    required and allocates buffers for them. It will also execute
  2272. X *    'silly' programs that are given as parameters.
  2273. X */
  2274. X
  2275. Xsetupfiles(argc,argv)
  2276. Xchar    **argv;
  2277. X{
  2278. X    register int    fp;
  2279. X    register int     nfiles=2;
  2280. X    register struct filebuf *p;
  2281. X    char    *q;
  2282. X    extern  memp    sbrk();
  2283. X
  2284. X#ifdef  NOEDIT
  2285. X    noedit=1;
  2286. X#endif
  2287. X    while(argc > 1 ){
  2288. X        q = *++argv;
  2289. X        if(*q++ !='-')
  2290. X            break;
  2291. X        if(isnumber(*q)){
  2292. X            nfiles= atoi(q);
  2293. X            if(nfiles<0 || nfiles > MAXFILES)
  2294. X                nfiles=2;
  2295. X        }
  2296. X        else if(*q=='x')
  2297. X            noedit=1;
  2298. X        else if(*q=='e')
  2299. X            noedit=0;
  2300. X        argc--;
  2301. X    }
  2302. X    filestart= sbrk(0);
  2303. X    fendcore= filestart+(sizeof(struct filebuf) * nfiles);
  2304. X    brk(fendcore+sizeof(xlinnumb) );        /* allocate enough core */
  2305. X    for(p = (filebufp)filestart ; p < (filebufp)fendcore ; p++){
  2306. X        p->filedes=0;
  2307. X        p->userfiledes=0;
  2308. X        p->use=0;
  2309. X        p->nleft=0;
  2310. X    }
  2311. X        /* code added to execute silly programs */
  2312. X    if(argc <= 1)
  2313. X        return;
  2314. X    if((fp=open(*argv,0))!=-1)
  2315. X        runfile(fp);
  2316. X    prints("file not found\n");
  2317. X    _exit(1);
  2318. X}
  2319. X
  2320. X/*
  2321. X *      This routine executes silly programs. It has to load up
  2322. X *    the program and then simulate the environment as is usually seen
  2323. X *    in main. It works....
  2324. X */
  2325. X
  2326. Xrunfile(fp)
  2327. X{
  2328. X    int    firsttime;
  2329. X    register lpoint p;
  2330. X
  2331. X    setupterm();            /* set up terminal - now done after files */
  2332. X    ecore= fendcore+sizeof(xlinnumb);
  2333. X    ( (lpoint) fendcore )->linnumb=0;
  2334. X    firsttime=1;           /* flag to say that we are just loading */
  2335. X    setexit();              /* the file at the moment */
  2336. X    if(ertrap)              /* setexit is the return for error */
  2337. X        goto execut;    /* and execute */
  2338. X    if(!firsttime)          /* an error or cntrl-c */
  2339. X        quit();
  2340. X    firsttime=0;
  2341. X    readfi(fp);
  2342. X    clear(DEFAULTSTRING);
  2343. X    p= (lpoint)fendcore;
  2344. X    stocurlin=p;
  2345. X    if(!(curline=p->linnumb))       /* is this needed - yes */
  2346. X        quit();
  2347. X    point= p->lin;
  2348. X    elsecount=0;
  2349. X    runmode=1;                      /* go and run it */
  2350. Xexecut:
  2351. X    execute();
  2352. X}
  2353. X
  2354. X/* commands implemented are :-
  2355. X    open / creat
  2356. X    close
  2357. X    input
  2358. X    print
  2359. X*/
  2360. X
  2361. X/* syntax of commands :-
  2362. X    open "filename" for input as <filedesc>
  2363. X    open "filename" [for output] as <filedesc>
  2364. X    close <filedesc> ,[<filedesc>]
  2365. X    input #<filedesc> , v1 , v2 , v3 ....
  2366. X    print #<filedesc> , v1 , v2 , v3 ....
  2367. X    */
  2368. X
  2369. X/* format of file buffers    added 17-12-81
  2370. X    struct  {
  2371. X        int     filedes;        / * Unix file descriptor
  2372. X        int     userfiledes;    / * name by which it is used
  2373. X        int     posn;           / * position of cursor in file
  2374. X        int     dev;            / * dev and inode are used to
  2375. X        int     inode;          / * stop r/w to same file
  2376. X        int     use;            / * r/w etc. + other info
  2377. X        int     nleft;          / * number of characters in buffer
  2378. X        char    buf[BLOCKSIZ];  / * the actual buffer
  2379. X        } file_buffer ;
  2380. X
  2381. X    The file_buffers are stored between the end of initialised data
  2382. X      and fendcore. uses sbrk() at start up.
  2383. X
  2384. X    At start up there are two buffer spaces allocated.
  2385. X*/
  2386. X
  2387. X/*
  2388. X *      The 'open' command it allocates file descriptors and buffer
  2389. X *    space then sets about opening the file and checking weather the
  2390. X *    the file is opened already and then checks to see if that file
  2391. X *    was opened for reading or writing.  It stops files being read and
  2392. X *    written at the same time
  2393. X */
  2394. X
  2395. Xfopen()
  2396. X{
  2397. X    char    chblock[256];
  2398. X    register struct filebuf *p;
  2399. X    register struct filebuf *q;
  2400. X    register int     c;
  2401. X    int     i;
  2402. X    int     append=0;
  2403. X    int     bl = 0;
  2404. X    int     mode= _READ;
  2405. X    struct  stat    inod;
  2406. X
  2407. X    stringeval(chblock);
  2408. X    chblock[gcursiz]=0;
  2409. X    c=getch();
  2410. X    if(c== FOR){
  2411. X        c=getch();
  2412. X        if(c== OUTPUT)
  2413. X            mode = _WRITE;
  2414. X        else if(c== APPEND){
  2415. X            append++;
  2416. X            mode = _WRITE;
  2417. X        }
  2418. X        else if(c== TERMINAL)
  2419. X            mode = _TERMINAL;
  2420. X        else if(c != INPUT)
  2421. X            error(SYNTAX);
  2422. X        c=getch();
  2423. X    }
  2424. X    if(c!= AS)
  2425. X        error(SYNTAX);
  2426. X    i=evalint();
  2427. X#ifdef  _BLOCKED
  2428. X    if(getch() == ','){
  2429. X        bl = evalint();
  2430. X        if(bl <= 0 || bl > 255)
  2431. X            error(10);
  2432. X    }
  2433. X    else
  2434. X        point--;
  2435. X#endif
  2436. X    check();
  2437. X
  2438. X/* here we have mode set. i is the file descriptor 1-9
  2439. X   now check to see if already allocated then allocate the descriptor
  2440. X   and open file etc. */
  2441. X
  2442. X    if(i<1 || i>MAXFILES)
  2443. X        error(29);
  2444. X    for(q=0,p = (filebufp)filestart ; p < (filebufp)fendcore ; p++){
  2445. X        if(i== p->userfiledes)
  2446. X            error(29);
  2447. X        else if(!p->userfiledes && !q)
  2448. X            q=p;
  2449. X    }
  2450. X    if(!(p=q))              /* out of file descriptors */
  2451. X        error(31);
  2452. X
  2453. X/*   code to check to see if file is open twice */
  2454. X
  2455. X    if(stat(chblock,&inod)!= -1){
  2456. X        if( (inod.st_mode & S_IFMT) == S_IFDIR)
  2457. X            if(mode== _READ )  /* cannot deal with directories */
  2458. X                error(15);
  2459. X            else
  2460. X                error(14);
  2461. X        for(q = (filebufp)filestart ; q < (filebufp)fendcore ; q++)
  2462. X            if(q->userfiledes && q->inodnumber== inod.st_ino &&
  2463. X                        q->device== inod.st_dev){
  2464. X                if(mode== _READ ){
  2465. X                    if( q->use & mode )
  2466. X                        break;
  2467. X                    error(15);
  2468. X                }
  2469. X                else
  2470. X                    error(14);
  2471. X            }
  2472. X    }
  2473. X    else if(mode == _TERMINAL)              /* terminals */
  2474. X        error(15);
  2475. X    if(mode == _READ){
  2476. X        if( (p->filedes=open(chblock,0))== -1)
  2477. X            error(15);
  2478. X    }
  2479. X    else  if(mode == _TERMINAL){
  2480. X#ifdef  _BLOCKED                        /* can't block terminals */
  2481. X        if(bl)
  2482. X            error(15);
  2483. X#endif
  2484. X        if((p->filedes = open(chblock,2)) == -1)
  2485. X            error(15);
  2486. X        mode |= _READ | _WRITE;
  2487. X    }
  2488. X    else  {
  2489. X        if(append){
  2490. X            p->filedes=open(chblock,1);
  2491. X#ifndef V6C
  2492. X            lseek(p->filedes, 0L, 2);
  2493. X#else
  2494. X            seek(p->filedes,0,2);
  2495. X#endif
  2496. X        }
  2497. X        if(!append || p->filedes== -1)
  2498. X            if((p->filedes=creat(chblock,0644))== -1)
  2499. X                error(14);
  2500. X    }
  2501. X    p->posn = 0;
  2502. X    fstat(p->filedes,&inod);
  2503. X#ifdef  V7
  2504. X    ioctl(p->filedes,FIOCLEX,0);    /* close on exec */
  2505. X#endif
  2506. X    p->device= inod.st_dev;         /* fill in all relevent details */
  2507. X    p->inodnumber= inod.st_ino;
  2508. X    p->userfiledes= i;
  2509. X#ifdef  _BLOCKED
  2510. X    if(bl){
  2511. X        p->blocksiz = bl;
  2512. X        mode |= _BLOCKED;
  2513. X    }
  2514. X#endif
  2515. X    p->nleft=0;
  2516. X    p->use=mode;
  2517. X    normret;
  2518. X}
  2519. X
  2520. X/*      the 'close' command it runs through the list of file descriptors
  2521. X *    and flushes all buffers and closes the file and clears all
  2522. X *    relevent entry in the structure
  2523. X */
  2524. X
  2525. Xfclosef()
  2526. X{
  2527. X    register struct filebuf *p;
  2528. X    for(;;){
  2529. X        p=getf(evalint(),(_READ | _WRITE) );
  2530. X        if(p->use & _WRITE )
  2531. X            f_flush(p);
  2532. X        close(p->filedes);
  2533. X        p->filedes=0;
  2534. X        p->userfiledes=0;
  2535. X        p->nleft=0;
  2536. X        p->use=0;
  2537. X        if(getch()!=',')
  2538. X            break;
  2539. X    }
  2540. X    point--;
  2541. X    normret;
  2542. X}
  2543. X
  2544. X/* the 'seek' command thought to be neccasary
  2545. X */
  2546. X
  2547. Xfseek()
  2548. X{
  2549. X    register struct filebuf *p;
  2550. X    register int    j;
  2551. X    register long    l;
  2552. X
  2553. X    if(getch() != '#')
  2554. X        error(SYNTAX);
  2555. X    p = getf(evalint(),(_READ | _WRITE));   /* get file */
  2556. X    if(getch() != ',')
  2557. X        error(SYNTAX);
  2558. X    eval();
  2559. X    if(getch() != ',')
  2560. X        error(SYNTAX);
  2561. X    if(!vartype && conv(&res))
  2562. X        error(FUNCT);
  2563. X#ifdef  _BLOCKED
  2564. X    if(p->use & _BLOCKED)
  2565. X#ifndef pdp11
  2566. X        l = res.i * p->blocksiz;
  2567. X#else
  2568. X        { register k = 0;                 /* fast multiply for non */
  2569. X        for(l = 0 ; k < 8 ; k++)             /* vax systems. this */
  2570. X            if(p->blocksiz & (1<<k) )    /* won't bring in the */
  2571. X                l += (long)res.i << k;  /* library */
  2572. X        }
  2573. X#endif
  2574. X    else                    /* watch this. note the indents */
  2575. X#endif                          /* it is right */
  2576. X    l = res.i;
  2577. X    j = evalint();
  2578. X    check();
  2579. X    if(j < 0 || j > 5)      /* out of range */
  2580. X        error(FUNCT);
  2581. X    if(p->use & _WRITE)     /* flush out all buffered output */
  2582. X        f_flush(p);
  2583. X    if(j >=3){
  2584. X        j -= 3;
  2585. X        l <<= 10;       /* blocks are 1024 */
  2586. X    }
  2587. X#ifndef V6C
  2588. X    lseek(p->filedes, l ,j);
  2589. X#else
  2590. X    if(l > 512)
  2591. X        seek(p->filedes, (int)(l >> 9) , j + 3);
  2592. X    seek(p->filedes,(int)l & 0777 ,j);
  2593. X#endif
  2594. X    p->posn = 0;
  2595. X    p->nleft = 0;
  2596. X    p->use &= ~_EOF;
  2597. X    normret;
  2598. X}
  2599. X
  2600. X
  2601. X/*      the 'eof' maths function eof is true if writting to the file
  2602. X *    or if the _EOF flag is set.
  2603. X */
  2604. X
  2605. Xeofl()
  2606. X{
  2607. X    register struct filebuf *p;
  2608. X
  2609. X    p=getf(evalint(),(_READ | _WRITE) );
  2610. X    vartype=01;
  2611. X    if( p->use & ( _EOF | _WRITE) ){
  2612. X        res.i = -1;
  2613. X        return;
  2614. X    }
  2615. X    if(!p->nleft){
  2616. X        p->posn = 0;
  2617. X        if( (p->nleft= read(p->filedes,p->buf,BLOCKSIZ)) <= 0){
  2618. X            p->nleft=0;
  2619. X            p->use |= _EOF;
  2620. X            res.i = -1;
  2621. X            return;
  2622. X        }
  2623. X    }
  2624. X    res.i =0;
  2625. X}
  2626. X
  2627. X/*      the 'posn' maths function returns the current 'virtual' cursor
  2628. X *    in the file. If the file descriptor is zero then the screen
  2629. X *    cursor is accessed.
  2630. X */
  2631. X
  2632. Xfposn()
  2633. X{
  2634. X    register struct filebuf *p;
  2635. X    register i;
  2636. X
  2637. X    i=evalint();
  2638. X    vartype=01;
  2639. X    if(!i){
  2640. X        res.i =cursor;
  2641. X        return;
  2642. X    }
  2643. X    p=getf(i,(_READ | _WRITE) );
  2644. X    if(p->use & _WRITE)
  2645. X        res.i = p->posn;
  2646. X    else
  2647. X        res.i = 0;
  2648. X}
  2649. X
  2650. X/*      getf() returns a pointer to a file buffer structure. with the
  2651. X *    relevent file descriptor and with the relevent access permissions
  2652. X */
  2653. X
  2654. Xstruct  filebuf *
  2655. Xgetf(i,j)
  2656. Xregister i;     /* file descriptor */
  2657. Xregister j;     /* access permission */
  2658. X{
  2659. X    register struct filebuf *p;
  2660. X
  2661. X    if(i == 0)
  2662. X        error(29);
  2663. X    j &= ( _READ | _WRITE ) ;
  2664. X    for(p= (filebufp)filestart ; p < (filebufp)fendcore ; p++)
  2665. X        if(p->userfiledes==i && ( p->use & j) )
  2666. X            return(p);
  2667. X    error(29);      /* unknown file descriptor */
  2668. X}
  2669. X
  2670. X/*      flushes the file pointed to by p */
  2671. X
  2672. Xf_flush(p)
  2673. Xregister struct filebuf *p;
  2674. X{
  2675. X    if(p->nleft ){
  2676. X        write(p->filedes,p->buf,p->nleft);
  2677. X        p->nleft=0;
  2678. X    }
  2679. X}
  2680. X
  2681. X/*      will flush all files , for use in 'shell' and in quit */
  2682. X
  2683. Xflushall()
  2684. X{
  2685. X    register struct filebuf *p;
  2686. X    for(p = (filebufp)filestart ; p < (filebufp)fendcore ; p++)
  2687. X        if(p->nleft && ( p->use & _WRITE ) ){
  2688. X            write(p->filedes,p->buf,p->nleft);
  2689. X            p->nleft=0;
  2690. X        }
  2691. X}
  2692. X
  2693. X/*      closes all files and clears the relevent bits of info
  2694. X *    used in clear and new.
  2695. X */
  2696. X
  2697. Xcloseall()
  2698. X{
  2699. X    register struct filebuf *p;
  2700. X    flushall();
  2701. X    for(p= (filebufp)filestart ; p < (filebufp)fendcore ; p++)
  2702. X        if(p->userfiledes){
  2703. X            close(p->filedes);
  2704. X            p->filedes=0;
  2705. X            p->userfiledes=0;
  2706. X            p->nleft=0;
  2707. X            p->use=0;
  2708. X        }
  2709. X}
  2710. X
  2711. X/*      write to a file , same as write in parameters (see print )
  2712. X */
  2713. X
  2714. Xputfile(p,q,i)
  2715. Xregister struct filebuf *p;
  2716. Xregister char   *q;
  2717. Xint     i;
  2718. X{
  2719. X    register char   *r;
  2720. X    if(!i)
  2721. X        return;
  2722. X    r= &p->buf[p->nleft];
  2723. X    do{
  2724. X        if(p->nleft >= BLOCKSIZ ){
  2725. X            f_flush(p);
  2726. X            r= p->buf;
  2727. X        }
  2728. X        *r++ = *q++;
  2729. X        p->nleft++;
  2730. X    }while(--i);
  2731. X    if(p->use & _TERMINAL)
  2732. X        f_flush(p);
  2733. X}
  2734. X
  2735. X/* gets a line into q (MAX 512 or j) from file p terminating with '\n'
  2736. X * or _EOF returns number of characters read.
  2737. X */
  2738. X
  2739. Xfilein(p,q,j)
  2740. Xregister struct filebuf *p;
  2741. Xregister char *q;
  2742. X{
  2743. X    register char   *r;
  2744. X    register int     i=0;
  2745. X
  2746. X    if(p->use & _TERMINAL)          /* kludge for terminal files */
  2747. X        p->use &= ~_EOF;
  2748. X    else if(p->use & _EOF)
  2749. X        return(0);              /* end of file */
  2750. X#ifdef  _BLOCKED
  2751. X    if(p->use & _BLOCKED)
  2752. X        j = p->blocksiz;
  2753. X#endif
  2754. X    r= &p->buf[p->posn];
  2755. X    for(;;){
  2756. X        if(!p->nleft){
  2757. X            r=p->buf;
  2758. X            if( (p->nleft= read(p->filedes,p->buf,BLOCKSIZ)) <=0){
  2759. X                p->nleft=0;     /* a read error */
  2760. X                p->use |= _EOF; /* or end of file */
  2761. X                break;
  2762. X            }
  2763. X        }
  2764. X        *q= *r++;
  2765. X        p->nleft--;
  2766. X        if(++i == j){
  2767. X            q++;
  2768. X            break;
  2769. X        }
  2770. X#ifdef  _BLOCKED
  2771. X        if(*q++ == '\n' && !(p->use & _BLOCKED) ){
  2772. X#else
  2773. X        if(*q++ =='\n'){
  2774. X#endif
  2775. X            q--;
  2776. X            break;
  2777. X        }
  2778. X        if(i>=512){             /* problems */
  2779. X            p->posn= r - p->buf;
  2780. X            error(32);
  2781. X        }
  2782. X    }                               /* end of for loop */
  2783. X    *q=0;
  2784. X    if(p->use & _TERMINAL){
  2785. X        p->nleft = 0;
  2786. X        p->posn = 0;
  2787. X    }
  2788. X    else
  2789. X        p->posn = r - p->buf;
  2790. X#ifdef  _BLOCKED
  2791. X    if( (p->use & _BLOCKED) && j != i){
  2792. X        p->use |= _EOF;
  2793. X        p->nleft = 0;
  2794. X        return(0);
  2795. X    }
  2796. X#endif
  2797. X    return(i);
  2798. X}
  2799. End of bas6.c
  2800. chmod u=rw-,g=r,o=r bas6.c
  2801.  
  2802.