home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / textutil / microemacs / Source / c / Riscos < prev    next >
Encoding:
Text File  |  1991-09-14  |  19.4 KB  |  998 lines

  1. /*    RISCOS.C:    Operating specific I/O and Spawning functions
  2.             under the RISC OS operating system
  3.             for MicroEMACS 3.10
  4.             (C)opyright 1988 by Daniel M. Lawrence
  5. */
  6.  
  7. #include        <stdio.h>
  8. #include    "estruct.h"
  9. #include    "eproto.h"
  10.  
  11. #ifdef    RISCOS
  12. #include        "edef.h"
  13. #include    "elang.h"
  14.  
  15. #include    <stdlib.h>
  16. #include    <time.h>
  17. #include    "filter.h"
  18. #include    "kernel.h"
  19. #include    "swis.h"
  20.  
  21. extern char *dirscan (char *);
  22.  
  23. static int bufread (BUFFER *, FILE *);
  24. static int fgetline (FILE *, char **, int *);
  25. static void shell (void);
  26. static int extchar (int, int);
  27.  
  28. /* Switch escape off and on, from C.Archimedes */
  29. extern void esc_off(void);
  30. extern void esc_on(void);
  31.  
  32. static _kernel_swi_regs regs;
  33.  
  34. #define fx(a,x,y)    (_kernel_osbyte(a,x,y))
  35. #define checkkey(k)    ((fx(121, (k) ^ 0x80, 0) & 0xFF) != 0)
  36. #define swi(n)        (_kernel_swi(n,®s,®s))
  37. #define vdu(n)        (void)(_kernel_oswrch(n))
  38.  
  39. #define vdu23(a,b,c,d,e,f,g,h,i) \
  40.     (void)( \
  41.     _kernel_oswrch(23), \
  42.     _kernel_oswrch(a), \
  43.     _kernel_oswrch(b), \
  44.     _kernel_oswrch(c), \
  45.     _kernel_oswrch(d), \
  46.     _kernel_oswrch(e), \
  47.     _kernel_oswrch(f), \
  48.     _kernel_oswrch(g), \
  49.     _kernel_oswrch(h), \
  50.     _kernel_oswrch(i)  \
  51.     )
  52.  
  53. #if ACORN  /* Acorn VDU codes and standard kbd */
  54.  
  55. /*    input buffers and pointers    */
  56.  
  57. #define    IBUFSIZE    64    /* this must be a power of 2 */
  58.  
  59. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  60. int in_next = 0;        /* pos to retrieve next input character */
  61. int in_last = 0;        /* pos to place most recent input character */
  62.  
  63. void in_init (void)    /* initialize the input buffer */
  64. {
  65.     in_next = in_last = 0;
  66. }
  67.  
  68. int in_check (void)    /* is the input buffer non-empty? */
  69. {
  70.     if (in_next == in_last)
  71.         return(FALSE);
  72.     else
  73.         return(TRUE);
  74. }
  75.  
  76. void in_put (int event)
  77. {
  78.     in_buf[in_last++] = event;
  79.     in_last &= (IBUFSIZE - 1);
  80. }
  81.  
  82. int in_get (void)    /* get an event from the input buffer */
  83. {
  84.     register int event;    /* event to return */
  85.  
  86.     event = in_buf[in_next++];
  87.     in_next &= (IBUFSIZE - 1);
  88.     return(event);
  89. }
  90.  
  91. /* This function is called once to set up the terminal device streams.
  92.  */
  93.  
  94. int ttopen (void)
  95. {
  96.     ttrow = 999;
  97.     ttcol = 999;
  98.     in_init();
  99.     return 0;
  100. }
  101.  
  102. /* Write a character to the display. On VMS, terminal output is buffered, and
  103.  * we just put the characters in the big array, after checking for overflow.
  104.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  105.  * MS-DOS (use the very very raw console output routine).
  106.  */
  107.  
  108. int ttputc (int c)
  109. {
  110.     vdu(c);
  111.     return 0;
  112. }
  113.  
  114. /* Flush terminal buffer. Does real work where the terminal output is buffered
  115.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  116.  */
  117. int ttflush (void)
  118. {
  119.     return 0;
  120. }
  121.  
  122. /* Get a character from the operating system. If it is a special key code,
  123.  * return the initial 0 of the Emacs extended code, and push the remaining
  124.  * part of the code sequence into the input buffer.
  125.  */
  126. int oschar (void)
  127. {
  128.     int ch = _kernel_osrdch();
  129.     int alt = 0;
  130.  
  131. #ifndef WIMP_MODE
  132.     /* Check for ALT */
  133.     if (ch == 0x7F)
  134.     {
  135.         alt = ALTD;
  136.         ch = _kernel_osrdch();
  137.     }
  138. #endif
  139.  
  140.     /* For non-function keys, simply return them */
  141.     if (ch != 0 && alt == 0)
  142.         return ch;
  143.  
  144.     /* For ALT-normal keys, return 0, ALT, char (upper case) */
  145.     if (ch != 0)
  146.     {
  147.         in_put(alt >> 8);
  148.         in_put(upperc(ch));
  149.         return(0);
  150.     }
  151.  
  152.     /* Skip the null byte */
  153.     ch = _kernel_osrdch();
  154.  
  155.     /* A genuine null gets returned as 0, 0 */
  156.     if (ch == 0)
  157.     {
  158.         in_put(0);
  159.         return(0);
  160.     }
  161.  
  162.     /* For function keys, convert to an extended character */
  163.     ch = extchar(alt, ch);
  164.  
  165.     /* Check for a simple character */
  166.     if ((ch >> 8) == 0)
  167.         return(ch);
  168.  
  169.     /* Otherwise, return an extended sequence */
  170.     in_put(ch >> 8);
  171.     in_put(ch & 0xFF);
  172.     return(0);
  173. }
  174.  
  175. /* Read a character from the terminal, performing no editing and doing no echo
  176.  * at all. Also mouse events are forced into the input stream here.
  177.  */
  178. int ttgetc (void)
  179. {
  180.     register int c;        /* character read */
  181.  
  182.     /* return any keystrokes waiting in the type ahead buffer */
  183.     if (in_check())
  184.         return(in_get());
  185.  
  186.     return(oschar());
  187. }
  188.  
  189. #if    TYPEAH
  190. /* Check to see if any characters are already in the keyboard buffer.
  191.  */
  192. int typahead (void)
  193. {
  194.     int result;
  195.  
  196.     result = fx(152,0,0);
  197.  
  198.     if (result & 0x0F00)
  199.         return(FALSE);
  200.     else
  201.         return(TRUE);
  202. }
  203. #endif
  204.  
  205. #endif   /* ACORN */
  206.  
  207. /*
  208.  * Create a subjob with a copy of the command intrepreter in it. When the
  209.  * command interpreter exits, mark the screen as garbage so that you do a full
  210.  * repaint. Bound to "^X C".
  211.  */
  212.  
  213. int spawncli (int f, int n)
  214. {
  215.     /* don't allow this command if restricted */
  216.     if (restflag)
  217.         return(resterr());
  218.  
  219.         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  220.         TTflush();
  221.     TTkclose();
  222.     shell();
  223.     TTkopen();
  224.         sgarbf = TRUE;
  225.         return(TRUE);
  226. }
  227.  
  228. /*
  229.  * Run a one-liner in a subjob. When the command returns, wait for a single
  230.  * character to be typed, then mark the screen as garbage so a full repaint is
  231.  * done. Bound to "C-X !".
  232.  */
  233. int spawn (int f, int n)
  234. {
  235.         register int s;
  236.         char line[NLINE];
  237.  
  238.     /* don't allow this command if restricted */
  239.     if (restflag)
  240.         return(resterr());
  241.  
  242.     strcpy(line, "Call:");
  243.  
  244.         if ((s=mlreply("!", &line[5], NLINE-5)) != TRUE)
  245.                 return(s);
  246.     movecursor(term.t_nrow - 1, 0);
  247.     TTkclose();
  248.         system(line);
  249.     TTkopen();
  250.     /* if we are interactive, pause here */
  251.     if (clexec == FALSE) {
  252.             mlputs(TEXT6);
  253. /*                     "\r\n\n[End]" */
  254.             tgetc();
  255.         }
  256.         sgarbf = TRUE;
  257.         return (TRUE);
  258. }
  259.  
  260. /*
  261.  * Run an external program with arguments. When it returns, wait for a single
  262.  * character to be typed, then mark the screen as garbage so a full repaint is
  263.  * done. Bound to "C-X $".
  264.  */
  265.  
  266. int execprg (int f, int n)
  267. {
  268.         register int s;
  269.         char line[NLINE];
  270.  
  271.     /* don't allow this command if restricted */
  272.     if (restflag)
  273.         return(resterr());
  274.  
  275.     strcpy(line, "Call:");
  276.  
  277.         if ((s=mlreply("$", &line[5], NLINE-5)) != TRUE)
  278.                 return(s);
  279.     movecursor(term.t_nrow - 1, 0);
  280.     TTkclose();
  281.         system(line);
  282.     TTkopen();
  283.     /* if we are interactive, pause here */
  284.     if (clexec == FALSE) {
  285.             mlputs(TEXT6);
  286. /*                     "\r\n\n[End]" */
  287.             tgetc();
  288.         }
  289.         sgarbf = TRUE;
  290.         return (TRUE);
  291. }
  292.  
  293. /*
  294.  * Pipe a one line command into a window
  295.  * Bound to ^X @
  296.  */
  297. int pipecmd (int f, int n)
  298. {
  299.     register WINDOW *wp;    /* pointer to new window */
  300.     register BUFFER *bp;    /* pointer to buffer to zot */
  301.     int s;            /* command status */
  302.         char line[NLINE];    /* command line send to shell */
  303.     FILTER *flt;        /* command filter */
  304.     static char bname[] = "command";
  305.  
  306.     /* don't allow this command if restricted */
  307.     if (restflag)
  308.         return(resterr());
  309.  
  310.     if ((flt = FLTopen()) == NULL)
  311.         return(FALSE);
  312.  
  313.     /* get the command to pipe in */
  314.         if (mlreply("@", line, NLINE) != TRUE)
  315.                 return(FALSE);
  316.  
  317.     /* get rid of the command output buffer if it exists */
  318.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  319.         /* try to make sure we are off screen */
  320.         wp = wheadp;
  321.         while (wp != NULL) {
  322.             if (wp->w_bufp == bp) {
  323.                 onlywind(FALSE, 1);
  324.                 break;
  325.             }
  326.             wp = wp->w_wndp;
  327.         }
  328.         /* get rid of the existing command buffer */
  329.         if (zotbuf(bp) != TRUE)
  330.             return(FALSE);
  331.     }
  332.  
  333.     movecursor(term.t_nrow - 1, 0);
  334.  
  335.     /* execute the command */
  336.     TTkclose();
  337.     s = FLTfilter(flt,line);
  338.     TTkopen();
  339.         sgarbf = TRUE;
  340.  
  341.         /* did the output file get generated? */
  342.     if (s == FILTER_ERROR)
  343.     {
  344.         FLTclose(flt);
  345.         return(FALSE);
  346.     }
  347.  
  348.     /* split the current window to make room for the command output */
  349.     if (splitwind(FALSE, 1) == FALSE)
  350.     {
  351.         FLTclose(flt);
  352.         return(FALSE);
  353.     }
  354.  
  355.     /* create a new buffer for the output */
  356.     if ((bp = bfind(bname, TRUE, BFINVS)) == FALSE)
  357.     {
  358.         FLTclose(flt);
  359.         return(FALSE);
  360.     }
  361.  
  362.     /* and read the stuff in */
  363.     if (bufread(bp,FLTout(flt)) == FALSE)
  364.     {
  365.         FLTclose(flt);
  366.         return(FALSE);
  367.     }
  368.  
  369.     FLTclose(flt);
  370.  
  371.     /* make this window in VIEW mode, update all mode lines */
  372.     bp->b_mode |= MDVIEW;
  373.     wp = wheadp;
  374.     while (wp != NULL) {
  375.         wp->w_flag |= WFMODE;
  376.         wp = wp->w_wndp;
  377.     }
  378.  
  379.     return(TRUE);
  380. }
  381.  
  382. /*
  383.  * filter a buffer through an external DOS program
  384.  * Bound to ^X #
  385.  */
  386. int filter (int f, int n)
  387. {
  388.         register int s;        /* return status from CLI */
  389.         char line[NLINE];    /* command line send to shell */
  390.     LINE *lp;        /* Temporary line pointer */
  391.     FILTER *flt;        /* Command filter */
  392.     register int i;
  393.  
  394.     /* don't allow this command if restricted */
  395.     if (restflag)
  396.         return(resterr());
  397.  
  398.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  399.         return(rdonly());    /* we are in read only mode    */
  400.  
  401.     if ((flt = FLTopen()) == NULL) {
  402.         mlwrite(TEXT2);
  403. /*                      "[Cannot write filter file]" */
  404.         return(FALSE);
  405.     }
  406.  
  407.     /* get the filter name and its args */
  408.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  409.                 return(s);
  410.  
  411.     /* copy the current buffer into the filter */
  412.     lp = lforw(curbp->b_linep);
  413.  
  414.     while (lp != curbp->b_linep)
  415.     {
  416.         for (i = 0; i < llength(lp); ++i)
  417.             putc(lp->l_text[i], FLTin(flt));
  418.  
  419.         putc('\n', FLTin(flt));
  420.  
  421.         if (ferror(FLTin(flt))) {
  422.             FLTclose(flt);
  423.             mlwrite(TEXT2);
  424. /*                          "[Cannot write filter file]" */
  425.             return(FALSE);
  426.         }
  427.  
  428.         lp = lforw(lp);
  429.     }
  430.  
  431.     movecursor(term.t_nrow - 1, 0);
  432.     TTkclose();
  433.     s = FLTfilter(flt,line);
  434.     TTkopen();
  435.         sgarbf = TRUE;
  436.  
  437.     /* on failure, escape gracefully */
  438.     if (s == FILTER_ERROR || bufread(curbp,FLTout(flt)) == FALSE)
  439.     {
  440.         FLTclose(flt);
  441.         mlwrite(TEXT3);
  442. /*                      "[Execution failed]" */
  443.         return(FALSE);
  444.     }
  445.  
  446.     /* Flag the buffer as changed */
  447.     curbp->b_flag |= BFCHG;
  448.     FLTclose(flt);
  449.  
  450.     return(TRUE);
  451. }
  452.  
  453. /* Read a file from a supplied file pointer into a specified buffer.
  454.  * The buffer's original contents is deleted. FALSE is returned in case
  455.  * of errors, TRUE if the read succeeds.
  456.  */
  457.  
  458. int bufread (BUFFER *bp, FILE *fp)
  459. {
  460.     register LINE *lp1;
  461.     register LINE *lp2;
  462.     register WINDOW *wp;
  463.     register int i;
  464.     register int s;
  465.     int nbytes;
  466.     int nline;
  467.     int cmark;
  468.     char mesg[NSTRING];
  469.     char *tline = NULL;
  470.     int tlen = 0;
  471.  
  472.     if ((s = bclear(bp)) != TRUE)
  473.         return(s);
  474.  
  475.     bp->b_flag &= ~BFCHG;
  476.  
  477.     nline = 0;
  478.  
  479.     while ((s = fgetline(fp, &tline, &tlen)) == FIOSUC)
  480.     {
  481.         nbytes = strlen(tline);
  482.         if ((lp1 = lalloc(nbytes)) == NULL)
  483.         {
  484.             s = FIOMEM;
  485.             break;
  486.         }
  487.         lp2 = lback(bp->b_linep);
  488.         lp2->l_fp = lp1;
  489.         lp1->l_fp = bp->b_linep;
  490.         lp1->l_bp = lp2;
  491.         bp->b_linep->l_bp = lp1;
  492.         for (i = 0; i < nbytes; ++i)
  493.             lputc(lp1, i, tline[i]);
  494.  
  495.         ++nline;
  496.     }
  497.  
  498.     if (tline != NULL)
  499.         free(tline);
  500.  
  501.     strcpy(mesg,"[");
  502.     if (s==FIOERR) {
  503.         strcat(mesg, TEXT141);
  504. /*                           "I/O ERROR, " */
  505.         bp->b_flag |= BFTRUNC;
  506.     }
  507.     if (s == FIOMEM) {
  508.         strcat(mesg, TEXT142);
  509. /*                           "OUT OF MEMORY, " */
  510.         bp->b_flag |= BFTRUNC;
  511.     }
  512.     strcat(mesg, TEXT140);
  513. /*                   "Read " */
  514.     strcat(mesg, int_asc(nline));
  515.     strcat(mesg, TEXT143);
  516. /*                   " line" */
  517.     if (nline > 1)
  518.         strcat(mesg, "s");
  519.     strcat(mesg, "]");
  520.     mlwrite(mesg);
  521.  
  522.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  523.         if (wp->w_bufp == bp) {
  524.             wp->w_linep = lforw(bp->b_linep);
  525.             wp->w_dotp  = lforw(bp->b_linep);
  526.             wp->w_doto  = 0;
  527.             for (cmark = 0; cmark < NMARKS; cmark++) {
  528.                 wp->w_markp[cmark] = NULL;
  529.                 wp->w_marko[cmark] = 0;
  530.             }
  531.             wp->w_flag |= WFMODE|WFHARD;
  532.         }
  533.     }
  534.  
  535.     if (s == FIOERR || s == FIOFNF)     /* False if error.    */
  536.         return(FALSE);
  537.  
  538.     return(TRUE);
  539. }
  540.  
  541. /* Read a line from a file, and store the bytes in the supplied buffer.
  542.  * Check for I/O errors. Return status.
  543.  */
  544. int fgetline(FILE *fp, char **tline, int *tlen)
  545. {
  546.         register int c;        /* current character read */
  547.         register int i;        /* current index into fline */
  548.     register char *tmpline;    /* temp storage for expanding line */
  549.  
  550.     /* internal copies of the parameters */
  551.     register char *tline1 = *tline;
  552.     register int   tlen1  = *tlen;
  553.  
  554.     /* if we are at the end...return it */
  555.     if (feof(fp))
  556.         return(FIOEOF);
  557.  
  558.     /* if we don't have an tline, allocate one */
  559.     if (tline1 == NULL)
  560.         if ((tline1 = malloc(tlen1 = NSTRING)) == NULL)
  561.             return(FIOMEM);
  562.  
  563.     /* read the line in */
  564.         i = 0;
  565.         while ((c = getc(fp)) != EOF && c != '\n') {
  566.                 tline1[i++] = c;
  567.         /* if it's longer, get more room */
  568.                 if (i >= tlen1) {
  569.                     if ((tmpline = malloc(tlen1+NSTRING)) == NULL)
  570.                     {
  571.                         *tline = tline1;
  572.                         *tlen = tlen1;
  573.                         return(FIOMEM);
  574.                     }
  575.                     bytecopy(tmpline, tline1, tlen1);
  576.                     tlen1 += NSTRING;
  577.                     free(tline1);
  578.                     tline1 = tmpline;
  579.                 }
  580.         }
  581.  
  582. #if    ST520
  583.     if (tline1[i-1] == '\r')
  584.         i--;
  585. #endif
  586.  
  587.     /* terminate the string */
  588.         tline1[i] = 0;
  589.  
  590.         /* restore the input variables */
  591.     *tline = tline1;
  592.     *tlen = tlen1;
  593.  
  594.     /* test for any errors that may have occured */
  595.         if (c == EOF) {
  596.                 if (ferror(fp)) {
  597.                         mlwrite(TEXT158);
  598. /*                              "File read error" */
  599.                         return(FIOERR);
  600.                 }
  601.  
  602.                 if (i == 0)
  603.             return(FIOEOF);
  604.         }
  605.  
  606.         return(FIOSUC);
  607. }
  608.  
  609. /* Run an interactive operating system shell */
  610.  
  611. #if ACORN
  612.  
  613. static void shell (void)
  614. {
  615.     int len;
  616.     _kernel_oserror *err;
  617.     char line[261];
  618.  
  619.     strcpy(line, "Call:");
  620.  
  621.     /* Set text window to the full screen */
  622.     vdu(26);
  623.  
  624.     /* Set background colour to green and foreground colour to black
  625.      * (but do it the opposite way round and apply reverse video, to
  626.      * set things up right for 2-colour modes)
  627.      */
  628. #if    COLOR
  629.     TTbacg(0);
  630.     TTforg(2);
  631.     TTrev(TRUE);
  632. #endif
  633.  
  634.     /* Clear screen */
  635.     vdu(12);
  636.  
  637.     /* Centre on line 0 */
  638.     vdu(31);
  639.     vdu((term.t_ncol - 14) / 2);
  640.     vdu(0);
  641.  
  642.     /* Write the screen title */
  643.     regs.r[0] = (int)"Archimedes MOS";
  644.     swi(OS_Write0);
  645.  
  646.     /* Define text window, missing top and bottom lines */
  647.     vdu(28);
  648.     vdu(0);
  649.     vdu(term.t_nrow - 1);
  650.     vdu(term.t_ncol - 1);
  651.     vdu(1);
  652.  
  653.     /* Set background colour to blue and foreground colour to grey */
  654. #if    COLOR
  655.     TTrev(FALSE);
  656.     TTbacg(4);
  657.     TTforg(7);
  658. #endif
  659.  
  660.     /* Clear screen */
  661.     vdu(12);
  662.  
  663.     for (;;)
  664.     {
  665.         vdu('*');
  666.  
  667.         regs.r[0] = (int)&line[5];
  668.         regs.r[1] = 256;
  669.         regs.r[2] = 32;
  670.         regs.r[3] = 255;
  671.  
  672.         /* We can't trap ESCAPE here... it acts just like NL */
  673.         if ((err = swi(OS_ReadLine)) != NULL)
  674.         {
  675.             swi(OS_NewLine);
  676.             regs.r[0] = (int)err->errmess;
  677.             swi(OS_Write0);
  678.             swi(OS_NewLine);
  679.  
  680.             continue;
  681.         }
  682.  
  683.         len = regs.r[1];
  684.  
  685.         if (len == 0)
  686.             break;
  687.  
  688.         line[5+len] = 0;
  689.  
  690.         esc_on();
  691.  
  692.         if (system(line) == -2)
  693.         {
  694.             char buf[300];
  695.  
  696.             err = _kernel_last_oserror();
  697.             sprintf(buf, "%s (Error %d)", err->errmess,
  698.                 err->errnum);
  699.  
  700.             swi(OS_NewLine);
  701.             regs.r[0] = (int)buf;
  702.             swi(OS_Write0);
  703.             swi(OS_NewLine);
  704.         }
  705.  
  706.         esc_off();
  707.     }
  708.  
  709.     /* Restore the default text window */
  710.     vdu(26);
  711. }
  712.  
  713. #endif /* ACORN */
  714.  
  715. #if RISCOSWIMP
  716.  
  717. static void shell(void)
  718. {
  719.     int wimp_starttask(char *);
  720.  
  721.     wimp_starttask("Shell_CLI");
  722. }
  723.  
  724. #endif /* RISCOSWIMP */
  725.  
  726. /* return a system dependent string with the current time */
  727.  
  728. char *timeset (void)
  729. {
  730.     register char *sp;    /* temp string pointer */
  731.     time_t timeval;
  732.  
  733.     time(&timeval);
  734.     sp = ctime(&timeval);
  735.     sp[strlen(sp)-1] = 0;
  736.     return(sp);
  737. }
  738.  
  739. /* Read a single keypress and return it, converting Risc OS character codes
  740.  * into Emacs extended character codes
  741.  */
  742.  
  743. static int extchar (int alt, int c)
  744. {
  745.     int base_key;
  746.     int shft = 0;
  747.     int ctrl = 0;
  748.  
  749. /* Save a bit of typing */
  750. #define asc (alt | shft | ctrl)
  751.  
  752.     /* Break the extended code up into parts */
  753.     base_key = c & 0xCF;
  754.     shft = (c & 0x10 ? SHFT : 0);
  755.     ctrl = (c & 0x20 ? CTRL : 0);
  756.  
  757.     /* F1 to F9 (FN1 - FN9) */
  758.     if (base_key >= 0x81  && base_key <= 0x89)
  759.         return(SPEC | asc | base_key - 0x81 + '1');
  760.  
  761.     switch (base_key)
  762.     {
  763.     case 0x80:    /* F0 (Print) */
  764.             return(SPEC | asc | '`');
  765.  
  766.     case 0xCA:    /* F10 */
  767.             return(SPEC | asc | '0');
  768.  
  769.     case 0xCB:    /* F11 */
  770.             return(SPEC | asc | '-');
  771.  
  772.     case 0xCC:    /* F12 */
  773.             return(SPEC | asc | '=');
  774.  
  775.     case 0x8B:    /* Copy */
  776.             return (SPEC | asc | '>');
  777.  
  778.     case 0x8C:    /* Cursor Left */
  779.             return (SPEC | asc | 'B');
  780.  
  781.     case 0x8D:    /* Cursor Right */
  782.             return (SPEC | asc | 'F');
  783.  
  784.     case 0x8E:    /* Cursor Down */
  785.             return (SPEC | asc | 'N');
  786.  
  787.     case 0x8F:    /* Cursor Up */
  788.             return (SPEC | asc | 'P');
  789.  
  790.     case 0xCD:    /* Insert */
  791.             return (SPEC | asc | 'C');
  792.  
  793.     case 0xC1:    /* Home */
  794.             return (SPEC | asc | '<');
  795.  
  796.     case 0xC2:    /* Page Down */
  797.             return (SPEC | asc | 'V');
  798.  
  799.     case 0xC3:    /* Page Up */
  800.             return (SPEC | asc | 'Z');
  801.  
  802.     case 0xC0:    /* Delete */
  803.         if (asc == 0)
  804.             return ('\x7F');
  805.         else
  806.             return (SPEC | asc | 'D');
  807.  
  808.     case 0x8A:    /* Tab */
  809.         if (asc == 0)
  810.             return ('\t');
  811.         else if (!ctrl)
  812.             return (alt | shft | CTRL | 'I');
  813.         else
  814.             return (SPEC | asc | 'T');        /*?????*/
  815.  
  816.     case 0xC4:    /* Backspace */
  817.         if (asc == 0)
  818.             return ('\b');
  819.         else if (!ctrl)
  820.             return (alt | shft | CTRL | 'H');
  821.         else
  822.             return (SPEC | asc | 'L');        /*?????*/
  823.  
  824.     case 0xC5:    /* Return */
  825.         if (asc == 0)
  826.             return ('\r');
  827.         else if (asc == SHFT)
  828.             return ('\n');
  829.         else
  830.             return (SPEC | asc | 'R');
  831.  
  832.     case 0xC6:    /* Enter */
  833.         if (asc == 0)
  834.             return ('\r');
  835.         else if (asc == SHFT)
  836.             return ('\n');
  837.         else
  838.             return (SPEC | asc | 'E');
  839.     }
  840.  
  841.     /* Anything else, return as itself */
  842.     return (alt | c);
  843.  
  844. #undef asc
  845. }
  846.  
  847. #if    FTYPE
  848. /*     File type routines */
  849.  
  850. void fsettype (char *fname, int type)
  851. {
  852.     regs.r[0] = 18;
  853.     regs.r[1] = (int)fname;
  854.     regs.r[2] = type;
  855.     swi(OS_File);
  856. }
  857.  
  858. int fgettype (char *fname)
  859. {
  860.     regs.r[0] = 5;
  861.     regs.r[1] = (int)fname;
  862.  
  863.     if (swi(OS_File))
  864.         return(0xFFF);
  865.  
  866.     if ((regs.r[2] & 0xFFF00000) != 0xFFF00000)
  867.         return(0xFFF);
  868.  
  869.     return((regs.r[2] >> 8) & 0xFFF);
  870. }
  871.  
  872. int maketype (char *type)
  873. {
  874.     regs.r[0] = 31;
  875.     regs.r[1] = (int)type;
  876.  
  877.     if (swi(OS_FSControl))
  878.         return(0xFFF);
  879.  
  880.     return(regs.r[2]);
  881. }
  882. #endif
  883.  
  884. #if    EXTINFO    /* OS Dependant file info */
  885. #define    DEFAULT_FILE_TYPE    0xfff    /* Text, but you can change it */
  886.  
  887. void type_lookup(BUFFER *bp)
  888. {
  889.     char buffer[16];
  890.     unsigned int l = bp->b_os.load;
  891.     unsigned int mask = 0xfff00000UL;
  892.  
  893.     if ( (l & mask) != mask)
  894.     {
  895.         strcpy(bp->b_os.typename, "Untyped");
  896.     }
  897.     else
  898.     {
  899.         sprintf(buffer, "File$Type_%03X", (l >> 8) & 0xfff );
  900.         if (_kernel_getenv(buffer, bp->b_os.typename, sizeof(bp->b_os.typename)) != NULL)
  901.         {
  902.             sprintf(bp->b_os.typename, "&%03X", (l >> 8) & 0xfff );
  903.         }
  904.     }
  905. }
  906.  
  907. void extinfo_default(BUFFER *bp)
  908. {
  909.     int time[2];
  910.     
  911.     /* Use current time stamp, text file */
  912.     time[0] = 3;
  913.     _kernel_osword(14, time);
  914.     bp->b_os.exec = time[0];
  915.     bp->b_os.load = (time[1] & 0xff)
  916.             | 0xfff00000UL
  917.             | (DEFAULT_FILE_TYPE << 8);
  918.     bp->b_os.attrs = 13;    /* RW/r */
  919.  
  920.     type_lookup(bp);
  921. }
  922.  
  923. void extinfo_read(char *fname, BUFFER *bp)
  924. {
  925.     _kernel_osfile_block fb;
  926.     
  927.     _kernel_osfile(5, fname, &fb);
  928.     bp->b_os.load = fb.load;
  929.     bp->b_os.exec = fb.exec;
  930.     bp->b_os.attrs = fb.end;
  931.  
  932.     type_lookup(bp);
  933. }
  934.  
  935. void extinfo_write(char *fname, BUFFER *bp)
  936. {
  937.     _kernel_osfile_block fb;
  938.     int time[2];
  939.  
  940.     fb.load = bp->b_os.load;
  941.     if ((fb.load & 0xfff00000UL) == 0xfff00000)
  942.     {
  943.         time[0] = 3;
  944.         _kernel_osword(14, time);
  945.         fb.exec = time[0];
  946.         fb.load = (fb.load & ~(0xff)) | (time[1] & 0xff);
  947.     }
  948.     else
  949.     {
  950.         fb.exec = bp->b_os.exec;
  951.     }
  952.     fb.end = bp->b_os.attrs;
  953.  
  954.     _kernel_osfile(1, fname, &fb);
  955. }
  956.  
  957. char *extinfo_display(BUFFER *bp)
  958. {
  959.     return bp->b_os.typename;
  960. }
  961. #endif
  962.  
  963. /*    FILE Directory routines        */
  964.  
  965. /*    do a wild card directory search (for file name completion) */
  966.  
  967. char *getffile (char *fspec)
  968. {
  969.     char fname[NFILEN];        /* file/path for dirscan() call */
  970.     char *name;
  971.     _kernel_osfile_block blk;
  972.  
  973.     /* Add a "*" wildcard at the end */
  974.     strcpy(fname, fspec);
  975.     strcat(fname, "*");
  976.  
  977.     /* Look for the next non-directory name */
  978.     name = dirscan(fname);
  979.     while (name && _kernel_osfile(17,name,&blk) != 1)
  980.         name = dirscan(0);
  981.  
  982.     return (name);
  983. }
  984.  
  985. char *getnfile (void)
  986. {
  987.     char *name;
  988.     _kernel_osfile_block blk;
  989.  
  990.     /* Look for the next non-directory name */
  991.     name = dirscan(0);
  992.     while (name && _kernel_osfile(17,name,&blk) != 1)
  993.         name = dirscan(0);
  994.  
  995.     return (name);
  996. }
  997. #endif
  998.