home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / runtime / rlocal.r < prev    next >
Text File  |  1996-03-22  |  42KB  |  1,899 lines

  1. /*
  2.  * File: rlocal.r
  3.  * Routines needed for different systems.
  4.  */
  5.  
  6. /*  IMPORTANT NOTE:  Because of the way RTL works, this file should not
  7.  *  contain any includes of system files, as in
  8.  *
  9.  *    include <foo>
  10.  *
  11.  *  Instead, such includes should be placed in h/sys.h.
  12.  */
  13.  
  14. /*
  15.  * The following code is operating-system dependent [@rlocal.01].
  16.  *  Routines needed by different systems.
  17.  */
  18.  
  19. #if PORT
  20.    /* place for anything system-specific */
  21. Deliberate Syntax Error
  22. #endif                    /* PORT */
  23.  
  24. #if AMIGA
  25. #if LATTICE
  26. long _STACK = 20000;
  27. long _MNEED = 200000;    /* reserve space for allocation (may be too large) */
  28. #endif                    /* LATTICE */
  29. #if AZTEC_C
  30. /*
  31.  * abs
  32.  */
  33. abs(i)
  34. int i;
  35. {
  36.     return ((i<0)? (-i) : i);
  37. }
  38.  
  39. /*
  40.  * ldexp
  41.  */
  42. double ldexp(value,exp)
  43. double value;
  44. {
  45.   double retval = 1.0;
  46.   if(exp>0) {
  47.     while(exp-->0) retval *= 2.0;
  48.   } else if (exp<0) {
  49.     while(exp++<0) retval = retval / 2.0;
  50.   }
  51.   return value * retval;
  52. }
  53.  
  54. /*
  55.  *  abort()
  56.  */
  57. novalue abort()
  58. {
  59.   fprintf(stderr,"icon error with ICONCORE set\n");
  60.   fflush(stderr);
  61.   exit(1);
  62. }
  63.  
  64. #ifdef SystemFnc
  65.  
  66. /*
  67.  * Aztec C version 3.6 does not support system(), but here is a substitute.
  68.  */
  69.  
  70. #define KLUDGE1 256
  71. #define KLUDGE2 64
  72. int system(s)
  73. char *s;
  74. {
  75.    char text[KLUDGE1], *cp=text;
  76.    char *av[KLUDGE2];
  77.    int ac = 0;
  78.    int l  = strlen(s);
  79.  
  80.    if (l >= KLUDGE1)
  81.       return -1;
  82.    strcpy(text,s);
  83.    av[ac++] = text;
  84.    while(*cp && ac<KLUDGE2-1) {
  85.       if (isspace(*cp)) {
  86.          *cp++ = '\0';
  87.      while(isspace(*cp))
  88.         cp++;
  89.          if (*cp)
  90.         av[ac++] = cp;
  91.          }
  92.       else {
  93.          cp++;
  94.          }
  95.       }
  96.     av[ac] = NULL;
  97.     return fexecv(av[0], av);
  98. }
  99. #endif                    /* SystemFnc */
  100. #endif                    /* AZTEC_C */
  101. #endif                    /* AMIGA */
  102.  
  103. #if ARM
  104. #include "kernel.h"
  105.  
  106. char *mktemp (const char *);
  107.  
  108. static char *strdup (const char *);
  109. static int os_cmd (char *);
  110. static int cmp_cmd (char *, char *);
  111.  
  112. #define MAX_PIPE 20
  113.  
  114. typedef enum
  115. {
  116.    unopened = 0,
  117.    reading,
  118.    writing
  119. }
  120. pipemode;
  121.  
  122. static struct pipe
  123. {
  124.    char *command;   /* The command being executed      */
  125.    char *name;   /* The name of the pipe file      */
  126.    FILE *fd;   /* The file used as a pipe      */
  127.    pipemode pmode;   /* The open mode of the pipe      */
  128.    int retval;   /* The return value of the command   */
  129. }
  130. pipes[MAX_PIPE];
  131.  
  132. FILE *popen (char *command, char *mode)
  133. {
  134.    FILE *current;
  135.    char *name;
  136.    int i;
  137.    pipemode curmode;
  138.    int rval = -1;
  139.    char tmp[11];
  140.  
  141.    /* decide on mode */
  142.    if ( mode[1] != 0 )
  143.       return NULL;
  144.    else if ( *mode == 'r' )
  145.       curmode = reading;
  146.    else if ( *mode == 'w' )
  147.       curmode = writing;
  148.    else
  149.       return NULL;
  150.  
  151.    /* Get a slot in the pipes structure */
  152.    for ( i = 0; i < MAX_PIPE; ++i )
  153.    {
  154.       if ( pipes[i].pmode == unopened )
  155.          break;
  156.    }
  157.  
  158.    if ( i >= MAX_PIPE )
  159.       return NULL;
  160.  
  161.    /* Get a file name to use */
  162.    sprintf(tmp, "Pipe%.2d", i);
  163.    name = mktemp(tmp);
  164.  
  165.    if ( name == NULL )
  166.       return NULL;
  167.  
  168.    /*
  169.     * If we're reading, just call system() to get a file filled
  170.     * with output.
  171.     */
  172.  
  173.    if ( curmode == reading )
  174.    {
  175.       char *tmpname;
  176.       int oscmd = os_cmd(command);
  177.       char cmd[256];
  178.       int n;
  179.  
  180.       if (*command == '%')
  181.       {
  182.          oscmd = 1;
  183.          ++command;
  184.       }
  185.  
  186.       if (!oscmd)
  187.       {
  188.          char *s;
  189.  
  190.          while (*command && isspace(*command))
  191.             ++command;
  192.  
  193.          s = command;
  194.  
  195.          while (*s && !isspace(*s))
  196.             ++s;
  197.          
  198.          n = sprintf(cmd, "%.*s > %s%s",
  199.             s - command, command, name, s);
  200.       }
  201.       else
  202.       {
  203.          tmpname = mktemp("PipeTmp");
  204.  
  205.          if (tmpname == NULL)
  206.          {
  207.             free(name);
  208.             return NULL;
  209.          }
  210.  
  211.          n = sprintf(cmd, "%s{ > %s }", command, tmpname);
  212.       }
  213.  
  214.       /* Emergency! Overflow in command buffer! */
  215.       if (n > 255)
  216.       {
  217.          if (oscmd)
  218.          {
  219.             remove(tmpname);
  220.             free(tmpname);
  221.          }
  222.          free(name);
  223.          return NULL;
  224.       }
  225.  
  226.       _kernel_setenv("Sys$ReturnCode", "0");
  227.       rval = system(cmd);
  228.  
  229.       if (rval == _kernel_ERROR)
  230.       {
  231.          remove(tmpname);
  232.          free(tmpname);
  233.          free(name);
  234.          return NULL;
  235.       }
  236.  
  237.       if (oscmd)
  238.       {
  239.          int ch;
  240.          FILE *in = fopen(tmpname, "r");
  241.          FILE *out = fopen(name, "w");
  242.  
  243.          if (in == NULL || out == NULL)
  244.          {
  245.             remove(tmpname);
  246.             free(tmpname);
  247.             free(name);
  248.             return NULL;
  249.          }
  250.  
  251.          /* Strip out CRs from the output */
  252.          while ((ch = getc(in)) != EOF && !ferror(out))
  253.          {
  254.             if (ch != '\r')
  255.                putc(ch, out);
  256.          }
  257.  
  258.          /* Did we succeed? */
  259.          ch = (ferror(in) || ferror(out));
  260.  
  261.          /* Tidy up */
  262.          fclose(in);
  263.          fclose(out);
  264.          remove(tmpname);
  265.          free(tmpname);
  266.  
  267.          if (ch)
  268.          {
  269.             free(name);
  270.             return NULL;
  271.          }
  272.       }
  273.  
  274.       if ( (current = fopen(name,"r")) == NULL )
  275.       {
  276.          free(name);
  277.          return NULL;
  278.       }
  279.    }
  280.    else
  281.    {
  282.       if ( (current = fopen(name,"w")) == NULL )
  283.       {
  284.          free(name);
  285.          return NULL;
  286.       }
  287.    }
  288.  
  289.    pipes[i].command = strdup(command);
  290.    pipes[i].name = name;
  291.    pipes[i].fd = current;
  292.    pipes[i].pmode = curmode;
  293.    pipes[i].retval = rval;
  294.    return current;
  295. }
  296.  
  297. #define ReadCat    5
  298.  
  299. /* Create a temporary file name by adding a directory prefix to file.
  300.  * If the external variable temp_dir is not zero, this directory will be
  301.  * used. Otherwise, the following are used, in order.
  302.  *   1. <Tmp$Dir>
  303.  *   2. &.Tmp
  304.  *   3. The current directory.
  305.  * The function returns zero on an error (temp_dir is not a directory, or
  306.  * malloc() failed), otherwise it returns a malloc-ed string containing
  307.  * the required name.
  308.  */
  309.  
  310. static char *concat (const char *dir, const char *file);
  311.  
  312. char *temp_dir = 0;
  313.  
  314. char *mktemp (const char *file)
  315. {
  316.    char *dir;
  317.    char *name;
  318.    char buf[11];
  319.    int len = strlen(file);
  320.    _kernel_osfile_block blk;
  321.    _kernel_swi_regs regs;
  322.  
  323.    /* Is the supplied filename a pure file name? */
  324.    if (len > 10)
  325.       return 0;
  326.  
  327.    /* Pad out the supplied filename on the left with a unique ID
  328.     * (Based on the program start time)
  329.     */
  330.    if (len < 10 && _kernel_swi(OS_GetEnv,®s,®s) == NULL)
  331.    {
  332.       int i;
  333.       char *time = (char *)regs.r[2];
  334.  
  335.       strcpy(buf,file);
  336.  
  337.       for (i = len; i < 10; ++i)
  338.       {
  339.          char c = time[(9 - i) >> 1];
  340.  
  341.          if (i & 1)
  342.             c >>= 4;
  343.  
  344.          c &= 0x0F;
  345.          buf[i] = "abcdefghijklmnop"[c];
  346.       }
  347.  
  348.       buf[10] = 0;
  349.  
  350.       file = buf;
  351.    }
  352.  
  353.    /* First, try the supplied directory */
  354.    if ( temp_dir )
  355.    {
  356.       if ( _kernel_osfile(ReadCat,temp_dir,&blk) == 2 )
  357.          return concat(temp_dir,file);
  358.       else
  359.       {
  360.          /* Is it a filing system name only? */
  361.          len = strlen(temp_dir);
  362.  
  363.          if (temp_dir[len-1] != ':')
  364.             return 0;
  365.  
  366.          /* One extra, just in case file == "", for the '@' */
  367.          name = malloc(len + strlen(file) + 2);
  368.  
  369.          if (name == 0)
  370.             return 0;
  371.  
  372.          strcpy(name,temp_dir);
  373.          name[len] = '@';
  374.          name[len+1] = '\0';
  375.  
  376.          if (_kernel_osfile(ReadCat,name,&blk) != 2)
  377.          {
  378.             free(name);
  379.             return 0;
  380.          }
  381.  
  382.          strcpy(&name[len],file);
  383.          return name;
  384.       }
  385.    }
  386.  
  387.    /* Otherwise, go through the list... */
  388.  
  389.    /* First of all, try <Tmp$Dir> */
  390.    if ((dir = getenv("Tmp$Dir")) != 0)
  391.    {
  392.       if (_kernel_osfile(ReadCat,dir,&blk) == 2)
  393.          return concat(dir,file);
  394.       else
  395.       {
  396.          /* Is it a filing system name only? */
  397.          len = strlen(dir);
  398.  
  399.          if (dir[len-1] != ':')
  400.             goto no_go;
  401.  
  402.          /* One extra, just in case file == "", for the '@' */
  403.          name = malloc(len + strlen(file) + 2);
  404.  
  405.          if (name == 0)
  406.             goto no_go;
  407.  
  408.          strcpy(name,dir);
  409.          name[len] = '@';
  410.          name[len+1] = '\0';
  411.  
  412.          if (_kernel_osfile(ReadCat,name,&blk) != 2)
  413.          {
  414.             free(name);
  415.             goto no_go;
  416.          }
  417.  
  418.          strcpy(&name[len],file);
  419.          return name;
  420.       }
  421.    }
  422.  
  423. no_go:
  424.    /* No <Tmp$Dir>, so try &.Tmp, if it exists */
  425.    if (_kernel_osfile(ReadCat,"&.Tmp",&blk) == 2)
  426.       return concat("&.Tmp",file);
  427.  
  428.    /* Out of luck - use the current directory */
  429.    name = malloc(strlen(file)+1);
  430.    if ( name )
  431.       strcpy(name,file);
  432.  
  433.    return name;
  434. }
  435.  
  436. static char *concat (const char *dir, const char *file)
  437. {
  438.     char *result = malloc(strlen(dir)+strlen(file)+2);
  439.     char *p = result;
  440.  
  441.     if ( result == 0 )
  442.         return 0;
  443.  
  444.     while ( *dir )
  445.         *p++ = *dir++;
  446.  
  447.     *p++ = '.';
  448.     while ( *file )
  449.         *p++ = *file++;
  450.  
  451.     *p = '\0';
  452.  
  453.     return result;
  454. }
  455.  
  456. /* ----------------------------------------------------------------- */
  457.  
  458. #ifdef test
  459.  
  460. int main (int argc, char *argv[])
  461. {
  462.     char *tmp;
  463.  
  464.     if ( argc != 2 && argc != 3 )
  465.     {
  466.         fprintf(stderr,"Usage: %s file [dir]\n",argv[0]);
  467.         return 1;
  468.     }
  469.  
  470.     if ( argc == 3 )
  471.         temp_dir = argv[2];
  472.  
  473.     tmp = mktemp (argv[1]);
  474.  
  475.     printf("Temp file = %s\n", tmp ? tmp : "<Not possible>");
  476.  
  477.     return 0;
  478. }
  479.  
  480. #endif
  481.  
  482. int pclose (FILE *current)
  483. {
  484.     int rval;
  485.     int i;
  486.  
  487.     /* Get the appropriate slot in thbe pipes structure */
  488.     for ( i = 0; i < MAX_PIPE; ++i )
  489.     {
  490.         if ( pipes[i].fd == current )
  491.             break;
  492.     }
  493.  
  494.     if ( i >= MAX_PIPE )
  495.         return -1;
  496.  
  497.     if ( pipes[i].pmode == reading )
  498.     {
  499.         /* Input pipes are just files we're done with */
  500.         rval = pipes[i].retval;
  501.         fclose(current);
  502.         remove(pipes[i].name);
  503.     }
  504.     else
  505.     {
  506.         /*
  507.          * Output pipes are temporary files we have
  508.          * to cram down the throats of programs.
  509.          */
  510.         char *command = pipes[i].command;
  511.         int oscmd = os_cmd(command);
  512.         int n;
  513.         char cmd[256];
  514.  
  515.         if (*command == '%')
  516.         {
  517.             oscmd = 1;
  518.             ++command;
  519.         }
  520.  
  521.         /* Close the pipe file */
  522.         fclose(current);
  523.  
  524.         /* Create the required command string */
  525.         if (oscmd)
  526.             n = sprintf(cmd, "%s{ < %s }", command, pipes[i].name);
  527.         else
  528.         {
  529.             char *s;
  530.  
  531.             while (*command && isspace(*command))
  532.                 ++command;
  533.  
  534.             s = command;
  535.  
  536.             while (*s && !isspace(*s))
  537.                 ++s;
  538.             
  539.             n = sprintf(cmd, "%.*s < %s%s",
  540.                 s - command, command, pipes[i].name, s);
  541.         }
  542.  
  543.         /* Check for overflow in command buffer */
  544.         if (n > 255)
  545.             rval = -1;
  546.         else
  547.         {
  548.             _kernel_setenv("Sys$ReturnCode", "0");
  549.             rval = system(cmd);
  550.         }
  551.  
  552.         remove(pipes[i].name);
  553.     }
  554.  
  555.     /* clean up current pipe */
  556.     pipes[i].pmode = unopened;
  557.     free(pipes[i].name);
  558.     free(pipes[i].command);
  559.     return rval;
  560. }
  561.  
  562. /* save a string on the heap; return pointer to it */
  563.  
  564. static char *strdup (const char *str)
  565. {
  566.     char *p = malloc(strlen(str)+1);
  567.  
  568.     if (p == NULL)
  569.     {
  570.         fprintf(stderr,"Not enough memory to save string\n");
  571.         exit(1);
  572.     }
  573.  
  574.     return (strcpy(p,str));
  575. }
  576.  
  577. /* Check whether a command is an OS command (binary search on the table
  578.  * os_commands of valid OS commands).
  579.  */
  580.  
  581. static char *os_commands[] =
  582. {
  583.     "access",    "adfs",        "alphabet",    "alphabets",
  584.     "append",    "audio",    "basic",    "breakclr",
  585.     "breaklist",    "breakset",    "build",    "cat",
  586.     "cdir",        "channelvoice",    "close",    "configure",
  587.     "continue",    "copy",        "count",    "countries",
  588.     "country",    "create",    "debug",    "delete",
  589.     "deskfs",    "dir",        "dump",        "echo",
  590.     "enumdir",    "error",    "eval",        "ex",
  591.     "exec",        "fileinfo",    "fontcat",    "fontlist",
  592.     "fx",        "go",        "gos",        "help",
  593.     "iconsprites",    "if",        "ignore",    "info",
  594.     "initstore",    "key",        "keyboard",    "lcat",
  595.     "lex",        "lib",        "list",        "load",
  596.     "memory",    "memorya",    "memoryi",    "modules",
  597.     "obey",        "opt",        "poduleload",    "podules",
  598.     "podulesave",    "pointer",    "print",    "qsound",
  599.     "quit",        "ram",        "remove",    "rename",
  600.     "rmclear",    "rmensure",    "rmfaster",    "rmkill",
  601.     "rmload",    "rmreinit",    "rmrun",    "rmtidy",
  602.     "rommodules",    "run",        "save",        "schoose",
  603.     "scopy",    "screenload",    "screensave",    "sdelete",
  604.     "set",        "seteval",    "setmacro",    "settype",
  605.     "sflipx",    "sflipy",    "sget",        "shadow",
  606.     "shellcli",    "show",        "showregs",    "shut",
  607.     "shutdown",    "sinfo",    "slist",    "sload",
  608.     "smerge",    "snew",        "sound",    "speaker",
  609.     "spool",    "spoolon",    "srename",    "ssave",
  610.     "stamp",    "status",    "stereo",    "tempo",
  611.     "time",        "tuning",    "tv",        "type",
  612.     "unplug",    "unset",    "up",        "voices",
  613.     "volume",    "wimppalette",    "wimpslot",    "wimptask",
  614.     "wipe"
  615. };
  616.  
  617. #define NUM_CMDS (sizeof(os_commands) / sizeof(char *))
  618.  
  619. static int os_cmd (char *cmd)
  620. {
  621.     int low = 0;
  622.     int high = NUM_CMDS - 1;
  623.  
  624.     while (low <= high)
  625.     {
  626.         int mid = (high + low) / 2;
  627.         int i = cmp_cmd(cmd,os_commands[mid]);
  628.  
  629.         if (i == 0)
  630.             return 1;
  631.         else if (i < 0)
  632.             high = mid - 1;
  633.         else
  634.             low = mid + 1;
  635.     }
  636.  
  637.     return 0;
  638. }
  639.  
  640. static int cmp_cmd (char *cmd, char *name)
  641. {
  642.     while (*name && tolower(*cmd) == *name)
  643.         ++name, ++cmd;
  644.  
  645.     if (*name)
  646.         return (tolower(*cmd) - *name);
  647.  
  648.     return (*cmd != '\0' && !isspace(*cmd));
  649. }
  650.  
  651. #ifdef test
  652. int main (int argc, char *argv[])
  653. {
  654.     FILE *fp;
  655.     char *cmd;
  656.  
  657.     if (argc <= 1)
  658.     {
  659.         printf("Usage Popen [cmd or Popen ]cmd\n");
  660.         return 0;
  661.     }
  662.  
  663.     cmd = argv[1];
  664.  
  665.     if (*cmd++ == ']')
  666.     {
  667.         fp = popen(cmd,"w");
  668.         fprintf(fp,"hello\nworld\nhow\nare\nyou\n");
  669.         pclose(fp);
  670.     }
  671.     else
  672.     {
  673.         char buf[500];
  674.         fp = popen(cmd,"r");
  675.         while (!feof(fp))
  676.         {
  677.             if (!fgets(buf,499,fp))
  678.             {
  679.                 printf("Read error!\n");
  680.                 return 1;
  681.             }
  682.             buf[strlen(buf)-1] = 0;
  683.             printf(">%s<\n", buf);
  684.         }
  685.         pclose(fp);
  686.     }
  687.  
  688.     return 0;
  689. }
  690. #endif
  691.  
  692. int unlink (const char *name)
  693. {
  694.     _kernel_osfile_block blk;
  695.  
  696.     return (_kernel_osfile(6,name,&blk) <= 0);
  697. }
  698.  
  699. int getch (void)
  700. {
  701.     return _kernel_osrdch();
  702. }
  703.  
  704. int getche (void)
  705. {
  706.     int ch = _kernel_osrdch();
  707.  
  708.     _kernel_oswrch(ch);
  709.  
  710.     return ch;
  711. }
  712.  
  713. int kbhit (void)
  714. {
  715.     return ((_kernel_osbyte(152,0,0) & 0x00FF0000) != 0x00010000);
  716. }
  717.  
  718. #endif                    /* ARM */
  719.  
  720. #if ATARI_ST
  721. #if LATTICE
  722.  
  723. long _STACK = 10240;
  724. long _MNEED = 200000;    /* reserve space for allocation (may be too large) */
  725.  
  726. #include <osbind.h>
  727.  
  728. /*  Structure necessary for handling system time. */
  729.    struct tm {
  730.        short tm_year;
  731.        short tm_mon;
  732.        short tm_wday;
  733.        short tm_mday;
  734.        short tm_hour;
  735.        short tm_min;
  736.        short tm_sec;
  737.    };
  738.  
  739. struct tm *localtime(clock)   /* fill structure with clock time */
  740. int clock;     /* millisecond timer value, if supplied; not used */
  741. {
  742.   static struct tm tv;
  743.   unsigned int time, date;
  744.  
  745.   time = Tgettime();
  746.   date = Tgetdate();
  747.   tv.tm_year = ((date >> 9) & 0x7f) + 80;
  748.   tv.tm_mon  = ((date >> 5) & 0xf) - 1;
  749.   tv.tm_mday = date & 0x1f;
  750.   tv.tm_hour = (time >> 11) & 0x1f;
  751.   tv.tm_min  = (time >> 5)  & 0x3f;
  752.   tv.tm_sec  = 2 * (time & 0x1f);
  753.  
  754.   tv.tm_wday = weekday(tv.tm_mday,tv.tm_mon+1,tv.tm_year);
  755.   return(&tv);
  756. }
  757.  
  758.  
  759. weekday(day,month,year)   /* find day of week from    */
  760. short day, month, year;   /* day, month, and year     */
  761. {                         /* Sunday..Saturday is 0..6 */
  762.   int index, yrndx, mondx;
  763.  
  764.   if(month <= 2) {   /* Jan or Feb month adjust */
  765.       month += 12;
  766.       year  -=  1;
  767.   }
  768.  
  769.   yrndx = year + (year / 4) - (year / 100) + (year / 400);
  770.   mondx = 2 * month + (3 * (month + 1)) / 5;
  771.   index = day + mondx + yrndx + 2;
  772.   return(index % 7);
  773. }
  774.  
  775.  
  776.  
  777. time(ptime)   /* return value of millisecond timer */
  778. int  *ptime;
  779. {
  780.   int  tmp, ssp;   /* value of supervisor stack pointer */
  781.   static int  *tmr = (int *) 0x04ba;   /* addr of timer */
  782.  
  783.   ssp = gemdos(0x20,0);   /* enter supervisor mode */
  784.   tmp = *tmr * 5;         /* get millisecond timer */
  785.   ssp = gemdos(0x20,ssp); /* enter programmer mode */
  786.  
  787.   if(ptime != NULL)
  788.       *ptime = tmp;
  789.  
  790.   return(tmp);
  791. }
  792.  
  793. int brk(p)
  794. char *p;
  795. {
  796.   char *sbrk();
  797.   long int l, m;
  798.  
  799.   l = (long int)p;
  800.   m = (long int)sbrk(0);
  801.  
  802.   return((lsbrk((long) (l - m)) == 0) ? -1 : 0);
  803. }
  804.  
  805. #endif                    /* LATTICE */
  806. #endif                    /* ATARI_ST */
  807.  
  808. #if MACINTOSH
  809. #if MPW
  810. /*
  811.  * Special routines for Macintosh Programmer's Workshop (MPW) implementation
  812.  *  of the Icon Programming Language
  813.  */
  814.  
  815. #include <stdlib.h>
  816. #include <stdio.h>
  817. #include <Types.h>
  818. #include <Events.h>
  819. #include <Files.h>
  820. #include <FCntl.h>
  821. #include <IOCtl.h>
  822. #include <SANE.h>
  823. #include <OSUtils.h>
  824. #include <Memory.h>
  825. #include <Errors.h>
  826. #include "time.h"
  827. #include <QuickDraw.h>
  828. #include <ToolUtils.h>
  829. #include <CursorCtl.h>
  830.  
  831. #define isatty(fd) (!ioctl((fd), FIOINTERACTIVE))
  832.  
  833.    void
  834. SetFileToMPWText(const char *fname) {
  835.    FInfo info;
  836.    int needToSet = 0;
  837.  
  838.    if (getfinfo(fname,0,&info) == 0) {
  839.       if (info.fdType == 0) {
  840.      info.fdType = 'TEXT';
  841.      needToSet = 1;
  842.      }
  843.       if (info.fdCreator == 0) {
  844.      info.fdCreator = 'MPS ';
  845.      needToSet = 1;
  846.      }
  847.       if (needToSet) {
  848.      setfinfo(fname,0,&info);
  849.      }
  850.       }
  851.    return;
  852.    }
  853.  
  854.  
  855.    int
  856. MPWFlush(FILE *f) {
  857.    static int fetched = 0;
  858.    static char *noLineFlush;
  859.  
  860.    if (!fetched) {
  861.       noLineFlush = getenv("NOLINEFLUSH");
  862.       fetched = 1;
  863.       }
  864.    if (!noLineFlush || noLineFlush[0] == '\0')
  865.          fflush(f);
  866.    return 0;
  867.    }
  868.  
  869.  
  870.    void
  871. SetFloatTrap(void (*fpetrap)()) {
  872.    /* This is equivalent to SIGFPE signal in the Standard Apple
  873.       Numeric Environment (SANE) */
  874.    environment e;
  875.  
  876.    getenvironment(&e);
  877.       #ifdef mc68881
  878.      e.FPCR |= CURUNDERFLOW|CUROVERFLOW|CURDIVBYZERO;
  879.       #else                    /* mc68881 */
  880.      e |= UNDERFLOW|OVERFLOW|DIVBYZERO;
  881.       #endif                    /* mc68881 */
  882.    setenvironment(e);
  883.    #ifdef mc68881
  884.       {
  885.       static trapvector tv =
  886.          {fpetrap,fpetrap,fpetrap,fpetrap,fpetrap,fpetrap,fpetrap};
  887.       settrapvector(&tv);
  888.       }
  889.    #else                    /* mc68881 */
  890.       sethaltvector((haltvector)fpetrap);
  891.    #endif                    /* mc68881 */
  892.    }
  893.  
  894.  
  895.    void
  896. SetWatchCursor(void) {
  897.    SetCursor(*GetCursor(watchCursor));    /* Set watch cursor */
  898.    }
  899.  
  900.  
  901. #define TicksPerRotation 10 /* rotate cursor no more often than 6 times
  902.                  per second */
  903.  
  904.    void
  905. RotateTheCursor(void) {
  906.    static unsigned long nextRotate = 0;
  907.    if (TickCount() >= nextRotate) {
  908.       RotateCursor(0);
  909.       nextRotate = TickCount() + TicksPerRotation;
  910.       }
  911.    else {
  912.       RotateCursor(1);
  913.       }
  914.    }
  915.  
  916. /*
  917.  *  Initialization and Termination Routines
  918.  */
  919.  
  920. /*
  921.  *  MacExit -- This function is installed by an atexit() call in MacInit
  922.  *  -- it is called automatically when the program terminates.
  923.  */
  924.    void
  925. MacExit() {
  926.    void ResetStack();
  927.    extern Ptr MemBlock;
  928.  
  929.    ResetStack();
  930.    /* if (MemBlock != NULL) DisposPtr(MemBlock); */
  931.    }
  932.  
  933. /*
  934.  *  MacInit -- This function is called near the beginning of execution of
  935.  *  iconx.  It is called by our own brk/sbrk initialization routine.
  936.  */
  937.    void
  938. MacInit() {
  939.    atexit(MacExit);
  940.    return;
  941.    }
  942.  
  943. /*
  944.  * MacDelay -- Delay n milliseconds.
  945.  */
  946.    void
  947. MacDelay(int n) {
  948.    unsigned long endTicks;
  949.    unsigned long nextRotate;
  950.  
  951.    endTicks = TickCount() + (n * 3 + 25) / 50;
  952.    nextRotate = 0;
  953.    while (TickCount() < endTicks) {
  954.       if (TickCount() >= nextRotate) {
  955.          nextRotate = TickCount() + TicksPerRotation;
  956.      RotateCursor(0);
  957.          }
  958.       else {
  959.          RotateCursor(1);
  960.      }
  961.       }
  962.    }
  963. #endif                    /* MPW */
  964. #endif                    /* MACINTOSH */
  965.  
  966. #if MSDOS
  967. #if NT
  968. /*
  969.  * header comment says not to do this, but the "right" way doesn't work
  970.  */
  971. #passthru #include <direct.h>
  972. #endif                    /* NT */
  973.  
  974. int pathFind(char target[], char buf[], int n)
  975.    {
  976.    char *path;
  977.    register int i;
  978.    int res;
  979.    struct stat sbuf;
  980.  
  981.    if ((path = getenv("PATH")) == 0)
  982.       path = "";
  983.  
  984.    if (!getcwd(buf, n)) {        /* get current working directory */
  985.       *buf = 0;        /* may be better to do something nicer if we can't */
  986.       return 0;        /* find out where we are -- struggling to achieve */
  987.       }            /* something can be better than not trying */
  988.  
  989.    /* attempt to find the icode file in the current directory first */
  990.    /* this mimicks the behavior of COMMAND.COM */
  991.    if ((i = strlen(buf)) > 0) {
  992.       i = buf[i - 1];
  993.       if (i != '\\' && i != '/' && i != ':')
  994.          strcat(buf, "/");
  995.       }
  996.    strcat(buf, target);
  997.    res = stat(buf, &sbuf);
  998.  
  999.    while(res && *path) {
  1000.       for (i = 0; *path && *path != ';'; ++i)
  1001.          buf[i] = *path++;
  1002.       if (*path)            /* skip the ; or : separator */
  1003.          ++path;
  1004.       if (i == 0)            /* skip empty fragments in PATH */
  1005.          continue;
  1006.       if (i > 0 && buf[i - 1] != '/' && buf[i - 1] != '\\' &&
  1007.          buf[i - 1] != ':')
  1008.             buf[i++] = '/';
  1009.       strcpy(buf + i, target);
  1010.       res = stat(buf, &sbuf);
  1011.       /* exclude directories (and any other nasties) from selection */
  1012.       if (res == 0 && sbuf.st_mode & S_IFDIR)
  1013.          res = -1;
  1014.       }
  1015.    if (res != 0)
  1016.       *buf = 0;
  1017.    return res == 0;
  1018.    }
  1019. #endif                    /* MSDOS */
  1020.  
  1021. #if MSDOS || OS2
  1022. FILE *pathOpen(fname, mode)
  1023.    char *fname;
  1024.    char *mode;
  1025.    {
  1026. #if OS2
  1027.    char buf[260 + 1];
  1028. #else                    /* OS2 */
  1029.    char buf[150 + 1];
  1030. #endif                    /* OS2 */
  1031.    int i, use = 1;
  1032.  
  1033. #if SCCX_MX
  1034.    /* Avoid compiler warning */
  1035.    for( i = 0; (buf[i] = fname[i]) != 0; ++i)
  1036. #else
  1037.    for( i = 0; buf[i] = fname[i]; ++i)
  1038. #endif                    /* SCCX_MX */
  1039.  
  1040.       /* find out if a path has been given in the file name */
  1041.       if (buf[i] == '/' || buf[i] == ':' || buf[i] == '\\')
  1042.          use = 0;
  1043.  
  1044.    /* If a path has been given with the file name, don't bother to
  1045.       use the PATH */
  1046.  
  1047. #if OS2
  1048.    if (use && DosSearchPath(SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT, 
  1049.                             "PATH", fname, buf, 260))
  1050. #else                    /* OS2 */
  1051.    if (use && !pathFind(fname, buf, 150))
  1052. #endif                     /* OS2 */
  1053.        return 0;
  1054.  
  1055.    return fopen(buf, mode);
  1056.    }
  1057. #endif                    /* MSDOS || OS2 */
  1058.  
  1059. #if MSDOS
  1060. #if INTEL_386
  1061. /*  sbrk(incr) - adjust the break value by incr.
  1062.  *  Returns the new break value, or -1 if unsuccessful.
  1063.  */
  1064.  
  1065. pointer sbrk(incr)
  1066. msize incr;
  1067. {
  1068.    static pointer base = 0;        /* base of the sbrk region */
  1069.    static pointer endofmem, curr;
  1070.    pointer result;
  1071.    union REGS rin, rout;
  1072.  
  1073.    if (!base) {                    /* if need to initialize                */
  1074.       rin.w.eax = 0x80004800;    /* use DOS allocate function with max    */
  1075.       rin.w.ebx = 0xffffffff;    /*  request to determine size of free    */
  1076.       intdos(&rin, &rout);        /*  memory (including virtual memory.    */
  1077.       rin.w.ebx = rout.w.ebx;    /* DOS allocate all of memory.            */
  1078.       intdos(&rin, &rout);
  1079.       if (rout.w.cflag)
  1080.          return (pointer)-1;
  1081.       curr = base = (pointer)rout.w.eax;
  1082.       endofmem = (pointer)((char *)base + rin.w.ebx);
  1083.       }
  1084.     
  1085.    if ((char *)curr + incr > (char *)endofmem)
  1086.       return (pointer)-1;
  1087.    result = curr;
  1088.    curr = (pointer)((char *)curr + incr);
  1089.    return result;
  1090.  
  1091. }
  1092.  
  1093. /*  brk(addr) - set the break address to the given value, rounded up to a page.
  1094.  *  returns 0 if successful, -1 if not.
  1095.  */
  1096.  
  1097. int brk(addr)
  1098. pointer addr;
  1099. {
  1100.    int result;
  1101.    result = sbrk((char *)addr - (char *)sbrk(0)) == (pointer)-1 ? -1 : 0;
  1102.    return result;
  1103. }
  1104.  
  1105. #endif                    /* INTEL_386 */
  1106.  
  1107. #if TURBO
  1108. extern unsigned _stklen = 16 * 1024;
  1109. #endif                    /* TURBO */
  1110.  
  1111. #endif                    /* MSDOS */
  1112.  
  1113. #if MVS || VM
  1114. #if SASC 
  1115. #passthru #include <options.h>
  1116. char _linkage = _OPTIMIZE;
  1117.  
  1118. #if MVS
  1119. char *_style = "tso:";          /* use dsnames as file names */
  1120. #define SYS_OSVS
  1121. #else                                   /* MVS */
  1122. #define SYS_CMS
  1123. #endif                                  /* MVS */
  1124.  
  1125. #passthru #define RES_SIGNAL
  1126. #passthru #define RES_COPROC
  1127. #passthru #define RES_IOUTIL
  1128. #passthru #define RES_DSNAME
  1129. #passthru #define RES_FILEDEF
  1130. #passthru #define RES_UNITREC
  1131. #passthru #define RES_TSOENVVAR
  1132. #passthru #define ALLOW_TRANSIENT /* temporary */
  1133.  
  1134. #passthru #include <resident.h>
  1135.  
  1136. #endif                                  /* SASC */
  1137. #endif                                  /* MVS || VM */
  1138.  
  1139. #if OS2
  1140. novalue abort()
  1141. {
  1142. #ifdef DeBugIconx
  1143.     blkdump();
  1144. #endif
  1145.     fflush(stderr);
  1146. #if CSET2
  1147.     _fcloseall();
  1148. #else
  1149.     fcloseall();
  1150. #endif        CSET2
  1151.     _exit(1);
  1152. }
  1153.  
  1154. #ifndef OS2EMX
  1155. #if CSET2
  1156. /* 20 is the default file handle max, this can be dynamically altered */
  1157. #define _NFILE  20
  1158. #endif        /* CSET2 */
  1159.  
  1160. static int _pipes[_NFILE];
  1161.  
  1162. /*
  1163.  * popen("command",mode)
  1164.  *
  1165.  * cmd = command to be passed to shell. (CMD.EXE or comspec->)
  1166.  * mode = "r" | "w"
  1167.  */
  1168. FILE *popen(char *cmd, char *mode)
  1169. {
  1170. #if OS2_32
  1171.     HFILE whandle, rhandle;
  1172. #else
  1173.     int whandle, rhandle;
  1174. #endif        /* OS2_32 */
  1175.     int phandle, chandle, shandle;
  1176.     int rc;
  1177.     char *cmdshell;
  1178.  
  1179.     /* Validate */
  1180.     if(cmd == NULL || mode == NULL) return NULL;
  1181.     if(tolower(*mode) != 'r' && tolower(*mode) != 'w')
  1182.     return NULL;
  1183.  
  1184.     /* Create the pipe */
  1185. #if OS2_32
  1186.     if (DosCreatePipe(&rhandle, &whandle, (ULONG)BUFSIZ) < 0)
  1187. #else
  1188.     if (DosMakePipe(&rhandle, &whandle, BUFSIZ) < 0)
  1189. #endif        /* OS2_32 */
  1190.     return NULL;
  1191.  
  1192.     /* Dup STDIN or STDOUT to the pipe */
  1193.     if (*mode == 'r') {
  1194.     /* Dup stdout */
  1195.     phandle = rhandle;
  1196.     chandle = whandle;
  1197.     shandle = dup(1);    /* Save STDOUT */
  1198.     rc = dup2(chandle, 1);
  1199.     } else {
  1200.     /* Dup stdin */
  1201.     phandle = whandle;
  1202.     chandle = rhandle;
  1203.     shandle = dup(0);    /* Save STDIN */
  1204.     rc = dup2(chandle, 0);
  1205.     }
  1206.     if (rc < 0) {
  1207.     perror("dup2");
  1208.     return NULL;
  1209.     }
  1210.     close(chandle);
  1211.  
  1212.     /* Make sure that we don't pass this handle on */
  1213.     DosSetFHandState(phandle, OPEN_FLAGS_NOINHERIT);
  1214.  
  1215.     /* Invoke the child, remember its processid */
  1216.     cmdshell = getenv("COMSPEC");
  1217.     if (cmdshell == NULL) cmdshell = "CMD.EXE";
  1218.  
  1219.     _pipes[chandle] = spawnlp(P_NOWAIT, cmdshell, cmdshell,"/c",cmd, NULL);
  1220.  
  1221.     /* Clean up by reestablishing our STDIN/STDOUT */
  1222.     if (*mode == 'r')
  1223.     rc = dup2(shandle, 1);
  1224.     else
  1225.     rc = dup2(shandle, 0);
  1226.     if (rc < 0) {
  1227.     perror("dup2");
  1228.     return NULL;
  1229.     }
  1230.     close(shandle);
  1231.  
  1232.     return fdopen(phandle, mode);
  1233. }
  1234. pclose(ptr)
  1235. FILE *ptr;
  1236. {
  1237.     int status, pnum;
  1238.  
  1239.     pnum = fileno(ptr);
  1240.     fclose(ptr);
  1241.  
  1242.     /* Now wait for child to end */
  1243.     cwait(&status, _pipes[pnum], WAIT_GRANDCHILD);
  1244.  
  1245.     return status;
  1246. }
  1247. #endif                    /* OS2EMX */
  1248.  
  1249. /* End of pipe support for OS/2 */
  1250. #endif                    /* OS2 */
  1251.  
  1252. #if UNIX
  1253. #ifdef ATTM32
  1254.  
  1255. /*
  1256.  * This file contains the routine necessary to allocate legal AT&T
  1257.  * 3B2/15/4000 stack space for co-expression stacks.
  1258.  *
  1259.  * Legal stack region begins at 0xC0020000, and UNIX will grow stack space
  1260.  * up to 50 Megabytes. 0xC0030000 should provide plenty of room for
  1261.  * main C stack growth.  Each time coexpr_salloc() is called, it
  1262.  * adds mstksize (max main stack size) and returns a new address,
  1263.  * meaning each coexpression stack is potentially as large as the main stack.
  1264.  */
  1265.  
  1266. /*
  1267.  * coexp_salloc() - return pointer in legal stack space for start
  1268.  *                  of a coexpression stack.
  1269.  */
  1270.  
  1271. pointer coexp_salloc()
  1272.    {
  1273.    static pointer sp = 0xC0030000 ;     /* pointer to stack region */
  1274.  
  1275.    sp +=  mstksize;
  1276.    return sp;
  1277. }
  1278. #endif                    /* ATTM32 */
  1279.  
  1280. #ifdef KeyboardFncs
  1281.  
  1282. #begdef CopyTty(t1,t2)
  1283.    if (!reset_flag) {
  1284.       t2 = t1;
  1285.       reset_flag = 1;
  1286.       }
  1287. #enddef
  1288.  
  1289. #begdef ResetTty(t1, theIOCTL)
  1290.    if (reset_flag) {
  1291.       if (ioctl(0, theIOCTL, t1) == -1) {
  1292.          keyboard_error = 214;
  1293.          return 0;
  1294.          }
  1295.       }
  1296. #enddef
  1297.  
  1298. #define ECHO_ON 1
  1299. #define ECHO_OFF 0
  1300.  
  1301.  
  1302. #ifdef HaveTermio
  1303.  
  1304. #define RawIOCTL   TCGETA
  1305. #define ResetIOCTL TCSETA
  1306. #define TtyFlags(t)   (t).c_lflag
  1307.  
  1308. #else                /* not HaveTermio */
  1309. #ifdef HaveTioc
  1310.  
  1311. #define ResetIOCTL TIOCSETN
  1312. #define RawIOCTL   TIOCGETP
  1313. #define TtyFlags(t)   (t).sg_flags
  1314. #endif                /* HaveTioc */
  1315. #endif                /* HaveTermio */
  1316.  
  1317. /*
  1318.  * read_a_char(turn_echo_on): int
  1319.  *
  1320.  * Routine to actually do the reading (either with echo or without,
  1321.  * depending on whether turn_echo_on is 1 or 0).
  1322.  */
  1323. int read_a_char(turn_echo_on)
  1324. int turn_echo_on;
  1325. {
  1326.    char c;
  1327. #ifdef HaveTermio
  1328.    struct termio tty, new_tty;
  1329.    novalue abort_on_signal();
  1330. #else                    /* HaveTermio */
  1331.    struct tchars tty_characters;
  1332.    struct sgttyb tty, new_tty;
  1333. #endif                    /* HaveTermio */
  1334.    register word status, isa_tty = 0, reset_flag = 0;
  1335.    extern int errno;
  1336.   
  1337.    if (isatty(0)) {
  1338.  
  1339.       isa_tty = 1;
  1340.       if (ioctl(0, RawIOCTL, &tty) == -1) {
  1341.      keyboard_error = 214;
  1342.      return 0;
  1343.          }
  1344. #ifdef HaveTioc
  1345.       if (ioctl(0, TIOCGETC, &tty_characters) == -1) {
  1346.      keyboard_error = 214;
  1347.      return 0;
  1348.          }
  1349. #endif                    /* HaveTioc */
  1350. #ifdef HaveTermio
  1351.       /* disable keyboard signals quit & interrupt */
  1352.       if (tty.c_lflag & ISIG) {
  1353.      CopyTty(tty, new_tty);    /* a macro, defined above */
  1354.      new_tty.c_lflag &= ~ISIG;
  1355.          }
  1356.       /* disable canonical input processing (like BSD cbreak) */
  1357.       if (tty.c_lflag & ICANON) {
  1358.      CopyTty(tty, new_tty);
  1359.      new_tty.c_lflag &= ~ICANON;
  1360.          }
  1361.       if (tty.c_cc[VMIN] != '\1') {
  1362.      CopyTty(tty, new_tty);
  1363.      new_tty.c_cc[VMIN] = (unsigned char )'\1';
  1364.          }
  1365.       if (tty.c_cc[VTIME]) {
  1366.      CopyTty(tty, new_tty);
  1367.      new_tty.c_cc[VTIME] = (unsigned char )'\0';
  1368.          }
  1369. #endif                    /* HaveTermio */
  1370.       if (turn_echo_on) {
  1371.      /* set echo bit, i.e. enable echo */
  1372.      if (! (TtyFlags(tty) & ECHO)) {
  1373.         CopyTty(tty, new_tty);
  1374.         TtyFlags(new_tty) |= ECHO;
  1375.         }
  1376.          }
  1377.       else { /* i.e. if _not_ turn_echo_on */
  1378.      /* mask out echo bit, i.e. disable echo */
  1379.     if (TtyFlags(tty) & ECHO) {
  1380.        CopyTty(tty, new_tty);
  1381.        TtyFlags(new_tty) &= ~ECHO;
  1382.        }
  1383.         }
  1384. #ifdef HaveTioc
  1385.       /* raw mode; we'll process quit and interrupt by hand */
  1386.       if (! (tty.sg_flags & RAW)) {
  1387.      CopyTty(tty, new_tty);
  1388.      new_tty.sg_flags |= RAW;
  1389.          }
  1390. #endif                    /* HaveTioc */
  1391.       ResetTty(&new_tty, ResetIOCTL);        /* a macro, defined above */
  1392.       }
  1393.  
  1394.    /* finally, read 1 char from the standard input */
  1395.    status = read(0, &c, 1);
  1396.    if (isa_tty)
  1397.       ResetTty(&tty, ResetIOCTL);
  1398.    if (status == -1) {
  1399.       switch (errno) {
  1400.       case EBADF:
  1401.      keyboard_error = 212;
  1402.      return 0;
  1403.       default:
  1404.      keyboard_error = 214;
  1405.      return 0;
  1406.          }
  1407.       }
  1408.  
  1409.    /* Check for quit and interrupt characters. */
  1410.    if (isa_tty) {
  1411. #ifdef HaveTermio
  1412.       if ((unsigned char)c == tty.c_cc[VINTR]) {
  1413. #else                    /* HaveTermio */
  1414.       if ((char )c == tty_characters.t_intrc) {
  1415. #endif                    /* HaveTermio */
  1416.      if (kill(getpid(), SIGINT) == -1) {
  1417.         perror("kill");
  1418.         keyboard_error = 500;
  1419.         return 0;
  1420.         }
  1421.          }
  1422. #ifdef HaveTermio
  1423.       else if ((unsigned char)c == tty.c_cc[VQUIT]) {
  1424. #else                    /* HaveTermio */
  1425.       else if ((char )c == tty_characters.t_quitc) {
  1426. #endif                    /* HaveTermio */
  1427.      if (kill(getpid(), SIGQUIT) == -1) {
  1428.         perror("kill");
  1429.         keyboard_error = 500;
  1430.         return 0;
  1431.         }
  1432.          }
  1433.       }
  1434.  
  1435.    if (! status) return -1;
  1436.    else return (int)c;
  1437. }
  1438.  
  1439. /*
  1440.  * getch(): int
  1441.  *
  1442.  * Routine to read one char from the standard input.  Enables cbreak mode
  1443.  * so as to read a character right from the buffer, without having to wait
  1444.  * for a carriage return.  Disables cbreak mode after reading a character.
  1445.  * Note that getch() does not echo any characters to the screen, although
  1446.  * characters might appear on the screen anyway, if they were typed before
  1447.  * getch() was invoked.
  1448.  */
  1449. int getch()
  1450. {
  1451.    int read_a_char();
  1452.    return read_a_char(ECHO_OFF);
  1453. }
  1454.  
  1455. /*
  1456.  * getche(): int
  1457.  *
  1458.  * Routine to read one char from the standard input.  Enables cbreak mode,
  1459.  * to read the character right from the buffer, without having to wait for
  1460.  * a carriage return.  Disables cbreak mode after reading a character.  NOTE:
  1461.  * Getche() does not disable echoing, so anything typed after it is invoked
  1462.  * will be echoed to the screen (unlike getch(), which disables echoing; see
  1463.  * above).
  1464.  */
  1465. int getche()
  1466. {
  1467.    int read_a_char();
  1468.    return read_a_char(ECHO_ON);
  1469. }
  1470.  
  1471. /*
  1472.  * kbhit(): int
  1473.  *
  1474.  * Routine to check for the availability of characters on the stdin
  1475.  * stream.  Does not actually read any characters.  Returns nonzero
  1476.  * value if characters are waiting; otherwise, zero.  The idea here,
  1477.  * as in getch() and getche(), is not to touch the tty settings
  1478.  * unless we have to.
  1479.  */
  1480. int kbhit()
  1481. {
  1482.    word arg;
  1483. #ifdef HaveTermio
  1484.    struct termio tty, new_tty;
  1485. #else                    /* HaveTermio */
  1486.    struct sgttyb tty, new_tty;
  1487. #endif                    /* HaveTermio */
  1488.    register word status, isa_tty = 0, reset_flag = 0;
  1489.    extern int errno;
  1490.  
  1491.    if (isatty(0)) {
  1492.  
  1493.       isa_tty = 1;
  1494.       if (ioctl(0, RawIOCTL, &tty) == -1) {
  1495.      keyboard_error = 214;
  1496.      return 0;
  1497.          }
  1498. #ifdef HaveTermio
  1499.       if (tty.c_lflag & ICANON) {
  1500.      CopyTty(tty, new_tty);
  1501.      new_tty.c_lflag &= ~ICANON;
  1502.          }
  1503. #else                    /* HaveTermio */
  1504.       /* Some Sun4s need this */
  1505.       if (tty.sg_flags & ECHO) {
  1506.      CopyTty(tty, new_tty);
  1507.      new_tty.sg_flags &= ~ECHO;
  1508.          }
  1509.       /* enable cbreak mode */
  1510.       if (! (tty.sg_flags & CBREAK)) {
  1511.      CopyTty(tty, new_tty);
  1512.      new_tty.sg_flags |= CBREAK;
  1513.          }
  1514. #endif                    /* HaveTermio */
  1515.       ResetTty(&new_tty, ResetIOCTL);
  1516.       }
  1517.  
  1518.    /* see if anything is waiting to be read from the file */
  1519. #ifdef HaveTioc
  1520.    status = ioctl(0, FIONREAD, &arg);
  1521. #endif                    /* HaveTioc */
  1522. #ifdef HaveTermio
  1523. #ifndef Linux
  1524. #ifdef Xenix386
  1525.    status = rdchk(0);
  1526. #else                    /* Xenix386 */
  1527.    status = ioctl(0, FIORDCHK, &arg);
  1528. #endif                    /* Xenix386 */
  1529. #else
  1530.    status = ioctl(0, FIONREAD, &arg);
  1531. #endif                    /* Linux */
  1532. #endif                    /* HaveTermio */
  1533.    if (isa_tty) ResetTty(&tty, ResetIOCTL);
  1534.    if (status == -1) {
  1535.       switch (errno) {
  1536.       case EBADF:
  1537.      keyboard_error = 212;
  1538.      return 0;
  1539.       default:
  1540.      keyboard_error = 214;
  1541.      return 0;
  1542.          }
  1543.       }
  1544.    return arg;
  1545. }
  1546.  
  1547. #endif                /* KeyboardFncs */
  1548.  
  1549.  
  1550. #endif                    /* UNIX */
  1551.  
  1552.  
  1553. #if VMS
  1554. #passthru #define LIB_GET_EF     LIB$GET_EF
  1555. #passthru #define SYS_CREMBX     SYS$CREMBX
  1556. #passthru #define LIB_FREE_EF    LIB$FREE_EF
  1557. #passthru #define DVI__DEVNAM    DVI$_DEVNAM
  1558. #passthru #define SYS_GETDVIW    SYS$GETDVIW
  1559. #passthru #define SYS_DASSGN     SYS$DASSGN
  1560. #passthru #define LIB_SPAWN      LIB$SPAWN
  1561. #passthru #define SYS_QIOW       SYS$QIOW
  1562. #passthru #define IO__WRITEOF    IO$_WRITEOF
  1563. #passthru #define SYS_WFLOR      SYS$WFLOR
  1564. #passthru #define sys_expreg     sys$expreg
  1565. #passthru #define STS_M_SUCCESS  STS$M_SUCCESS
  1566. #passthru #define sys_cretva     sys$cretva
  1567. #passthru #define SYS_ASSIGN     SYS$ASSIGN
  1568. #passthru #define SYS_QIO        SYS$QIO
  1569. #passthru #define IO__TTYREADALL IO$_TTYREADALL
  1570. #passthru #define IO__WRITEVBLK  IO$_WRITEVBLK
  1571. #passthru #define IO_M_NOECHO    IO$M_NOECHO
  1572. #passthru #define SYS_SCHDWK     SYS$SCHDWK
  1573. #passthru #define SYS_HIBER      SYS$HIBER
  1574.  
  1575. typedef struct _descr {
  1576.    int length;
  1577.    char *ptr;
  1578. } descriptor;
  1579.  
  1580. typedef struct _pipe {
  1581.    long pid;            /* process id of child */
  1582.    long status;            /* exit status of child */
  1583.    long flags;            /* LIB$SPAWN flags */
  1584.    int channel;            /* MBX channel number */
  1585.    int efn;            /* Event flag to wait for */
  1586.    char mode;            /* the open mode */
  1587.    FILE *fptr;            /* file pointer (for fun) */
  1588.    unsigned running : 1;    /* 1 if child is running */
  1589. } Pipe;
  1590.  
  1591. Pipe _pipes[_NFILE];        /* one for every open file */
  1592.  
  1593. #define NOWAIT        1
  1594. #define NOCLISYM    2
  1595. #define NOLOGNAM    4
  1596. #define NOKEYPAD    8
  1597. #define NOTIFY        16
  1598. #define NOCONTROL    32
  1599. #define SFLAGS    (NOWAIT|NOKEYPAD|NOCONTROL)
  1600.  
  1601. /*
  1602.  * delay_vms - delay for n milliseconds
  1603.  */
  1604.  
  1605. void delay_vms(n)
  1606. int n;
  1607. {
  1608.    int pid = getpid();
  1609.    int delay_time[2];
  1610.  
  1611.    delay_time[0] = -1000 * n;
  1612.    delay_time[1] = -1;
  1613.    SYS_SCHDWK(&pid, 0, delay_time, 0);
  1614.    SYS_HIBER();
  1615. }
  1616.  
  1617. /*
  1618.  * popen - open a pipe command
  1619.  * Last modified 2-Apr-86/chj
  1620.  *
  1621.  *    popen("command", mode)
  1622.  */
  1623.  
  1624. FILE *popen(cmd, mode)
  1625. char *cmd;
  1626. char *mode;
  1627. {
  1628.    FILE *pfile;            /* the Pfile */
  1629.    Pipe *pd;            /* _pipe database */
  1630.    descriptor mbxname;        /* name of mailbox */
  1631.    descriptor command;        /* command string descriptor */
  1632.    descriptor nl;        /* null device descriptor */
  1633.    char mname[65];        /* mailbox name string */
  1634.    int chan;            /* mailbox channel number */
  1635.    int status;            /* system service status */
  1636.    int efn;
  1637.    struct {
  1638.       short len;
  1639.       short code;
  1640.       char *address;
  1641.       char *retlen;
  1642.       int last;
  1643.    } itmlst;
  1644.  
  1645.    if (!cmd || !mode)
  1646.       return (0);
  1647.    LIB_GET_EF(&efn);
  1648.    if (efn == -1)
  1649.       return (0);
  1650.    if (_tolower(mode[0]) != 'r' && _tolower(mode[0]) != 'w')
  1651.       return (0);
  1652.    /* create and open the mailbox */
  1653.    status = SYS_CREMBX(0, &chan, 0, 0, 0, 0, 0);
  1654.    if (!(status & 1)) {
  1655.       LIB_FREE_EF(&efn);
  1656.       return (0);
  1657.    }
  1658.    itmlst.last = mbxname.length = 0;
  1659.    itmlst.address = mbxname.ptr = mname;
  1660.    itmlst.retlen = &mbxname.length;
  1661.    itmlst.code = DVI__DEVNAM;
  1662.    itmlst.len = 64;
  1663.    status = SYS_GETDVIW(0, chan, 0, &itmlst, 0, 0, 0, 0);
  1664.    if (!(status & 1)) {
  1665.       LIB_FREE_EF(&efn);
  1666.       return (0);
  1667.    }
  1668.    mname[mbxname.length] = '\0';
  1669.    pfile = fopen(mname, mode);
  1670.    if (!pfile) {
  1671.       LIB_FREE_EF(&efn);
  1672.       SYS_DASSGN(chan);
  1673.       return (0);
  1674.    }
  1675.    /* Save file information now */
  1676.    pd = &_pipes[fileno(pfile)];    /* get Pipe pointer */
  1677.    pd->mode = _tolower(mode[0]);
  1678.    pd->fptr = pfile;
  1679.    pd->pid = pd->status = pd->running = 0;
  1680.    pd->flags = SFLAGS;
  1681.    pd->channel = chan;
  1682.    pd->efn = efn;
  1683.    /* fork the command */
  1684.    nl.length = strlen("_NL:");
  1685.    nl.ptr = "_NL:";
  1686.    command.length = strlen(cmd);
  1687.    command.ptr = cmd;
  1688.    status = LIB_SPAWN(&command,
  1689.       (pd->mode == 'r') ? 0 : &mbxname,    /* input file */
  1690.       (pd->mode == 'r') ? &mbxname : 0,    /* output file */
  1691.       &pd->flags, 0, &pd->pid, &pd->status, &pd->efn, 0, 0, 0, 0);
  1692.    if (!(status & 1)) {
  1693.       LIB_FREE_EF(&efn);
  1694.       SYS_DASSGN(chan);
  1695.       return (0);
  1696.    } else {
  1697.       pd->running = 1;
  1698.    }
  1699.    return (pfile);
  1700. }
  1701.  
  1702. /*
  1703.  * pclose - close a pipe
  1704.  * Last modified 2-Apr-86/chj
  1705.  *
  1706.  */
  1707. pclose(pfile)
  1708. FILE *pfile;
  1709. {
  1710.    Pipe *pd;
  1711.    int status;
  1712.    int fstatus;
  1713.  
  1714.    pd = fileno(pfile) ? &_pipes[fileno(pfile)] : 0;
  1715.    if (pd == NULL)
  1716.       return (-1);
  1717.    fflush(pd->fptr);            /* flush buffers */
  1718.    fstatus = fclose(pfile);
  1719.    if (pd->mode == 'w') {
  1720.       status = SYS_QIOW(0, pd->channel, IO__WRITEOF, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  1721.       SYS_WFLOR(pd->efn, 1 << (pd->efn % 32));
  1722.    }
  1723.    SYS_DASSGN(pd->channel);
  1724.    LIB_FREE_EF(&pd->efn);
  1725.    pd->running = 0;
  1726.    return (fstatus);
  1727. }
  1728.  
  1729. /*
  1730.  * redirect(&argc,argv,nfargs) - redirect standard I/O
  1731.  *    int *argc        number of command arguments (from call to main)
  1732.  *    char *argv[]    command argument list (from call to main)
  1733.  *    int nfargs    number of filename arguments to process
  1734.  *
  1735.  * argc and argv will be adjusted by redirect.
  1736.  *
  1737.  * redirect processes a program's command argument list and handles redirection
  1738.  * of stdin, and stdout.  Any arguments which redirect I/O are removed from the
  1739.  * argument list, and argc is adjusted accordingly.  redirect would typically be
  1740.  * called as the first statement in the main program.
  1741.  *
  1742.  * Files are redirected based on syntax or position of command arguments.
  1743.  * Arguments of the following forms always redirect a file:
  1744.  *
  1745.  *    <file    redirects standard input to read the given file
  1746.  *    >file    redirects standard output to write to the given file
  1747.  *    >>file    redirects standard output to append to the given file
  1748.  *
  1749.  * It is often useful to allow alternate input and output files as the
  1750.  * first two command arguments without requiring the <file and >file
  1751.  * syntax.  If the nfargs argument to redirect is 2 or more then the
  1752.  * first two command arguments, if supplied, will be interpreted in this
  1753.  * manner:  the first argument replaces stdin and the second stdout.
  1754.  * A filename of "-" may be specified to occupy a position without
  1755.  * performing any redirection.
  1756.  *
  1757.  * If nfargs is 1, only the first argument will be considered and will
  1758.  * replace standard input if given.  Any arguments processed by setting
  1759.  * nfargs > 0 will be removed from the argument list, and again argc will
  1760.  * be adjusted.  Positional redirection follows syntax-specified
  1761.  * redirection and therefore overrides it.
  1762.  *
  1763.  */
  1764.  
  1765.  
  1766. redirect(argc,argv,nfargs)
  1767. int *argc, nfargs;
  1768. char *argv[];
  1769. {
  1770.    int i;
  1771.  
  1772.    i = 1;
  1773.    while (i < *argc)  {        /* for every command argument... */
  1774.       switch (argv[i][0])  {        /* check first character */
  1775.          case '<':            /* <file redirects stdin */
  1776.             filearg(argc,argv,i,1,stdin,"r");
  1777.             break;
  1778.          case '>':            /* >file or >>file redirects stdout */
  1779.             if (argv[i][1] == '>')
  1780.                filearg(argc,argv,i,2,stdout,"a");
  1781.             else
  1782.                filearg(argc,argv,i,1,stdout,"w");
  1783.             break;
  1784.          default:            /* not recognized, go on to next arg */
  1785.             i++;
  1786.       }
  1787.    }
  1788.    if (nfargs >= 1 && *argc > 1)    /* if positional redirection & 1 arg */
  1789.       filearg(argc,argv,1,0,stdin,"r");    /* then redirect stdin */
  1790.    if (nfargs >= 2 && *argc > 1)    /* likewise for 2nd arg if wanted */
  1791.       filearg(argc,argv,1,0,stdout,"w");/* redirect stdout */
  1792. }
  1793.  
  1794.  
  1795.  
  1796. /* filearg(&argc,argv,n,i,fp,mode) - redirect and remove file argument
  1797.  *    int *argc        number of command arguments (from call to main)
  1798.  *    char *argv[]    command argument list (from call to main)
  1799.  *    int n        argv entry to use as file name and then delete
  1800.  *    int i        first character of file name to use (skip '<' etc.)
  1801.  *    FILE *fp        file pointer for file to reopen (typically stdin etc.)
  1802.  *    char mode[]    file access mode (see freopen spec)
  1803.  */
  1804.  
  1805. filearg(argc,argv,n,i,fp,mode)
  1806. int *argc, n, i;
  1807. char *argv[], mode[];
  1808. FILE *fp;
  1809. {
  1810.    if (strcmp(argv[n]+i,"-"))        /* alter file if arg not "-" */
  1811.       fp = freopen(argv[n]+i,mode,fp);
  1812.    if (fp == NULL)  {            /* abort on error */
  1813.       fprintf(stderr,"%%can't open %s",argv[n]+i);
  1814.       exit(ErrorExit);
  1815.    }
  1816.    for ( ;  n < *argc;  n++)        /* move down following arguments */
  1817.       argv[n] = argv[n+1];
  1818.    *argc = *argc - 1;            /* decrement argument count */
  1819. }
  1820.  
  1821. #ifdef KeyboardFncs
  1822.  
  1823. short channel;
  1824. int   request_queued = 0;
  1825. int   char_available = 0;
  1826. char  char_typed;
  1827.  
  1828. void assign_channel_to_terminal()
  1829. {
  1830.    descriptor terminal;
  1831.  
  1832.    terminal.length = strlen("SYS$COMMAND");
  1833.    terminal.ptr    = "SYS$COMMAND";
  1834.    SYS_ASSIGN(&terminal, &channel, 0, 0);
  1835. }
  1836.  
  1837. word read_a_char(echo_on)
  1838. int echo_on;
  1839. {
  1840.    if (char_available) {
  1841.       char_available = 0;
  1842.       if (echo_on)
  1843.          SYS_QIOW(2, channel, IO__WRITEVBLK, 0, 0, 0, &char_typed, 1,
  1844.           0, 32, 0, 0);
  1845.       goto return_char;
  1846.       }
  1847.    if (echo_on)
  1848.       SYS_QIOW(1, channel, IO__TTYREADALL, 0, 0, 0, &char_typed, 1, 0, 0, 0, 0);
  1849.    else
  1850.       SYS_QIOW(1, channel, IO__TTYREADALL | IO_M_NOECHO, 0, 0, 0,
  1851.            &char_typed, 1, 0, 0, 0, 0);
  1852.  
  1853. return_char:
  1854.    if (char_typed == '\003' && kill(getpid(), SIGINT) == -1) {
  1855.       perror("kill");
  1856.       return 0;
  1857.       }
  1858.    if (char_typed == '\034' && kill(getpid(), SIGQUIT) == -1) {
  1859.       perror("kill");
  1860.       return 0;
  1861.       }
  1862.    return (word)char_typed;
  1863. }
  1864.  
  1865. word getch()
  1866. {
  1867.    return read_a_char(0);
  1868. }
  1869.  
  1870. word getche()
  1871. {
  1872.    return read_a_char(1);
  1873. }
  1874.  
  1875. void ast_proc()
  1876. {
  1877.    char_available = 1;
  1878.    request_queued = 0;
  1879. }
  1880.  
  1881. int kbhit()
  1882. {
  1883.    if (!request_queued) {
  1884.       request_queued = 1;
  1885.       SYS_QIO(1, channel, IO__TTYREADALL | IO_M_NOECHO, 0, ast_proc, 0,
  1886.               &char_typed, 1, 0, 0, 0, 0);
  1887.       }
  1888.    return char_available;
  1889. }
  1890.  
  1891. #endif                    /* KeyboardFncs */
  1892.  
  1893. #endif                    /* VMS */
  1894. /*
  1895.  * End of operating-system specific code.
  1896.  */
  1897.  
  1898. static char x;            /* avoid empty module */
  1899.