home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / runtime / rlocal.r < prev    next >
Text File  |  2002-01-18  |  32KB  |  1,466 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.  
  25. /*********************************** AMIGA ***********************************/
  26.  
  27. #if AMIGA
  28. #if LATTICE
  29. long _STACK = 20000;
  30. long _MNEED = 200000;    /* reserve space for allocation (may be too large) */
  31. #endif                    /* LATTICE */
  32. #if __SASC
  33. long __stack = 20000;
  34. #endif                    /* __SASC */
  35. #if AZTEC_C
  36. /*
  37.  * abs
  38.  */
  39. abs(i)
  40. int i;
  41. {
  42.     return ((i<0)? (-i) : i);
  43. }
  44.  
  45. /*
  46.  * ldexp
  47.  */
  48. double ldexp(value,exp)
  49. double value;
  50. {
  51.   double retval = 1.0;
  52.   if(exp>0) {
  53.     while(exp-->0) retval *= 2.0;
  54.   } else if (exp<0) {
  55.     while(exp++<0) retval = retval / 2.0;
  56.   }
  57.   return value * retval;
  58. }
  59.  
  60. /*
  61.  *  abort()
  62.  */
  63. void abort()
  64. {
  65.   fprintf(stderr,"icon error with ICONCORE set\n");
  66.   fflush(stderr);
  67.   exit(1);
  68. }
  69.  
  70. #endif                    /* AZTEC_C */
  71.  
  72. /* Implement popen and pclose using Per Bojsen's APipe-Handler */
  73.  
  74. FILE *popen(const char *pname, const char *mode) {
  75.  
  76.    char *exname;
  77.    char device[] = "APIPE:";
  78.    FILE *fp;
  79.  
  80.    exname = malloc(strlen(pname) + strlen(device) + 1);
  81.    strcpy(exname, device);
  82.    strcat(exname, pname);
  83.    fp = fopen(exname, mode);
  84.    free(exname);
  85.    return fp;
  86.    }
  87.  
  88. int pclose(FILE *pipe) {
  89.    return fclose(pipe);
  90.    }
  91.  
  92. #endif                    /* AMIGA */
  93.  
  94. /*********************************** ARM ***********************************/
  95.  
  96. #if ARM
  97. #include "kernel.h"
  98.  
  99. char *mktemp (const char *);
  100.  
  101. static char *strdup (const char *);
  102. static int os_cmd (char *);
  103. static int cmp_cmd (char *, char *);
  104.  
  105. #define MAX_PIPE 20
  106.  
  107. typedef enum
  108. {
  109.    unopened = 0,
  110.    reading,
  111.    writing
  112. }
  113. pipemode;
  114.  
  115. static struct pipe
  116. {
  117.    char *command;   /* The command being executed      */
  118.    char *name;   /* The name of the pipe file      */
  119.    FILE *fd;   /* The file used as a pipe      */
  120.    pipemode pmode;   /* The open mode of the pipe      */
  121.    int retval;   /* The return value of the command   */
  122. }
  123. pipes[MAX_PIPE];
  124.  
  125. FILE *popen (char *command, char *mode)
  126. {
  127.    FILE *current;
  128.    char *name;
  129.    int i;
  130.    pipemode curmode;
  131.    int rval = -1;
  132.    char tmp[11];
  133.  
  134.    /* decide on mode */
  135.    if ( mode[1] != 0 )
  136.       return NULL;
  137.    else if ( *mode == 'r' )
  138.       curmode = reading;
  139.    else if ( *mode == 'w' )
  140.       curmode = writing;
  141.    else
  142.       return NULL;
  143.  
  144.    /* Get a slot in the pipes structure */
  145.    for ( i = 0; i < MAX_PIPE; ++i )
  146.    {
  147.       if ( pipes[i].pmode == unopened )
  148.          break;
  149.    }
  150.  
  151.    if ( i >= MAX_PIPE )
  152.       return NULL;
  153.  
  154.    /* Get a file name to use */
  155.    sprintf(tmp, "Pipe%.2d", i);
  156.    name = mktemp(tmp);
  157.  
  158.    if ( name == NULL )
  159.       return NULL;
  160.  
  161.    /*
  162.     * If we're reading, just call system() to get a file filled
  163.     * with output.
  164.     */
  165.  
  166.    if ( curmode == reading )
  167.    {
  168.       char *tmpname;
  169.       int oscmd = os_cmd(command);
  170.       char cmd[256];
  171.       int n;
  172.  
  173.       if (*command == '%')
  174.       {
  175.          oscmd = 1;
  176.          ++command;
  177.       }
  178.  
  179.       if (!oscmd)
  180.       {
  181.          char *s;
  182.  
  183.          while (*command && isspace(*command))
  184.             ++command;
  185.  
  186.          s = command;
  187.  
  188.          while (*s && !isspace(*s))
  189.             ++s;
  190.  
  191.          n = sprintf(cmd, "%.*s > %s%s",
  192.             s - command, command, name, s);
  193.       }
  194.       else
  195.       {
  196.          tmpname = mktemp("PipeTmp");
  197.  
  198.          if (tmpname == NULL)
  199.          {
  200.             free(name);
  201.             return NULL;
  202.          }
  203.  
  204.          n = sprintf(cmd, "%s{ > %s }", command, tmpname);
  205.       }
  206.  
  207.       /* Emergency! Overflow in command buffer! */
  208.       if (n > 255)
  209.       {
  210.          if (oscmd)
  211.          {
  212.             remove(tmpname);
  213.             free(tmpname);
  214.          }
  215.          free(name);
  216.          return NULL;
  217.       }
  218.  
  219.       _kernel_setenv("Sys$ReturnCode", "0");
  220.       rval = system(cmd);
  221.  
  222.       if (rval == _kernel_ERROR)
  223.       {
  224.          remove(tmpname);
  225.          free(tmpname);
  226.          free(name);
  227.          return NULL;
  228.       }
  229.  
  230.       if (oscmd)
  231.       {
  232.          int ch;
  233.          FILE *in = fopen(tmpname, "r");
  234.          FILE *out = fopen(name, "w");
  235.  
  236.          if (in == NULL || out == NULL)
  237.          {
  238.             remove(tmpname);
  239.             free(tmpname);
  240.             free(name);
  241.             return NULL;
  242.          }
  243.  
  244.          /* Strip out CRs from the output */
  245.          while ((ch = getc(in)) != EOF && !ferror(out))
  246.          {
  247.             if (ch != '\r')
  248.                putc(ch, out);
  249.          }
  250.  
  251.          /* Did we succeed? */
  252.          ch = (ferror(in) || ferror(out));
  253.  
  254.          /* Tidy up */
  255.          fclose(in);
  256.          fclose(out);
  257.          remove(tmpname);
  258.          free(tmpname);
  259.  
  260.          if (ch)
  261.          {
  262.             free(name);
  263.             return NULL;
  264.          }
  265.       }
  266.  
  267.       if ( (current = fopen(name,"r")) == NULL )
  268.       {
  269.          free(name);
  270.          return NULL;
  271.       }
  272.    }
  273.    else
  274.    {
  275.       if ( (current = fopen(name,"w")) == NULL )
  276.       {
  277.          free(name);
  278.          return NULL;
  279.       }
  280.    }
  281.  
  282.    pipes[i].command = strdup(command);
  283.    pipes[i].name = name;
  284.    pipes[i].fd = current;
  285.    pipes[i].pmode = curmode;
  286.    pipes[i].retval = rval;
  287.    return current;
  288. }
  289.  
  290. #define ReadCat    5
  291.  
  292. /* Create a temporary file name by adding a directory prefix to file.
  293.  * If the external variable temp_dir is not zero, this directory will be
  294.  * used. Otherwise, the following are used, in order.
  295.  *   1. <Tmp$Dir>
  296.  *   2. &.Tmp
  297.  *   3. The current directory.
  298.  * The function returns zero on an error (temp_dir is not a directory, or
  299.  * malloc() failed), otherwise it returns a malloc-ed string containing
  300.  * the required name.
  301.  */
  302.  
  303. static char *concat (const char *dir, const char *file);
  304.  
  305. char *temp_dir = 0;
  306.  
  307. char *mktemp (const char *file)
  308. {
  309.    char *dir;
  310.    char *name;
  311.    char buf[11];
  312.    int len = strlen(file);
  313.    _kernel_osfile_block blk;
  314.    _kernel_swi_regs regs;
  315.  
  316.    /* Is the supplied filename a pure file name? */
  317.    if (len > 10)
  318.       return 0;
  319.  
  320.    /* Pad out the supplied filename on the left with a unique ID
  321.     * (Based on the program start time)
  322.     */
  323.    if (len < 10 && _kernel_swi(OS_GetEnv,®s,®s) == NULL)
  324.    {
  325.       int i;
  326.       char *time = (char *)regs.r[2];
  327.  
  328.       strcpy(buf,file);
  329.  
  330.       for (i = len; i < 10; ++i)
  331.       {
  332.          char c = time[(9 - i) >> 1];
  333.  
  334.          if (i & 1)
  335.             c >>= 4;
  336.  
  337.          c &= 0x0F;
  338.          buf[i] = "abcdefghijklmnop"[c];
  339.       }
  340.  
  341.       buf[10] = 0;
  342.  
  343.       file = buf;
  344.    }
  345.  
  346.    /* First, try the supplied directory */
  347.    if ( temp_dir )
  348.    {
  349.       if ( _kernel_osfile(ReadCat,temp_dir,&blk) == 2 )
  350.          return concat(temp_dir,file);
  351.       else
  352.       {
  353.          /* Is it a filing system name only? */
  354.          len = strlen(temp_dir);
  355.  
  356.          if (temp_dir[len-1] != ':')
  357.             return 0;
  358.  
  359.          /* One extra, just in case file == "", for the '@' */
  360.          name = malloc(len + strlen(file) + 2);
  361.  
  362.          if (name == 0)
  363.             return 0;
  364.  
  365.          strcpy(name,temp_dir);
  366.          name[len] = '@';
  367.          name[len+1] = '\0';
  368.  
  369.          if (_kernel_osfile(ReadCat,name,&blk) != 2)
  370.          {
  371.             free(name);
  372.             return 0;
  373.          }
  374.  
  375.          strcpy(&name[len],file);
  376.          return name;
  377.       }
  378.    }
  379.  
  380.    /* Otherwise, go through the list... */
  381.  
  382.    /* First of all, try <Tmp$Dir> */
  383.    if ((dir = getenv("Tmp$Dir")) != 0)
  384.    {
  385.       if (_kernel_osfile(ReadCat,dir,&blk) == 2)
  386.          return concat(dir,file);
  387.       else
  388.       {
  389.          /* Is it a filing system name only? */
  390.          len = strlen(dir);
  391.  
  392.          if (dir[len-1] != ':')
  393.             goto no_go;
  394.  
  395.          /* One extra, just in case file == "", for the '@' */
  396.          name = malloc(len + strlen(file) + 2);
  397.  
  398.          if (name == 0)
  399.             goto no_go;
  400.  
  401.          strcpy(name,dir);
  402.          name[len] = '@';
  403.          name[len+1] = '\0';
  404.  
  405.          if (_kernel_osfile(ReadCat,name,&blk) != 2)
  406.          {
  407.             free(name);
  408.             goto no_go;
  409.          }
  410.  
  411.          strcpy(&name[len],file);
  412.          return name;
  413.       }
  414.    }
  415.  
  416. no_go:
  417.    /* No <Tmp$Dir>, so try &.Tmp, if it exists */
  418.    if (_kernel_osfile(ReadCat,"&.Tmp",&blk) == 2)
  419.       return concat("&.Tmp",file);
  420.  
  421.    /* Out of luck - use the current directory */
  422.    name = malloc(strlen(file)+1);
  423.    if ( name )
  424.       strcpy(name,file);
  425.  
  426.    return name;
  427. }
  428.  
  429. static char *concat (const char *dir, const char *file)
  430. {
  431.     char *result = malloc(strlen(dir)+strlen(file)+2);
  432.     char *p = result;
  433.  
  434.     if ( result == 0 )
  435.         return 0;
  436.  
  437.     while ( *dir )
  438.         *p++ = *dir++;
  439.  
  440.     *p++ = '.';
  441.     while ( *file )
  442.         *p++ = *file++;
  443.  
  444.     *p = '\0';
  445.  
  446.     return result;
  447. }
  448.  
  449. /* ----------------------------------------------------------------- */
  450.  
  451. #ifdef test
  452.  
  453. int main (int argc, char *argv[])
  454. {
  455.     char *tmp;
  456.  
  457.     if ( argc != 2 && argc != 3 )
  458.     {
  459.         fprintf(stderr,"Usage: %s file [dir]\n",argv[0]);
  460.         return 1;
  461.     }
  462.  
  463.     if ( argc == 3 )
  464.         temp_dir = argv[2];
  465.  
  466.     tmp = mktemp (argv[1]);
  467.  
  468.     printf("Temp file = %s\n", tmp ? tmp : "<Not possible>");
  469.  
  470.     return 0;
  471. }
  472.  
  473. #endif
  474.  
  475. int pclose (FILE *current)
  476. {
  477.     int rval;
  478.     int i;
  479.  
  480.     /* Get the appropriate slot in thbe pipes structure */
  481.     for ( i = 0; i < MAX_PIPE; ++i )
  482.     {
  483.         if ( pipes[i].fd == current )
  484.             break;
  485.     }
  486.  
  487.     if ( i >= MAX_PIPE )
  488.         return -1;
  489.  
  490.     if ( pipes[i].pmode == reading )
  491.     {
  492.         /* Input pipes are just files we're done with */
  493.         rval = pipes[i].retval;
  494.         fclose(current);
  495.         remove(pipes[i].name);
  496.     }
  497.     else
  498.     {
  499.         /*
  500.          * Output pipes are temporary files we have
  501.          * to cram down the throats of programs.
  502.          */
  503.         char *command = pipes[i].command;
  504.         int oscmd = os_cmd(command);
  505.         int n;
  506.         char cmd[256];
  507.  
  508.         if (*command == '%')
  509.         {
  510.             oscmd = 1;
  511.             ++command;
  512.         }
  513.  
  514.         /* Close the pipe file */
  515.         fclose(current);
  516.  
  517.         /* Create the required command string */
  518.         if (oscmd)
  519.             n = sprintf(cmd, "%s{ < %s }", command, pipes[i].name);
  520.         else
  521.         {
  522.             char *s;
  523.  
  524.             while (*command && isspace(*command))
  525.                 ++command;
  526.  
  527.             s = command;
  528.  
  529.             while (*s && !isspace(*s))
  530.                 ++s;
  531.  
  532.             n = sprintf(cmd, "%.*s < %s%s",
  533.                 s - command, command, pipes[i].name, s);
  534.         }
  535.  
  536.         /* Check for overflow in command buffer */
  537.         if (n > 255)
  538.             rval = -1;
  539.         else
  540.         {
  541.             _kernel_setenv("Sys$ReturnCode", "0");
  542.             rval = system(cmd);
  543.         }
  544.  
  545.         remove(pipes[i].name);
  546.     }
  547.  
  548.     /* clean up current pipe */
  549.     pipes[i].pmode = unopened;
  550.     free(pipes[i].name);
  551.     free(pipes[i].command);
  552.     return rval;
  553. }
  554.  
  555. /* save a string on the heap; return pointer to it */
  556.  
  557. static char *strdup (const char *str)
  558. {
  559.     char *p = malloc(strlen(str)+1);
  560.  
  561.     if (p == NULL)
  562.     {
  563.         fprintf(stderr,"Not enough memory to save string\n");
  564.         exit(1);
  565.     }
  566.  
  567.     return (strcpy(p,str));
  568. }
  569.  
  570. /* Check whether a command is an OS command (binary search on the table
  571.  * os_commands of valid OS commands).
  572.  */
  573.  
  574. static char *os_commands[] =
  575. {
  576.     "access",    "adfs",        "alphabet",    "alphabets",
  577.     "append",    "audio",    "basic",    "breakclr",
  578.     "breaklist",    "breakset",    "build",    "cat",
  579.     "cdir",        "channelvoice",    "close",    "configure",
  580.     "continue",    "copy",        "count",    "countries",
  581.     "country",    "create",    "debug",    "delete",
  582.     "deskfs",    "dir",        "dump",        "echo",
  583.     "enumdir",    "error",    "eval",        "ex",
  584.     "exec",        "fileinfo",    "fontcat",    "fontlist",
  585.     "fx",        "go",        "gos",        "help",
  586.     "iconsprites",    "if",        "ignore",    "info",
  587.     "initstore",    "key",        "keyboard",    "lcat",
  588.     "lex",        "lib",        "list",        "load",
  589.     "memory",    "memorya",    "memoryi",    "modules",
  590.     "obey",        "opt",        "poduleload",    "podules",
  591.     "podulesave",    "pointer",    "print",    "qsound",
  592.     "quit",        "ram",        "remove",    "rename",
  593.     "rmclear",    "rmensure",    "rmfaster",    "rmkill",
  594.     "rmload",    "rmreinit",    "rmrun",    "rmtidy",
  595.     "rommodules",    "run",        "save",        "schoose",
  596.     "scopy",    "screenload",    "screensave",    "sdelete",
  597.     "set",        "seteval",    "setmacro",    "settype",
  598.     "sflipx",    "sflipy",    "sget",        "shadow",
  599.     "shellcli",    "show",        "showregs",    "shut",
  600.     "shutdown",    "sinfo",    "slist",    "sload",
  601.     "smerge",    "snew",        "sound",    "speaker",
  602.     "spool",    "spoolon",    "srename",    "ssave",
  603.     "stamp",    "status",    "stereo",    "tempo",
  604.     "time",        "tuning",    "tv",        "type",
  605.     "unplug",    "unset",    "up",        "voices",
  606.     "volume",    "wimppalette",    "wimpslot",    "wimptask",
  607.     "wipe"
  608. };
  609.  
  610. #define NUM_CMDS (sizeof(os_commands) / sizeof(char *))
  611.  
  612. static int os_cmd (char *cmd)
  613. {
  614.     int low = 0;
  615.     int high = NUM_CMDS - 1;
  616.  
  617.     while (low <= high)
  618.     {
  619.         int mid = (high + low) / 2;
  620.         int i = cmp_cmd(cmd,os_commands[mid]);
  621.  
  622.         if (i == 0)
  623.             return 1;
  624.         else if (i < 0)
  625.             high = mid - 1;
  626.         else
  627.             low = mid + 1;
  628.     }
  629.  
  630.     return 0;
  631. }
  632.  
  633. static int cmp_cmd (char *cmd, char *name)
  634. {
  635.     while (*name && tolower(*cmd) == *name)
  636.         ++name, ++cmd;
  637.  
  638.     if (*name)
  639.         return (tolower(*cmd) - *name);
  640.  
  641.     return (*cmd != '\0' && !isspace(*cmd));
  642. }
  643.  
  644. #ifdef test
  645. int main (int argc, char *argv[])
  646. {
  647.     FILE *fp;
  648.     char *cmd;
  649.  
  650.     if (argc <= 1)
  651.     {
  652.         printf("Usage Popen [cmd or Popen ]cmd\n");
  653.         return 0;
  654.     }
  655.  
  656.     cmd = argv[1];
  657.  
  658.     if (*cmd++ == ']')
  659.     {
  660.         fp = popen(cmd,"w");
  661.         fprintf(fp,"hello\nworld\nhow\nare\nyou\n");
  662.         pclose(fp);
  663.     }
  664.     else
  665.     {
  666.         char buf[500];
  667.         fp = popen(cmd,"r");
  668.         while (!feof(fp))
  669.         {
  670.             if (!fgets(buf,499,fp))
  671.             {
  672.                 printf("Read error!\n");
  673.                 return 1;
  674.             }
  675.             buf[strlen(buf)-1] = 0;
  676.             printf(">%s<\n", buf);
  677.         }
  678.         pclose(fp);
  679.     }
  680.  
  681.     return 0;
  682. }
  683. #endif
  684.  
  685. int getch (void)
  686. {
  687.     return _kernel_osrdch();
  688. }
  689.  
  690. int getche (void)
  691. {
  692.     int ch = _kernel_osrdch();
  693.  
  694.     _kernel_oswrch(ch);
  695.  
  696.     return ch;
  697. }
  698.  
  699. int kbhit (void)
  700. {
  701.     return ((_kernel_osbyte(152,0,0) & 0x00FF0000) != 0x00010000);
  702. }
  703.  
  704. #endif                    /* ARM */
  705.  
  706. /*********************************** MAC ***********************************/
  707.  
  708. #if MACINTOSH
  709. #if MPW
  710. /*
  711.  * Special routines for Macintosh Programmer's Workshop (MPW) implementation
  712.  *  of the Icon Programming Language
  713.  */
  714.  
  715. #include <Types.h>
  716. #include <Events.h>
  717. #include <Files.h>
  718. #include <FCntl.h>
  719. #include <IOCtl.h>
  720. #include <SANE.h>
  721. #include <OSUtils.h>
  722. #include <Memory.h>
  723. #include <Errors.h>
  724. #include "time.h"
  725. #include <QuickDraw.h>
  726. #include <ToolUtils.h>
  727. #include <CursorCtl.h>
  728.  
  729. #define isatty(fd) (!ioctl((fd), FIOINTERACTIVE))
  730.  
  731.    void
  732. SetFileToMPWText(const char *fname) {
  733.    FInfo info;
  734.    int needToSet = 0;
  735.  
  736.    if (getfinfo(fname,0,&info) == 0) {
  737.       if (info.fdType == 0) {
  738.      info.fdType = 'TEXT';
  739.      needToSet = 1;
  740.      }
  741.       if (info.fdCreator == 0) {
  742.      info.fdCreator = 'MPS ';
  743.      needToSet = 1;
  744.      }
  745.       if (needToSet) {
  746.      setfinfo(fname,0,&info);
  747.      }
  748.       }
  749.    return;
  750.    }
  751.  
  752.  
  753.    int
  754. MPWFlush(FILE *f) {
  755.    static int fetched = 0;
  756.    static char *noLineFlush;
  757.  
  758.    if (!fetched) {
  759.       noLineFlush = getenv("NOLINEFLUSH");
  760.       fetched = 1;
  761.       }
  762.    if (!noLineFlush || noLineFlush[0] == '\0')
  763.          fflush(f);
  764.    return 0;
  765.    }
  766.  
  767.  
  768.    void
  769. SetFloatTrap(void (*fpetrap)()) {
  770.    /* This is equivalent to SIGFPE signal in the Standard Apple
  771.       Numeric Environment (SANE) */
  772.    environment e;
  773.  
  774.    getenvironment(&e);
  775.       #ifdef mc68881
  776.      e.FPCR |= CURUNDERFLOW|CUROVERFLOW|CURDIVBYZERO;
  777.       #else                    /* mc68881 */
  778.      e |= UNDERFLOW|OVERFLOW|DIVBYZERO;
  779.       #endif                    /* mc68881 */
  780.    setenvironment(e);
  781.    #ifdef mc68881
  782.       {
  783.       static trapvector tv =
  784.          {fpetrap,fpetrap,fpetrap,fpetrap,fpetrap,fpetrap,fpetrap};
  785.       settrapvector(&tv);
  786.       }
  787.    #else                    /* mc68881 */
  788.       sethaltvector((haltvector)fpetrap);
  789.    #endif                    /* mc68881 */
  790.    }
  791.  
  792.  
  793.    void
  794. SetWatchCursor(void) {
  795.    SetCursor(*GetCursor(watchCursor));    /* Set watch cursor */
  796.    }
  797.  
  798.  
  799. #define TicksPerRotation 10 /* rotate cursor no more often than 6 times
  800.                  per second */
  801.  
  802.    void
  803. RotateTheCursor(void) {
  804.    static unsigned long nextRotate = 0;
  805.    if (TickCount() >= nextRotate) {
  806.       RotateCursor(0);
  807.       nextRotate = TickCount() + TicksPerRotation;
  808.       }
  809.    else {
  810.       RotateCursor(1);
  811.       }
  812.    }
  813.  
  814. /*
  815.  *  Initialization and Termination Routines
  816.  */
  817.  
  818. /*
  819.  *  MacExit -- This function is installed by an atexit() call in MacInit
  820.  *  -- it is called automatically when the program terminates.
  821.  */
  822.    void
  823. MacExit() {
  824.    void ResetStack();
  825.    extern Ptr MemBlock;
  826.  
  827.    ResetStack();
  828.    /* if (MemBlock != NULL) DisposPtr(MemBlock); */
  829.    }
  830.  
  831. /*
  832.  *  MacInit -- This function is called near the beginning of execution of
  833.  *  iconx.  It is called by our own brk/sbrk initialization routine.
  834.  */
  835.    void
  836. MacInit() {
  837.    atexit(MacExit);
  838.    return;
  839.    }
  840.  
  841. /*
  842.  * MacDelay -- Delay n milliseconds.
  843.  */
  844.    void
  845. MacDelay(int n) {
  846.    unsigned long endTicks;
  847.    unsigned long nextRotate;
  848.  
  849.    endTicks = TickCount() + (n * 3 + 25) / 50;
  850.    nextRotate = 0;
  851.    while (TickCount() < endTicks) {
  852.       if (TickCount() >= nextRotate) {
  853.          nextRotate = TickCount() + TicksPerRotation;
  854.      RotateCursor(0);
  855.          }
  856.       else {
  857.          RotateCursor(1);
  858.      }
  859.       }
  860.    }
  861. #endif                    /* MPW */
  862. #endif                    /* MACINTOSH */
  863.  
  864. /*********************************** MSDOS ***********************************/
  865.  
  866. #if MSDOS
  867. #if INTEL_386
  868. /*  sbrk(incr) - adjust the break value by incr.
  869.  *  Returns the new break value, or -1 if unsuccessful.
  870.  */
  871.  
  872. pointer sbrk(incr)
  873. msize incr;
  874. {
  875.    static pointer base = 0;        /* base of the sbrk region */
  876.    static pointer endofmem, curr;
  877.    pointer result;
  878.    union REGS rin, rout;
  879.  
  880.    if (!base) {                    /* if need to initialize                */
  881.       rin.w.eax = 0x80004800;    /* use DOS allocate function with max    */
  882.       rin.w.ebx = 0xffffffff;    /*  request to determine size of free    */
  883.       intdos(&rin, &rout);        /*  memory (including virtual memory.    */
  884.       rin.w.ebx = rout.w.ebx;    /* DOS allocate all of memory.            */
  885.       intdos(&rin, &rout);
  886.       if (rout.w.cflag)
  887.          return (pointer)-1;
  888.       curr = base = (pointer)rout.w.eax;
  889.       endofmem = (pointer)((char *)base + rin.w.ebx);
  890.       }
  891.  
  892.    if ((char *)curr + incr > (char *)endofmem)
  893.       return (pointer)-1;
  894.    result = curr;
  895.    curr = (pointer)((char *)curr + incr);
  896.    return result;
  897.  
  898. }
  899.  
  900. /*  brk(addr) - set the break address to the given value, rounded up to a page.
  901.  *  returns 0 if successful, -1 if not.
  902.  */
  903.  
  904. int brk(addr)
  905. pointer addr;
  906. {
  907.    int result;
  908.    result = sbrk((char *)addr - (char *)sbrk(0)) == (pointer)-1 ? -1 : 0;
  909.    return result;
  910. }
  911.  
  912. #endif                    /* INTEL_386 */
  913.  
  914. #if TURBO
  915. extern unsigned _stklen = 16 * 1024;
  916. #endif                    /* TURBO */
  917.  
  918. #endif                    /* MSDOS */
  919.  
  920. /*********************************** OS/2 ***********************************/
  921.  
  922. #if OS2
  923. void abort()
  924. {
  925. #ifdef DeBugIconx
  926.     blkdump();
  927. #endif
  928.     fflush(stderr);
  929. #if CSET2
  930.     _fcloseall();
  931. #else
  932.     fcloseall();
  933. #endif        CSET2
  934.     _exit(1);
  935. }
  936.  
  937. #ifndef OS2EMX
  938. #if CSET2
  939. /* 20 is the default file handle max, this can be dynamically altered */
  940. #define _NFILE  20
  941. #endif        /* CSET2 */
  942.  
  943. static int _pipes[_NFILE];
  944.  
  945. /*
  946.  * popen("command",mode)
  947.  *
  948.  * cmd = command to be passed to shell. (CMD.EXE or comspec->)
  949.  * mode = "r" | "w"
  950.  */
  951. FILE *popen(char *cmd, char *mode)
  952. {
  953. #if OS2_32
  954.     HFILE whandle, rhandle;
  955. #else
  956.     int whandle, rhandle;
  957. #endif        /* OS2_32 */
  958.     int phandle, chandle, shandle;
  959.     int rc;
  960.     char *cmdshell;
  961.  
  962.     /* Validate */
  963.     if(cmd == NULL || mode == NULL) return NULL;
  964.     if(tolower(*mode) != 'r' && tolower(*mode) != 'w')
  965.     return NULL;
  966.  
  967.     /* Create the pipe */
  968. #if OS2_32
  969.     if (DosCreatePipe(&rhandle, &whandle, (ULONG)BUFSIZ) < 0)
  970. #else
  971.     if (DosMakePipe(&rhandle, &whandle, BUFSIZ) < 0)
  972. #endif        /* OS2_32 */
  973.     return NULL;
  974.  
  975.     /* Dup STDIN or STDOUT to the pipe */
  976.     if (*mode == 'r') {
  977.     /* Dup stdout */
  978.     phandle = rhandle;
  979.     chandle = whandle;
  980.     shandle = dup(1);    /* Save STDOUT */
  981.     rc = dup2(chandle, 1);
  982.     } else {
  983.     /* Dup stdin */
  984.     phandle = whandle;
  985.     chandle = rhandle;
  986.     shandle = dup(0);    /* Save STDIN */
  987.     rc = dup2(chandle, 0);
  988.     }
  989.     if (rc < 0) {
  990.     perror("dup2");
  991.     return NULL;
  992.     }
  993.     close(chandle);
  994.  
  995.     /* Make sure that we don't pass this handle on */
  996.     DosSetFHandState(phandle, OPEN_FLAGS_NOINHERIT);
  997.  
  998.     /* Invoke the child, remember its processid */
  999.     cmdshell = getenv("COMSPEC");
  1000.     if (cmdshell == NULL) cmdshell = "CMD.EXE";
  1001.  
  1002.     _pipes[chandle] = spawnlp(P_NOWAIT, cmdshell, cmdshell,"/c",cmd, NULL);
  1003.  
  1004.     /* Clean up by reestablishing our STDIN/STDOUT */
  1005.     if (*mode == 'r')
  1006.     rc = dup2(shandle, 1);
  1007.     else
  1008.     rc = dup2(shandle, 0);
  1009.     if (rc < 0) {
  1010.     perror("dup2");
  1011.     return NULL;
  1012.     }
  1013.     close(shandle);
  1014.  
  1015.     return fdopen(phandle, mode);
  1016. }
  1017. pclose(ptr)
  1018. FILE *ptr;
  1019. {
  1020.     int status, pnum;
  1021.  
  1022.     pnum = fileno(ptr);
  1023.     fclose(ptr);
  1024.  
  1025.     /* Now wait for child to end */
  1026.     cwait(&status, _pipes[pnum], WAIT_GRANDCHILD);
  1027.  
  1028.     return status;
  1029. }
  1030. #endif                    /* OS2EMX */
  1031.  
  1032. /* End of pipe support for OS/2 */
  1033. #endif                    /* OS2 */
  1034.  
  1035. /*********************************** UNIX ***********************************/
  1036.  
  1037. #if UNIX
  1038.  
  1039. #ifdef KeyboardFncs
  1040.  
  1041. /*
  1042.  * Documentation notwithstanding, the Unix versions of the keyboard functions
  1043.  * read from standard input and not necessarily from the keyboard (/dev/tty).
  1044.  */
  1045. #define STDIN 0
  1046.  
  1047. /*
  1048.  * int getch() -- read character without echoing
  1049.  * int getche() -- read character with echoing
  1050.  *
  1051.  * Read and return a character from standard input in non-canonical
  1052.  * ("cbreak") mode.  Return -1 for EOF.
  1053.  *
  1054.  * Reading is done even if stdin is not a tty;
  1055.  * the tty get/set functions are just rejected by the system.
  1056.  */
  1057.  
  1058. int rchar(int with_echo);
  1059.  
  1060. int getch(void)        { return rchar(0); }
  1061. int getche(void)    { return rchar(1); }
  1062.  
  1063. int rchar(int with_echo)
  1064. {
  1065.    struct termios otty, tty;
  1066.    char c;
  1067.    int n;
  1068.  
  1069.    tcgetattr(STDIN, &otty);        /* get current tty attributes */
  1070.  
  1071.    tty = otty;
  1072.    tty.c_lflag &= ~ICANON;
  1073.    if (with_echo)
  1074.       tty.c_lflag |= ECHO;
  1075.    else
  1076.       tty.c_lflag &= ~ECHO;
  1077.    tcsetattr(STDIN, TCSANOW, &tty);    /* set temporary attributes */
  1078.  
  1079.    n = read(STDIN, &c, 1);        /* read one char from stdin */
  1080.  
  1081.    tcsetattr(STDIN, TCSANOW, &otty);    /* reset tty to original state */
  1082.  
  1083.    if (n == 1)                /* if read succeeded */
  1084.       return c & 0xFF;
  1085.    else
  1086.       return -1;
  1087. }
  1088.  
  1089. /*
  1090.  * kbhit() -- return nonzero if characters are available for getch/getche.
  1091.  */
  1092. int kbhit(void)
  1093. {
  1094.    struct termios otty, tty;
  1095.    fd_set fds;
  1096.    struct timeval tv;
  1097.    int rv;
  1098.  
  1099.    tcgetattr(STDIN, &otty);        /* get current tty attributes */
  1100.  
  1101.    tty = otty;
  1102.    tty.c_lflag &= ~ICANON;        /* disable input batching */
  1103.    tcsetattr(STDIN, TCSANOW, &tty);    /* set attribute temporarily */
  1104.  
  1105.    FD_ZERO(&fds);            /* initialize fd struct */
  1106.    FD_SET(STDIN, &fds);            /* set STDIN bit */
  1107.    tv.tv_sec = tv.tv_usec = 0;        /* set immediate return */
  1108.    rv = select(STDIN + 1, &fds, NULL, NULL, &tv);
  1109.  
  1110.    tcsetattr(STDIN, TCSANOW, &otty);    /* reset tty to original state */
  1111.  
  1112.    return rv;                /* return result */
  1113. }
  1114. #endif                    /* KeyboardFncs */
  1115.  
  1116. #endif                    /* UNIX */
  1117.  
  1118. /*********************************** VMS ***********************************/
  1119.  
  1120. #if VMS
  1121. #passthru #define LIB_GET_EF     LIB$GET_EF
  1122. #passthru #define SYS_CREMBX     SYS$CREMBX
  1123. #passthru #define LIB_FREE_EF    LIB$FREE_EF
  1124. #passthru #define DVI__DEVNAM    DVI$_DEVNAM
  1125. #passthru #define SYS_GETDVIW    SYS$GETDVIW
  1126. #passthru #define SYS_DASSGN     SYS$DASSGN
  1127. #passthru #define LIB_SPAWN      LIB$SPAWN
  1128. #passthru #define SYS_QIOW       SYS$QIOW
  1129. #passthru #define IO__WRITEOF    IO$_WRITEOF
  1130. #passthru #define SYS_WFLOR      SYS$WFLOR
  1131. #passthru #define sys_expreg     sys$expreg
  1132. #passthru #define STS_M_SUCCESS  STS$M_SUCCESS
  1133. #passthru #define sys_cretva     sys$cretva
  1134. #passthru #define SYS_ASSIGN     SYS$ASSIGN
  1135. #passthru #define SYS_QIO        SYS$QIO
  1136. #passthru #define IO__TTYREADALL IO$_TTYREADALL
  1137. #passthru #define IO__WRITEVBLK  IO$_WRITEVBLK
  1138. #passthru #define IO_M_NOECHO    IO$M_NOECHO
  1139. #passthru #define SYS_SCHDWK     SYS$SCHDWK
  1140. #passthru #define SYS_HIBER      SYS$HIBER
  1141.  
  1142. typedef struct _descr {
  1143.    int length;
  1144.    char *ptr;
  1145. } descriptor;
  1146.  
  1147. typedef struct _pipe {
  1148.    long pid;            /* process id of child */
  1149.    long status;            /* exit status of child */
  1150.    long flags;            /* LIB$SPAWN flags */
  1151.    int channel;            /* MBX channel number */
  1152.    int efn;            /* Event flag to wait for */
  1153.    char mode;            /* the open mode */
  1154.    FILE *fptr;            /* file pointer (for fun) */
  1155.    unsigned running : 1;    /* 1 if child is running */
  1156. } Pipe;
  1157.  
  1158. Pipe _pipes[_NFILE];        /* one for every open file */
  1159.  
  1160. #define NOWAIT        1
  1161. #define NOCLISYM    2
  1162. #define NOLOGNAM    4
  1163. #define NOKEYPAD    8
  1164. #define NOTIFY        16
  1165. #define NOCONTROL    32
  1166. #define SFLAGS    (NOWAIT|NOKEYPAD|NOCONTROL)
  1167.  
  1168. /*
  1169.  * delay_vms - delay for n milliseconds
  1170.  */
  1171.  
  1172. void delay_vms(n)
  1173. int n;
  1174. {
  1175.    int pid = getpid();
  1176.    int delay_time[2];
  1177.  
  1178.    delay_time[0] = -1000 * n;
  1179.    delay_time[1] = -1;
  1180.    SYS_SCHDWK(&pid, 0, delay_time, 0);
  1181.    SYS_HIBER();
  1182. }
  1183.  
  1184. /*
  1185.  * popen - open a pipe command
  1186.  * Last modified 2-Apr-86/chj
  1187.  *
  1188.  *    popen("command", mode)
  1189.  */
  1190.  
  1191. FILE *popen(cmd, mode)
  1192. char *cmd;
  1193. char *mode;
  1194. {
  1195.    FILE *pfile;            /* the Pfile */
  1196.    Pipe *pd;            /* _pipe database */
  1197.    descriptor mbxname;        /* name of mailbox */
  1198.    descriptor command;        /* command string descriptor */
  1199.    descriptor nl;        /* null device descriptor */
  1200.    char mname[65];        /* mailbox name string */
  1201.    int chan;            /* mailbox channel number */
  1202.    int status;            /* system service status */
  1203.    int efn;
  1204.    struct {
  1205.       short len;
  1206.       short code;
  1207.       char *address;
  1208.       char *retlen;
  1209.       int last;
  1210.    } itmlst;
  1211.  
  1212.    if (!cmd || !mode)
  1213.       return (0);
  1214.    LIB_GET_EF(&efn);
  1215.    if (efn == -1)
  1216.       return (0);
  1217.    if (_tolower(mode[0]) != 'r' && _tolower(mode[0]) != 'w')
  1218.       return (0);
  1219.    /* create and open the mailbox */
  1220.    status = SYS_CREMBX(0, &chan, 0, 0, 0, 0, 0);
  1221.    if (!(status & 1)) {
  1222.       LIB_FREE_EF(&efn);
  1223.       return (0);
  1224.    }
  1225.    itmlst.last = mbxname.length = 0;
  1226.    itmlst.address = mbxname.ptr = mname;
  1227.    itmlst.retlen = &mbxname.length;
  1228.    itmlst.code = DVI__DEVNAM;
  1229.    itmlst.len = 64;
  1230.    status = SYS_GETDVIW(0, chan, 0, &itmlst, 0, 0, 0, 0);
  1231.    if (!(status & 1)) {
  1232.       LIB_FREE_EF(&efn);
  1233.       return (0);
  1234.    }
  1235.    mname[mbxname.length] = '\0';
  1236.    pfile = fopen(mname, mode);
  1237.    if (!pfile) {
  1238.       LIB_FREE_EF(&efn);
  1239.       SYS_DASSGN(chan);
  1240.       return (0);
  1241.    }
  1242.    /* Save file information now */
  1243.    pd = &_pipes[fileno(pfile)];    /* get Pipe pointer */
  1244.    pd->mode = _tolower(mode[0]);
  1245.    pd->fptr = pfile;
  1246.    pd->pid = pd->status = pd->running = 0;
  1247.    pd->flags = SFLAGS;
  1248.    pd->channel = chan;
  1249.    pd->efn = efn;
  1250.    /* fork the command */
  1251.    nl.length = strlen("_NL:");
  1252.    nl.ptr = "_NL:";
  1253.    command.length = strlen(cmd);
  1254.    command.ptr = cmd;
  1255.    status = LIB_SPAWN(&command,
  1256.       (pd->mode == 'r') ? 0 : &mbxname,    /* input file */
  1257.       (pd->mode == 'r') ? &mbxname : 0,    /* output file */
  1258.       &pd->flags, 0, &pd->pid, &pd->status, &pd->efn, 0, 0, 0, 0);
  1259.    if (!(status & 1)) {
  1260.       LIB_FREE_EF(&efn);
  1261.       SYS_DASSGN(chan);
  1262.       return (0);
  1263.    } else {
  1264.       pd->running = 1;
  1265.    }
  1266.    return (pfile);
  1267. }
  1268.  
  1269. /*
  1270.  * pclose - close a pipe
  1271.  * Last modified 2-Apr-86/chj
  1272.  *
  1273.  */
  1274. pclose(pfile)
  1275. FILE *pfile;
  1276. {
  1277.    Pipe *pd;
  1278.    int status;
  1279.    int fstatus;
  1280.  
  1281.    pd = fileno(pfile) ? &_pipes[fileno(pfile)] : 0;
  1282.    if (pd == NULL)
  1283.       return (-1);
  1284.    fflush(pd->fptr);            /* flush buffers */
  1285.    fstatus = fclose(pfile);
  1286.    if (pd->mode == 'w') {
  1287.       status = SYS_QIOW(0, pd->channel, IO__WRITEOF, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  1288.       SYS_WFLOR(pd->efn, 1 << (pd->efn % 32));
  1289.    }
  1290.    SYS_DASSGN(pd->channel);
  1291.    LIB_FREE_EF(&pd->efn);
  1292.    pd->running = 0;
  1293.    return (fstatus);
  1294. }
  1295.  
  1296. /*
  1297.  * redirect(&argc,argv,nfargs) - redirect standard I/O
  1298.  *    int *argc        number of command arguments (from call to main)
  1299.  *    char *argv[]    command argument list (from call to main)
  1300.  *    int nfargs    number of filename arguments to process
  1301.  *
  1302.  * argc and argv will be adjusted by redirect.
  1303.  *
  1304.  * redirect processes a program's command argument list and handles redirection
  1305.  * of stdin, and stdout.  Any arguments which redirect I/O are removed from the
  1306.  * argument list, and argc is adjusted accordingly.  redirect would typically be
  1307.  * called as the first statement in the main program.
  1308.  *
  1309.  * Files are redirected based on syntax or position of command arguments.
  1310.  * Arguments of the following forms always redirect a file:
  1311.  *
  1312.  *    <file    redirects standard input to read the given file
  1313.  *    >file    redirects standard output to write to the given file
  1314.  *    >>file    redirects standard output to append to the given file
  1315.  *
  1316.  * It is often useful to allow alternate input and output files as the
  1317.  * first two command arguments without requiring the <file and >file
  1318.  * syntax.  If the nfargs argument to redirect is 2 or more then the
  1319.  * first two command arguments, if supplied, will be interpreted in this
  1320.  * manner:  the first argument replaces stdin and the second stdout.
  1321.  * A filename of "-" may be specified to occupy a position without
  1322.  * performing any redirection.
  1323.  *
  1324.  * If nfargs is 1, only the first argument will be considered and will
  1325.  * replace standard input if given.  Any arguments processed by setting
  1326.  * nfargs > 0 will be removed from the argument list, and again argc will
  1327.  * be adjusted.  Positional redirection follows syntax-specified
  1328.  * redirection and therefore overrides it.
  1329.  *
  1330.  */
  1331.  
  1332.  
  1333. redirect(argc,argv,nfargs)
  1334. int *argc, nfargs;
  1335. char *argv[];
  1336. {
  1337.    int i;
  1338.  
  1339.    i = 1;
  1340.    while (i < *argc)  {        /* for every command argument... */
  1341.       switch (argv[i][0])  {        /* check first character */
  1342.          case '<':            /* <file redirects stdin */
  1343.             filearg(argc,argv,i,1,stdin,"r");
  1344.             break;
  1345.          case '>':            /* >file or >>file redirects stdout */
  1346.             if (argv[i][1] == '>')
  1347.                filearg(argc,argv,i,2,stdout,"a");
  1348.             else
  1349.                filearg(argc,argv,i,1,stdout,"w");
  1350.             break;
  1351.          default:            /* not recognized, go on to next arg */
  1352.             i++;
  1353.       }
  1354.    }
  1355.    if (nfargs >= 1 && *argc > 1)    /* if positional redirection & 1 arg */
  1356.       filearg(argc,argv,1,0,stdin,"r");    /* then redirect stdin */
  1357.    if (nfargs >= 2 && *argc > 1)    /* likewise for 2nd arg if wanted */
  1358.       filearg(argc,argv,1,0,stdout,"w");/* redirect stdout */
  1359. }
  1360.  
  1361.  
  1362.  
  1363. /* filearg(&argc,argv,n,i,fp,mode) - redirect and remove file argument
  1364.  *    int *argc        number of command arguments (from call to main)
  1365.  *    char *argv[]    command argument list (from call to main)
  1366.  *    int n        argv entry to use as file name and then delete
  1367.  *    int i        first character of file name to use (skip '<' etc.)
  1368.  *    FILE *fp        file pointer for file to reopen (typically stdin etc.)
  1369.  *    char mode[]    file access mode (see freopen spec)
  1370.  */
  1371.  
  1372. filearg(argc,argv,n,i,fp,mode)
  1373. int *argc, n, i;
  1374. char *argv[], mode[];
  1375. FILE *fp;
  1376. {
  1377.    if (strcmp(argv[n]+i,"-"))        /* alter file if arg not "-" */
  1378.       fp = freopen(argv[n]+i,mode,fp);
  1379.    if (fp == NULL)  {            /* abort on error */
  1380.       fprintf(stderr,"%%can't open %s",argv[n]+i);
  1381.       exit(EXIT_FAILURE);
  1382.    }
  1383.    for ( ;  n < *argc;  n++)        /* move down following arguments */
  1384.       argv[n] = argv[n+1];
  1385.    *argc = *argc - 1;            /* decrement argument count */
  1386. }
  1387.  
  1388. #ifdef KeyboardFncs
  1389.  
  1390. short channel;
  1391. int   request_queued = 0;
  1392. int   char_available = 0;
  1393. char  char_typed;
  1394.  
  1395. void assign_channel_to_terminal()
  1396. {
  1397.    descriptor terminal;
  1398.  
  1399.    terminal.length = strlen("SYS$COMMAND");
  1400.    terminal.ptr    = "SYS$COMMAND";
  1401.    SYS_ASSIGN(&terminal, &channel, 0, 0);
  1402. }
  1403.  
  1404. word read_a_char(echo_on)
  1405. int echo_on;
  1406. {
  1407.    if (char_available) {
  1408.       char_available = 0;
  1409.       if (echo_on)
  1410.          SYS_QIOW(2, channel, IO__WRITEVBLK, 0, 0, 0, &char_typed, 1,
  1411.           0, 32, 0, 0);
  1412.       goto return_char;
  1413.       }
  1414.    if (echo_on)
  1415.       SYS_QIOW(1, channel, IO__TTYREADALL, 0, 0, 0, &char_typed, 1, 0, 0, 0, 0);
  1416.    else
  1417.       SYS_QIOW(1, channel, IO__TTYREADALL | IO_M_NOECHO, 0, 0, 0,
  1418.            &char_typed, 1, 0, 0, 0, 0);
  1419.  
  1420. return_char:
  1421.    if (char_typed == '\003' && kill(getpid(), SIGINT) == -1) {
  1422.       perror("kill");
  1423.       return 0;
  1424.       }
  1425.    if (char_typed == '\034' && kill(getpid(), SIGQUIT) == -1) {
  1426.       perror("kill");
  1427.       return 0;
  1428.       }
  1429.    return (word)char_typed;
  1430. }
  1431.  
  1432. int getch()
  1433. {
  1434.    return read_a_char(0);
  1435. }
  1436.  
  1437. int getche()
  1438. {
  1439.    return read_a_char(1);
  1440. }
  1441.  
  1442. void ast_proc()
  1443. {
  1444.    char_available = 1;
  1445.    request_queued = 0;
  1446. }
  1447.  
  1448. int kbhit()
  1449. {
  1450.    if (!request_queued) {
  1451.       request_queued = 1;
  1452.       SYS_QIO(1, channel, IO__TTYREADALL | IO_M_NOECHO, 0, ast_proc, 0,
  1453.               &char_typed, 1, 0, 0, 0, 0);
  1454.       }
  1455.    return char_available;
  1456. }
  1457.  
  1458. #endif                    /* KeyboardFncs */
  1459.  
  1460. #endif                    /* VMS */
  1461. /*
  1462.  * End of operating-system specific code.
  1463.  */
  1464.  
  1465. static char xjunk;            /* avoid empty module */
  1466.