home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / language / icon / Source / Iconx / C / Rlocal < prev    next >
Encoding:
Text File  |  1990-07-19  |  23.8 KB  |  1,007 lines

  1. /*
  2.  * Routines needed for different systems.
  3.  */
  4.  
  5. #include <math.h>
  6. #include "../h/config.h"
  7. #include "../h/rt.h"
  8. #include "rproto.h"
  9. #include <ctype.h>
  10.  
  11. /*
  12.  * The following code is operating-system dependent [@rlocal.01].
  13.  *  Routines needed by different systems.
  14.  */
  15.  
  16. #if PORT
  17.    /* place for anything system-specific */
  18. Deliberate Syntax Error
  19. #endif                    /* PORT */
  20.  
  21. #if ARM
  22. #include "kernel.h"
  23.  
  24. int unlink (const char *name)
  25. {
  26.     _kernel_osfile_block blk;
  27.  
  28.     return (_kernel_osfile(6,name,&blk) <= 0);
  29. }
  30.  
  31. int getch (void)
  32. {
  33.     return _kernel_osrdch();
  34. }
  35.  
  36. int getche (void)
  37. {
  38.     int ch = _kernel_osrdch();
  39.  
  40.     _kernel_oswrch(ch);
  41.  
  42.     return ch;
  43. }
  44.  
  45. int kbhit (void)
  46. {
  47.     return ((_kernel_osbyte(152,0,0) & 0x00FF0000) != 0x00010000);
  48. }
  49.  
  50. char *ecvt(double number, int ndigit, int *decpt, int *sign)
  51. {
  52.     int n = 0;
  53.     static char buf[30];
  54.  
  55.     /* Sort out the sign */
  56.     if (number >= 0)
  57.         *sign = 0;
  58.     else
  59.     {
  60.         *sign = 1;
  61.         number = -number;
  62.     }
  63.  
  64.     /* Normalise the number to 0.1 <= number < 1, setting decpt */
  65.     if (number >= 1)
  66.     {
  67.         while (number >= 1)
  68.         {
  69.             ++n;
  70.             number /= 10.0;
  71.         }
  72.     }
  73.     else if (number != 0.0 && number < 0.1)
  74.     {
  75.         while (number < 0.1)
  76.         {
  77.             --n;
  78.             number *= 10.0;
  79.         }
  80.     }
  81.     *decpt = n;
  82.  
  83.     sprintf(buf, "%#.*f", ndigit, number);
  84.  
  85.     /* Skip the leading "0." */
  86.     return (buf+2);
  87. }
  88. #endif
  89.  
  90. #if AMIGA
  91. #if AZTEC_C
  92. /*
  93.  * abs
  94.  */
  95. abs(i)
  96. int i;
  97. {
  98.     return ((i<0)? (-i) : i);
  99. }
  100.  
  101. /*
  102.  * ldexp
  103.  */
  104. double ldexp(value,exp)
  105. double value;
  106. {
  107.   double retval = 1.0;
  108.   if(exp>0) {
  109.     while(exp-->0) retval *= 2.0;
  110.   } else if (exp<0) {
  111.     while(exp++<0) retval = retval / 2.0;
  112.   }
  113.   return value * retval;
  114. }
  115.  
  116. /*
  117.  *  abort()
  118.  */
  119. novalue abort()
  120. {
  121.   fprintf(stderr,"ICON ERROR WITH ICONCORE SET\n");
  122.   fflush(stderr);
  123.   exit(1);
  124. }
  125.  
  126. #ifdef SystemFnc
  127.  
  128. /*
  129.  * Aztec C version 3.6 does not support system(), but here is a substitute.
  130.  * This is a bonafide untested-original-it-just-compiles routine.
  131.  * Manx will probably implement system() before we fix this version...
  132.  */
  133. #include <ctype.h>
  134.  
  135. #define KLUDGE1 256
  136. #define KLUDGE2 64
  137. int system(s)
  138. char *s;
  139. {
  140.    char text[KLUDGE1], *cp=text;
  141.    char **av[KLUDGE2];
  142.    int ac = 0;
  143.    int l  = strlen(s);
  144.  
  145.    if (l >= KLUDGE1)
  146.       return -1;
  147.    strcpy(text,s);
  148.    av[ac++] = text;
  149.    while(*cp && ac<KLUDGE2-1) {
  150.       if (isspace(*cp)) {
  151.          *cp++ = '\0';
  152.      while(isspace(*cp))
  153.         cp++;
  154.          if (*cp)
  155.         av[ac++] = cp;
  156.          }
  157.       else {
  158.          cp++;
  159.          }
  160.       }
  161.     av[ac] = NULL;
  162.     return fexecv(av[0], av);
  163. }
  164. #endif                    /* SystemFnc */
  165. #endif                    /* AZTEC_C */
  166. #endif                    /* AMIGA */
  167.  
  168. #if ATARI_ST
  169. #if LATTICE
  170.  
  171. long _STACK = 10240;
  172. long _MNEED = 200000;    /* reserve space for allocation (may be too large) */
  173.  
  174. #include <osbind.h>
  175.  
  176. /*  Structure necessary for handling system time. */
  177.    struct tm {
  178.        short tm_year;
  179.        short tm_mon;
  180.        short tm_wday;
  181.        short tm_mday;
  182.        short tm_hour;
  183.        short tm_min;
  184.        short tm_sec;
  185.    };
  186.  
  187. struct tm *localtime(clock)   /* fill structure with clock time */
  188. int clock;     /* millisecond timer value, if supplied; not used */
  189. {
  190.   static struct tm tv;
  191.   unsigned int time, date;
  192.  
  193.   time = Tgettime();
  194.   date = Tgetdate();
  195.   tv.tm_year = ((date >> 9) & 0x7f) + 80;
  196.   tv.tm_mon  = ((date >> 5) & 0xf) - 1;
  197.   tv.tm_mday = date & 0x1f;
  198.   tv.tm_hour = (time >> 11) & 0x1f;
  199.   tv.tm_min  = (time >> 5)  & 0x3f;
  200.   tv.tm_sec  = 2 * (time & 0x1f);
  201.  
  202.   tv.tm_wday = weekday(tv.tm_mday,tv.tm_mon+1,tv.tm_year);
  203.   return(&tv);
  204. }
  205.  
  206.  
  207. weekday(day,month,year)   /* find day of week from    */
  208. short day, month, year;   /* day, month, and year     */
  209. {                         /* Sunday..Saturday is 0..6 */
  210.   int index, yrndx, mondx;
  211.  
  212.   if(month <= 2) {   /* Jan or Feb month adjust */
  213.       month += 12;
  214.       year  -=  1;
  215.   }
  216.  
  217.   yrndx = year + (year / 4) - (year / 100) + (year / 400);
  218.   mondx = 2 * month + (3 * (month + 1)) / 5;
  219.   index = day + mondx + yrndx + 2;
  220.   return(index % 7);
  221. }
  222.  
  223.  
  224.  
  225. time(ptime)   /* return value of millisecond timer */
  226. int  *ptime;
  227. {
  228.   int  tmp, ssp;   /* value of supervisor stack pointer */
  229.   static int  *tmr = (int *) 0x04ba;   /* addr of timer */
  230.  
  231.   ssp = gemdos(0x20,0);   /* enter supervisor mode */
  232.   tmp = *tmr * 5;         /* get millisecond timer */
  233.   ssp = gemdos(0x20,ssp); /* enter programmer mode */
  234.  
  235.   if(ptime != NULL)
  236.       *ptime = tmp;
  237.  
  238.   return(tmp);
  239. }
  240.  
  241. int brk(p)
  242. char *p;
  243. {
  244.   char *sbrk();
  245.   long int l, m;
  246.  
  247.   l = (long int)p;
  248.   m = (long int)sbrk(0);
  249.  
  250.   return((lsbrk((long) (l - m)) == 0) ? -1 : 0);
  251. }
  252.  
  253.  
  254. #ifdef LocalQsort
  255. /* Shell sort with some enhancements from Knuth.. */
  256.  
  257. void qsort( base, nel, width, cmp )   /* was llqsort( ... */
  258. char *base;                           /*-also kqsort( ...-*/
  259. int nel;
  260. int width;
  261. int (*cmp)();
  262. {
  263.    register int i, j;
  264.    long int gap;
  265.    int k, tmp ;
  266.    char *p1, *p2;
  267.  
  268.    for( gap=1; gap <= nel; gap = 3*gap + 1 ) ;
  269.  
  270.    for( gap /= 3;  gap > 0  ; gap /= 3 )
  271.        for( i = gap; i < nel; i++ )
  272.            for( j = i-gap; j >= 0 ; j -= gap ) {
  273.                 p1 = base + ( j     * width);
  274.                 p2 = base + ((j+gap) * width);
  275.  
  276.                 if( (*cmp)( p1, p2 ) <= 0 ) break;
  277.  
  278.                 for( k = width; --k >= 0 ;) {
  279.                    tmp   = *p1;
  280.                    *p1++ = *p2;
  281.                    *p2++ = tmp;
  282.                 }
  283.            }
  284. }
  285. #endif                    /* LocalQsort */
  286.  
  287. #endif                    /* LATTICE */
  288. #endif                    /* ATARI_ST */
  289.  
  290. #if HIGHC_386
  291. #endif                    /* HIGHC_386 */
  292.  
  293. #if MACINTOSH
  294. #if MPW
  295. /*
  296. **  Special routines for Macintosh Programmer's Workshop
  297. **  implementation of the Icon Programming Language
  298. */
  299.  
  300. #include <Types.h>
  301. #include <Events.h>
  302. #include <OSUtils.h>
  303. #define MaxBlockX MaxBlock /* MaxBlock Icon definition conflicts */
  304. #undef MaxBlock           /* with Mac Toolbox routine */
  305. #include <Memory.h>
  306. #define MaxBlock MaxBlockX
  307. #undef MaxBlockX
  308. #include <Errors.h>
  309.  
  310. /*
  311. **  Initialization and Termination Routines
  312. */
  313. /*
  314. **  MacExit -- This function is installed by an onexit() call in MacInit
  315. **  -- it is called automatically when the program terminates.
  316. */
  317. void
  318. MacExit()
  319. {
  320.   void ResetStack();
  321.   extern Ptr MemBlock;
  322.  
  323.   ResetStack();
  324.   if (MemBlock != NULL) DisposPtr(MemBlock);
  325. }
  326.  
  327. /*
  328. **  MacInit -- This function is called near the beginning of execution of
  329. **  iconx.  It is called by our own brk/sbrk initialization routine.
  330. */
  331. void
  332. MacInit()
  333. {
  334.   atexit(MacExit);
  335. }
  336.  
  337.  
  338. /*
  339. **  Brk and Sbrk Equivalents
  340. */
  341.  
  342. typedef Ptr caddr_t;
  343.  
  344. static caddr_t MemBlock, Break, Limit;
  345. word xcodesize;
  346.  
  347. init_brk()
  348. {
  349.   static short init = 0;
  350.   Size max, grow, size;
  351.   char *v;
  352.   extern word mstksize, statsize, ssize, abrsize;
  353.  
  354.   if (!init) {
  355.     init = 1;
  356.     MacInit();
  357.     if ((v = getenv("ICONSIZE")) != NULL) {    /* if ICONSIZE defined */
  358.       if ((size = atol(v)) <= 0) {        /* if ICONSIZE negative */
  359.     max = MaxMem(&grow);
  360.     size = max + grow - (size < 0 ? -size : max / 4);
  361.       }
  362.     }
  363.     else {                    /* if ICONSIZE undefined */
  364.       size = xcodesize + mstksize + statsize + ssize + abrsize + 512;
  365.     }
  366.     if ((MemBlock = NewPtr(size)) == NULL) {
  367.       syserr("problem allocating Mac memory");
  368.     }
  369.     Break = MemBlock;
  370.     Limit = MemBlock + size;
  371.   }
  372.   return 1;
  373. }
  374.  
  375. caddr_t
  376. brk(addr)
  377. caddr_t addr;
  378. {
  379.   Size newsize;
  380.  
  381.   if (!init_brk()) return (caddr_t)-1;
  382.   if (addr < MemBlock) return (caddr_t)-1;
  383.   if (addr < Limit) Break = addr;
  384.   else {
  385.     newsize = addr - MemBlock;
  386.     SetPtrSize(MemBlock, newsize);
  387.     if (MemError() != noErr) return (caddr_t)-1;
  388.     Break = Limit = addr;
  389.   }
  390.   return (caddr_t)0;
  391. }
  392.  
  393. caddr_t
  394. sbrk(incr)
  395. int incr;
  396. {
  397.   caddr_t start;
  398.  
  399.   if (!init_brk()) return (caddr_t)-1;
  400.   start = Break;
  401.   if (incr != 0) {
  402.     if (brk(start + incr) == (caddr_t)-1) return (caddr_t)-1;
  403.   }
  404.   return start;
  405. }
  406.  
  407. #endif                    /* MPW */
  408. #endif                    /* MACINTOSH */
  409.  
  410. #if MSDOS
  411.  
  412. #if TURBO
  413. extern unsigned _stklen = 8 * 1024;
  414. #endif                    /* TURBO */
  415.  
  416. #if LATTICE
  417.  
  418. #include <error.h>
  419.  
  420. int _stack = (8 * 1024);
  421. long int _mneed = (20 * 1024);
  422.  
  423. extern long int *sp;
  424. long int **xsp = &sp;  /* Used for rswitch.asm .. since 'sp' is a reserved */
  425.                /* symbol for the assembler.. */
  426.  
  427. extern char *statend;  /* Indicator for when to use malloc for _GETBF */
  428.  
  429. int brk(p)
  430. char *p;
  431. {
  432.    char *sbrk();
  433.    long int l, m;
  434.  
  435.    l = (long int)p;
  436.    m = (long int)sbrk((word)0);
  437.  
  438.    if( lsbrk((long) (l - m) ) == 0) return -1;
  439.    else return 0;
  440. }
  441.  
  442. novalue abort()    /* Abort set to 'dump' icon data area.. */
  443. {
  444. #ifdef DeBugIconx
  445.    blkdump();
  446. #endif                    /* DeBugIconx */
  447.    fflush(stderr);
  448.    fcloseall();
  449.    _exit(1);
  450. }
  451. #endif                    /* LATTICE */
  452. #endif                    /* MSDOS */
  453.  
  454. #if MVS || VM
  455. #if SASC
  456. #include <options.h>
  457. char _linkage = _OPTIMIZE;
  458.  
  459. #if MVS
  460. char *_style = "tso:";          /* use dsnames as file names */
  461. #define SYS_OSVS
  462. #else                    /* MVS */
  463. #define SYS_CMS
  464. #endif                    /* MVS */
  465. int _mneed = 512000;            /* size of sbrk-managed region */
  466.  
  467. #define RES_SIGNAL
  468. #define RES_COPROC
  469. #define RES_IOUTIL
  470. #define RES_DSNAME
  471. #define RES_FILEDEF
  472. #define RES_UNITREC
  473. #if VM
  474. #define BIMODAL_CMS
  475. #endif                    /* VM */
  476.  
  477. #include <resident.h>
  478.  
  479. #endif                    /* SASC */
  480. #ifdef WATERLOO_C_V3_0
  481. const int _staksize = (64*1024);
  482. #endif                    /* WATERLOO_C_V3_0 */
  483. #endif                    /* MVS || VM */
  484.  
  485. #if OS2
  486. novalue abort()
  487. {
  488. #ifdef DeBugIconx
  489.     blkdump();
  490. #endif
  491.     fflush(stderr);
  492.     fcloseall();
  493.     _exit(1);
  494. }
  495. /* Pipe support for OS/2 */
  496. #include <stddef.h>
  497. #include <process.h>
  498. #include <errno.h>
  499.  
  500. #define INCL_DOS
  501. #include <os2.h>
  502.  
  503. static int _pipes[_NFILE];
  504.  
  505. /*
  506.  * popen("command",mode)
  507.  *
  508.  * mode = "r" | "w"
  509.  */
  510. FILE *
  511. popen(cmd, mode)
  512. char *cmd;
  513. char *mode;
  514. {
  515.  
  516.     int whandle, rhandle;
  517.     int phandle, chandle, shandle;
  518.     int rc;
  519.  
  520.     /* Validate */
  521.     if(cmd == NULL || mode == NULL) return NULL;
  522.     if(tolower(*mode) != 'r' && tolower(*mode) != 'w')
  523.     return NULL;
  524.  
  525.     /* Create the pipe */
  526.     if (DosMakePipe(&rhandle, &whandle, BUFSIZ) < 0)
  527.     return NULL;
  528.  
  529.     /* Dup STDIN or STDOUT to the pipe */
  530.     if (*mode == 'r') {
  531.     /* Dup stdout */
  532.     phandle = rhandle;
  533.     chandle = whandle;
  534.     shandle = dup(1);    /* Save STDOUT */
  535.     rc = dup2(chandle, 1);
  536.     } else {
  537.     /* Dup stdin */
  538.     phandle = whandle;
  539.     chandle = rhandle;
  540.     shandle = dup(0);    /* Save STDIN */
  541.     rc = dup2(chandle, 0);
  542.     }
  543.     if (rc < 0) {
  544.     perror("dup2");
  545.     return NULL;
  546.     }
  547.     close(chandle);
  548.  
  549.     /* Make sure that we don't pass this handle on */
  550.     DosSetFHandState(phandle, OPEN_FLAGS_NOINHERIT);
  551.  
  552.     /* Invoke the child, remember its processid */
  553.     _pipes[chandle] = spawnlp(P_NOWAIT, cmd, cmd, NULL);
  554.  
  555.     /* Clean up by reestablishing our STDIN/STDOUT */
  556.     if (*mode == 'r')
  557.     rc = dup2(shandle, 1);
  558.     else
  559.     rc = dup2(shandle, 0);
  560.     if (rc < 0) {
  561.     perror("dup2");
  562.     return NULL;
  563.     }
  564.     close(shandle);
  565.  
  566.     return fdopen(phandle, mode);
  567. }
  568. pclose(ptr)
  569. FILE *ptr;
  570. {
  571.     int status, pnum;
  572.  
  573.     pnum = fileno(ptr);
  574.     fclose(ptr);
  575.  
  576.     /* Now wait for child to end */
  577.     cwait(&status, _pipes[pnum], WAIT_GRANDCHILD);
  578.  
  579.     return status;
  580. }
  581.  
  582. /* End of pipe support for OS/2 */
  583. #endif                    /* OS2 */
  584.  
  585. #if UNIX
  586. #ifdef ATTM32
  587.  
  588. /*
  589.  * This file contains the routine necessary to allocate legal AT&T
  590.  * 3B2/15/4000 stack space for co-expression stacks.
  591.  *
  592.  * Legal stack region begins at 0xC0020000, and UNIX will grow stack space
  593.  * up to 50 Megabytes. 0xC0030000 should provide plenty of room for
  594.  * main C stack growth.  Each time coexpr_salloc() is called, it
  595.  * adds mstksize (max main stack size) and returns a new address,
  596.  * meaning each coexpression stack is potentially as large as the main stack.
  597.  */
  598.  
  599. /*
  600.  * coexp_salloc() - return pointer in legal stack space for start
  601.  *                  of a coexpression stack.
  602.  */
  603.  
  604. pointer coexp_salloc()
  605.    {
  606.    static pointer sp = 0xC0030000 ;     /* pointer to stack region */
  607.  
  608.    sp +=  mstksize;
  609.    return sp;
  610. }
  611. #endif                    /* ATTM32 */
  612. #if CONVEX
  613.  
  614. /* replacement pow() that allows negative ** integer */
  615.  
  616. #undef pow
  617.  
  618. double pow0 (base, exp)
  619.     double base, exp;
  620. {   if (base >= 0) return pow (base, exp);
  621.     else {
  622.     long n = exp;
  623.     if (n != exp) runerr (-206, 0);
  624.     else if (n & 1) return -pow (-base, exp);
  625.     else return pow (-base, exp);}}
  626. #endif                    /* CONVEX */
  627.  
  628. #endif                    /* UNIX */
  629.  
  630. #if VMS
  631. #include dvidef
  632. #include iodef
  633.  
  634. typedef struct _descr {
  635.    int length;
  636.    char *ptr;
  637. } descriptor;
  638.  
  639. typedef struct _pipe {
  640.    long pid;            /* process id of child */
  641.    long status;            /* exit status of child */
  642.    long flags;            /* LIB$SPAWN flags */
  643.    int channel;            /* MBX channel number */
  644.    int efn;            /* Event flag to wait for */
  645.    char mode;            /* the open mode */
  646.    FILE *fptr;            /* file pointer (for fun) */
  647.    unsigned running : 1;    /* 1 if child is running */
  648. } Pipe;
  649.  
  650. Pipe _pipes[_NFILE];        /* one for every open file */
  651.  
  652. #define NOWAIT        1
  653. #define NOCLISYM    2
  654. #define NOLOGNAM    4
  655. #define NOKEYPAD    8
  656. #define NOTIFY        16
  657. #define NOCONTROL    32
  658. #define SFLAGS    (NOWAIT|NOKEYPAD|NOCONTROL)
  659.  
  660. /*
  661.  * popen - open a pipe command
  662.  * Last modified 2-Apr-86/chj
  663.  *
  664.  *    popen("command", mode)
  665.  */
  666.  
  667. FILE *popen(cmd, mode)
  668. char *cmd;
  669. char *mode;
  670. {
  671.    FILE *pfile;            /* the Pfile */
  672.    Pipe *pd;            /* _pipe database */
  673.    descriptor mbxname;        /* name of mailbox */
  674.    descriptor command;        /* command string descriptor */
  675.    descriptor nl;        /* null device descriptor */
  676.    char mname[65];        /* mailbox name string */
  677.    int chan;            /* mailbox channel number */
  678.    int status;            /* system service status */
  679.    int efn;
  680.    struct {
  681.       short len;
  682.       short code;
  683.       char *address;
  684.       char *retlen;
  685.       int last;
  686.    } itmlst;
  687.  
  688.    if (!cmd || !mode)
  689.       return (0);
  690.    LIB$GET_EF(&efn);
  691.    if (efn == -1)
  692.       return (0);
  693.    if (_tolower(mode[0]) != 'r' && _tolower(mode[0]) != 'w')
  694.       return (0);
  695.    /* create and open the mailbox */
  696.    status = SYS$CREMBX(0, &chan, 0, 0, 0, 0, 0);
  697.    if (!(status & 1)) {
  698.       LIB$FREE_EF(&efn);
  699.       return (0);
  700.    }
  701.    itmlst.last = mbxname.length = 0;
  702.    itmlst.address = mbxname.ptr = mname;
  703.    itmlst.retlen = &mbxname.length;
  704.    itmlst.code = DVI$_DEVNAM;
  705.    itmlst.len = 64;
  706.    status = SYS$GETDVIW(0, chan, 0, &itmlst, 0, 0, 0, 0);
  707.    if (!(status & 1)) {
  708.       LIB$FREE_EF(&efn);
  709.       return (0);
  710.    }
  711.    mname[mbxname.length] = '\0';
  712.    pfile = fopen(mname, mode);
  713.    if (!pfile) {
  714.       LIB$FREE_EF(&efn);
  715.       SYS$DASSGN(chan);
  716.       return (0);
  717.    }
  718.    /* Save file information now */
  719.    pd = &_pipes[fileno(pfile)];    /* get Pipe pointer */
  720.    pd->mode = _tolower(mode[0]);
  721.    pd->fptr = pfile;
  722.    pd->pid = pd->status = pd->running = 0;
  723.    pd->flags = SFLAGS;
  724.    pd->channel = chan;
  725.    pd->efn = efn;
  726.    /* fork the command */
  727.    nl.length = strlen("_NL:");
  728.    nl.ptr = "_NL:";
  729.    command.length = strlen(cmd);
  730.    command.ptr = cmd;
  731.    status = LIB$SPAWN(&command,
  732.       (pd->mode == 'r') ? 0 : &mbxname,    /* input file */
  733.       (pd->mode == 'r') ? &mbxname : 0,    /* output file */
  734.       &pd->flags, 0, &pd->pid, &pd->status, &pd->efn, 0, 0, 0, 0);
  735.    if (!(status & 1)) {
  736.       LIB$FREE_EF(&efn);
  737.       SYS$DASSGN(chan);
  738.       return (0);
  739.    } else {
  740.       pd->running = 1;
  741.    }
  742.    return (pfile);
  743. }
  744.  
  745. /*
  746.  * pclose - close a pipe
  747.  * Last modified 2-Apr-86/chj
  748.  *
  749.  */
  750. pclose(pfile)
  751. FILE *pfile;
  752. {
  753.    Pipe *pd;
  754.    int status;
  755.    int fstatus;
  756.  
  757.    pd = fileno(pfile) ? &_pipes[fileno(pfile)] : 0;
  758.    if (pd == NULL)
  759.       return (-1);
  760.    fflush(pd->fptr);            /* flush buffers */
  761.    fstatus = fclose(pfile);
  762.    if (pd->mode == 'w') {
  763.       status = SYS$QIOW(0, pd->channel, IO$_WRITEOF, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  764.       SYS$WFLOR(pd->efn, 1 << (pd->efn % 32));
  765.    }
  766.    SYS$DASSGN(pd->channel);
  767.    LIB$FREE_EF(&pd->efn);
  768.    pd->running = 0;
  769.    return (fstatus);
  770. }
  771.  
  772. /*
  773.  * redirect(&argc,argv,nfargs) - redirect standard I/O
  774.  *    int *argc        number of command arguments (from call to main)
  775.  *    char *argv[]    command argument list (from call to main)
  776.  *    int nfargs    number of filename arguments to process
  777.  *
  778.  * argc and argv will be adjusted by redirect.
  779.  *
  780.  * redirect processes a program's command argument list and handles redirection
  781.  * of stdin, and stdout.  Any arguments which redirect I/O are removed from the
  782.  * argument list, and argc is adjusted accordingly.  redirect would typically be
  783.  * called as the first statement in the main program.
  784.  *
  785.  * Files are redirected based on syntax or position of command arguments.
  786.  * Arguments of the following forms always redirect a file:
  787.  *
  788.  *    <file    redirects standard input to read the given file
  789.  *    >file    redirects standard output to write to the given file
  790.  *    >>file    redirects standard output to append to the given file
  791.  *
  792.  * It is often useful to allow alternate input and output files as the
  793.  * first two command arguments without requiring the <file and >file
  794.  * syntax.  If the nfargs argument to redirect is 2 or more then the
  795.  * first two command arguments, if supplied, will be interpreted in this
  796.  * manner:  the first argument replaces stdin and the second stdout.
  797.  * A filename of "-" may be specified to occupy a position without
  798.  * performing any redirection.
  799.  *
  800.  * If nfargs is 1, only the first argument will be considered and will
  801.  * replace standard input if given.  Any arguments processed by setting
  802.  * nfargs > 0 will be removed from the argument list, and again argc will
  803.  * be adjusted.  Positional redirection follows syntax-specified
  804.  * redirection and therefore overrides it.
  805.  *
  806.  */
  807.  
  808.  
  809. redirect(argc,argv,nfargs)
  810. int *argc, nfargs;
  811. char *argv[];
  812. {
  813.    int i;
  814.  
  815.    i = 1;
  816.    while (i < *argc)  {        /* for every command argument... */
  817.       switch (argv[i][0])  {        /* check first character */
  818.          case '<':            /* <file redirects stdin */
  819.             filearg(argc,argv,i,1,stdin,"r");
  820.             break;
  821.          case '>':            /* >file or >>file redirects stdout */
  822.             if (argv[i][1] == '>')
  823.                filearg(argc,argv,i,2,stdout,"a");
  824.             else
  825.                filearg(argc,argv,i,1,stdout,"w");
  826.             break;
  827.          default:            /* not recognized, go on to next arg */
  828.             i++;
  829.       }
  830.    }
  831.    if (nfargs >= 1 && *argc > 1)    /* if positional redirection & 1 arg */
  832.       filearg(argc,argv,1,0,stdin,"r");    /* then redirect stdin */
  833.    if (nfargs >= 2 && *argc > 1)    /* likewise for 2nd arg if wanted */
  834.       filearg(argc,argv,1,0,stdout,"w");/* redirect stdout */
  835. }
  836.  
  837.  
  838.  
  839. /* filearg(&argc,argv,n,i,fp,mode) - redirect and remove file argument
  840.  *    int *argc        number of command arguments (from call to main)
  841.  *    char *argv[]    command argument list (from call to main)
  842.  *    int n        argv entry to use as file name and then delete
  843.  *    int i        first character of file name to use (skip '<' etc.)
  844.  *    FILE *fp        file pointer for file to reopen (typically stdin etc.)
  845.  *    char mode[]    file access mode (see freopen spec)
  846.  */
  847.  
  848. filearg(argc,argv,n,i,fp,mode)
  849. int *argc, n, i;
  850. char *argv[], mode[];
  851. FILE *fp;
  852. {
  853.    if (strcmp(argv[n]+i,"-"))        /* alter file if arg not "-" */
  854.       fp = freopen(argv[n]+i,mode,fp);
  855.    if (fp == NULL)  {            /* abort on error */
  856.       fprintf(stderr,"%%can't open %s",argv[n]+i);
  857.       exit(ErrorExit);
  858.    }
  859.    for ( ;  n < *argc;  n++)        /* move down following arguments */
  860.       argv[n] = argv[n+1];
  861.    *argc = *argc - 1;            /* decrement argument count */
  862. }
  863.  
  864. /* Special versions of sbrk() and brk() for use by Icon under VMS.
  865.  * #defines in define.h actually rename these to vms_brk and vms_sbrk.
  866.  *
  867.  * For historical reasons, Icon assumes it can repeatedly call brk/sbrk
  868.  * and always get contiguous chunks.  This was made to work under Unix by
  869.  * overloading the definitions of malloc and friends, the only other callers
  870.  * of sbrk, and making them return Icon-managed memory.
  871.  
  872.  * Under VMS, sbrk is not the lowest-level system interface.  It gets memory
  873.  * from underlying VMS routines such as SYS$EXPREG.  These routines are also
  874.  * called by others, for example when a file is opened;  so successive sbrk
  875.  * calls may return nonadjacent chunks.  This makes overloading malloc and
  876.  * friends futile.
  877.  *
  878.  * The routines below replace sbrk and brk for Icon (only) under VMS.  They
  879.  * provide the continuously growing memory Icon needs without relying on
  880.  * special privileges or unusually large quotas.  Like the Unix solution and
  881.  * earlier VMS attempts, this is an empirical solution and may need further
  882.  * revision as the system changes.  But we hope not.
  883.  *
  884.  * The Icon interpreter is loaded beginning at address 0 and grows upward as
  885.  * it requests more memory through sbrk.  The C stack grows downward from
  886.  * 0x7FFFFFFF. We're going to draw a line to divide the address space, then
  887.  * force the C and VMS runtime systems to put anything they need above it;
  888.  * then sbrk can grow the program region unimpeded up to the line.
  889.  *
  890.  * The line is drawn MAXMEM bytes beyond the start of the sbrk region.  MAXMEM
  891.  * is an environment variable (logical name to VMS) with a default as given in
  892.  * define.h.  Large values cost CPU and real time expended at process exit; we
  893.  * don't know why.  On an 8600 the cost was very roughly .04 CP sec / megabyte.
  894.  *
  895.  * When first called, sbrk expands the program region by one page to get a
  896.  * starting address.  A limit address is calculated by adding MAXMEM.  A single
  897.  * page created just below the limit address "draws the line" and causes the
  898.  * VMS runtime system to allocate anything it needs above that point.  sbrk
  899.  * creates pages between base and limit as needed.
  900.  *
  901.  * Possible errors and their manifestations:
  902.  *
  903.  *    MAXMEM too large to initialize sbrk:
  904.  *       error in startup code: value of MAXMEM too large
  905.  *
  906.  *    MAXMEM too small to initialize sbrk:
  907.  *       error in startup code: value of MAXMEM too small
  908.  *
  909.  *    MAXMEM too small for subsequent brk/sbrk growth
  910.  *       Run-time error 351:  insufficient MAXMEM limit
  911.  *
  912.  *    MAXMEM okay but insufficient user quota for needed memory:
  913.  *       Run-time error 303:  unable to expand memory region
  914.  *
  915.  *    unexpected ("can't happen") failures of system calls:
  916.  *       these produce their standard VMS error message
  917.  *
  918.  *    unexpected intrusion into the sbrk region by the runtime system:
  919.  *       unknown, but undoubtedly ugly
  920.  */
  921.  
  922.  
  923. #define PageSize 512        /* size of a VMS page */
  924. #define MaxP0 0x40000000    /* first address beyond the P0 region */
  925.  
  926. #include <stsdef.h>
  927.  
  928. word memsize = MaxMem;        /* set from environment variable MAXMEM */
  929.  
  930.  
  931. /*  sbrk(incr) - adjust the break value by incr, rounding up to a page.
  932.  *  returns the new break value, or -1 if unsuccessful.
  933.  */
  934.  
  935. char *
  936. sbrk(incr)
  937. int incr;
  938. {
  939.    static char *base;        /* base of the sbrk region */
  940.    static char *curr;        /* current break value (end+1) */
  941.    static char *limit;        /* region limit ("the line") */
  942.    char *range[2], *p;        /* scratch for system calls */
  943.    int s;            /* status return from calls */
  944.  
  945.    /*  initialization code */
  946.    if (!base)  {
  947.       s = sys$expreg(1,range,0,0);    /* expand P0 to get base address */
  948.       if (!(s & STS$M_SUCCESS))
  949.          exit(s);            /* couldn't get one page?! */
  950.       base = curr = range[0];        /* initialize empty sbrk region */
  951.       memsize = (memsize + PageSize - 1) & -PageSize;
  952.                     /* round memsize to page boundary */
  953.       limit = base + memsize;        /* calculate sbrk region limit*/
  954.       if (limit > MaxP0)
  955.      limit = MaxP0;            /* limit to legal values */
  956.       if (limit <= base)
  957.          error("value of MAXMEM too small");  /* can't even start */
  958.       range[0] = range[1] = limit-1;
  959.       s = sys$cretva(range,range,0);    /* get a page there to draw the line */
  960.       if (!(s & STS$M_SUCCESS))
  961.          error("value of MAXMEM too large");  /* can't even start */
  962.    }
  963.  
  964.    if (incr > 0)  {
  965.  
  966.       /* grow the region */
  967.       if (curr + incr > limit)        /* check address space available */
  968.          fatalerr(-351,NULL);        /* oops, MAXMEM too small */
  969.       range[0] = curr;
  970.       range[1] = curr + incr - 1;
  971.       s = sys$cretva(range,range,0);    /* ask for the pages */
  972.       if (!(s & STS$M_SUCCESS))
  973.          return (char *) -1;        /* failed, quota exceeded */
  974.       curr = range[1] + 1;        /* set new break value as returned */
  975.  
  976.    } else if (incr < 0) {
  977.  
  978.       /* shrink the region (not expected to be used).  does not actually
  979.        * return the memory, but does make it available for reuse.  */
  980.       curr -= -incr & -PageSize;
  981.    }
  982.  
  983.    /* return the current break value */
  984.    return curr;
  985. }
  986.  
  987.  
  988.  
  989.  
  990. /*  brk(addr) - set the break address to the given value, rounded up to a page.
  991.  *  returns 0 if successful, -1 if not.
  992.  */
  993.  
  994. char *
  995. brk(addr)
  996. char *addr;
  997. {
  998.    return ((sbrk(addr-sbrk(0))) == (char *) -1 ? (char *) -1 : 0);
  999. }
  1000. #endif                    /* VMS */
  1001.  
  1002. /*
  1003.  * End of operating-system specific code.
  1004.  */
  1005.  
  1006. static char x;            /* avoid empty module */
  1007.