home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / researchmachines.zip / rmldis.c < prev    next >
Text File  |  1985-07-11  |  19KB  |  747 lines

  1.  
  2. /************************************************************************/
  3.  
  4. /* File KDISK.C  -  Disk & File Handling Support for Kermit.
  5.             Chris Kennington    5th July 1985.    */
  6.  
  7.  
  8. #include  "stdio.h"
  9.  
  10. #ifdef      MPUZ80    /* 480Z        */
  11.  
  12. #ifndef      TINY
  13. #include  "io.h"
  14. #endif
  15.  
  16. #else            /* Nimbus    */
  17.  
  18. /* Layout of FCB (as in <io.h>):    */
  19. struct fcb {
  20.     char f_driv;
  21.     char f_name[8];
  22.     char f_type[3];
  23.     char f_ext;
  24.     char f_resv[2];
  25.     char f_rc;
  26.     char f_sydx[16];
  27.     char f_cr;
  28.     unsigned f_record; char f_overfl;
  29. };
  30.  
  31. /* displacements in block returned by Find Match/Next File:-    */
  32. #define     MCHATTRIB    21
  33. #define     MCHNAME    30
  34.  
  35. /* workspace for MCH*                        */
  36. static  char  dmabuf[65];
  37.  
  38. #endif
  39.  
  40. #include  "ctype.h"
  41.  
  42. #define     DEFS2    1
  43. #define  DEFS5    1
  44.  
  45. #include "b:kext.h"
  46.  
  47. #define     DMA    0x0080            /* use default DMA    */
  48.  
  49.  
  50. /* The routines in this file provide OS-independent support on Aztec-C
  51.     for the disk-maintenance functions:
  52.         CHAnge            (reset all drives)
  53.         DIR    dname/dfname
  54.         ERAse    dfname        (DEL is synonym)
  55.         HELP            (print help-text; ? is synonym)
  56.         REName    fname    fname
  57.         TYPe    dfname
  58.         UPAth            (show environment)
  59.         USEr    num        (CP/M only)
  60.         [DRIve]    dname
  61.     (only first 3 chars need be entered)
  62.  
  63. where the valid arguments are:-
  64.     dname    -  a valid disk-letter;
  65.     fname    -  a valid file-name (on default disk);
  66.     dfname    -  a valid file-name with optional disk-letter;
  67.     num    -  a valid user-number.
  68.  
  69.  
  70. Standard Return-Code Byte:
  71.       bit    0  -  file not found
  72.       bit    1  -  filename invalid
  73.       bit    2  -  disk-letter invalid
  74.       bit    3  -  system file
  75.       bit    4  -  file is read/only
  76.       bit    5  -  disk is temporarily read-only (CP/M)
  77.       bit    6  -  wildcards in name
  78.       bit    7  -  directory-name (MSDOS)
  79. */
  80.  
  81.  
  82.  
  83. /* static variables for intercommunication            */
  84. static    char    *s1, *s2;        /* => names 1 & 2    */
  85. static    char    cmd;            /* command-number    */
  86. static    char    *cmds[] = {        /* valid commands    */
  87.     "Nul", "DIR", "ERA", "REN",    /* 0-3 (0 is unused)    */
  88.     "TYP", "USE", "UPA", "DRI",    /* 4-7            */
  89.     "DEL", "CHA", "HEL",        /* 8-10            */
  90.     0};                /* zero to terminate    */
  91.  
  92. static  char    allfiles[] = "*.*";
  93. static    char    diskro[]   = "(disk r/o) ";
  94. static    char    exists[]   = "  <%s> already exists, ";
  95. static  char    explicit[15];        /* new filename        */
  96. static  char    inval[]       = "invalid";
  97. static  char    invalid[]  = " <%s> now invalid ";
  98. static  char    notdel[]   = " NOT deleted.";
  99. static  char    notren[]   = " NOT renamed.";
  100. static  char    overw[]       = "overwritten ";
  101. static  char    reject[]   = "rejecting <%s>.";
  102. static  char    wildcds[]  = "has wildcards";
  103. /* working variables    */
  104. static  char    c, cold, rtn, rtnall, *e, *w;
  105.  
  106. /* Displayed text which needs to vary between CP/M & MSDOS    */
  107. #ifdef MPUZ80
  108. char diskcmds[]    = "          CHAnge  DIRectory  DRIve  ERAse  REName  TYPe  USEr  UPAth";
  109. char diskfail[]    = "Disk failure, CP/M code %d";
  110. char os1[]    = "\r  The following commands are valid (only 3 letters needed):\r\
  111. CHAnge floppy;     DRIve change;    DIRectory list;    ERAse file(s);";
  112. char os2[]    = "\r\
  113. REName file;       TYPe file;       USEr-number;       UPAth (show defaults).\
  114. \r  Wildcards (? *) accepted in DIR & ERA."; 
  115. #else
  116. char diskcmds[]    = "          DELete  DIRectory  DRIve  REName  TYPe  UPAth";
  117. char diskfail[]    = "Disk failure, MSDOS code %d";
  118.  
  119. char os1[]    = "\r  The following commands are valid (only 3 letters needed):\r\
  120.     DELete file(s);    DRIve change;    DIRectory list;";
  121. char os2[]    = "\r\
  122.     REName file;       TYPe file;       UPAth (show path).\
  123. \r  Wildcards (? *) accepted in DIR & DEL."; 
  124. #endif
  125.  
  126.  
  127.  
  128.  
  129. char  *avoid(file)    /* implement collison avoidance    */
  130. /*  If the requested file already exists, queries setting of
  131.     nmavoid and acts accordingly;
  132.     Returns 0 if file not there or may be overwritten,
  133.     else address of explanatory string.        */
  134. char    *file;            /* file-name        */
  135. {
  136.     static  char  ret;
  137.     char    c, *r2;
  138.     int        len;
  139.  
  140.     keyget(&c);            /* trap ESC        */
  141.     ret = filechek(0,file,work);
  142.     if ( (ret & (char)0x01) != 0 )
  143.     return(0);        /* no such file        */
  144.     if ( (ret & (char)0x06) != 0 )
  145.     return(invalid);    /* bad name        */
  146.  
  147.   /* file exists - see what to do about it        */
  148.     outc(CR);
  149.     printf(exists,file);
  150.     switch(nmavoid) {    /* break if OK, return if not    */
  151.  
  152.       case 0:        /* overwrite            */
  153.     txtout(overw);
  154.     break;
  155.  
  156.       case 1:        /* avoid by renaming        */
  157.     if ( (len = strlen(file) - 1) < 2 ) {
  158.         len = 2;
  159.         file[2] = '0';
  160.     }
  161.     if (file[len-1] == '.') {
  162.         len += 2;
  163.         file[len] = '0';
  164.     }
  165.     c = file[len];
  166.     if (file[len-1] == '$')
  167.         file[len] = ++c;    /* increment last char    */
  168.     else
  169.         file[len-1] = '$';    /*  or set previous to $ */
  170.     file[len+1] = 0;    /* ensure closed    */
  171.     if ( (r2 = avoid(file)) == 0 )
  172.         break;        /*   then check that    */
  173.     else
  174.         return(r2);
  175.  
  176.       case 2:        /* reject incoming file        */
  177.         return(reject);
  178.  
  179.       case 3:        /* check with user        */
  180.         printf("OK if %s",overw);
  181.         if (confirm())
  182.         break;        /* Yes            */
  183.         else
  184.         return(reject);
  185.  
  186.       default:        /* unkmown setting        */
  187.         return(null);
  188.     }            /* end switch            */
  189.     vtline(LOCFILE,file);
  190.  
  191.   /* Make sure BDOS will not prevent overwriting    */
  192.     if ( (ret & (char)0x30) != 0 )
  193.     return("<%s> is read-only ");
  194.     else
  195.     return(0);
  196. }            /* End of avoid()        */
  197.  
  198.  
  199.  
  200. char dirprt(name)    /* list directory-matches    */
  201. /* Leaves expanded name in "explicit" and sets up "ownfcb";
  202.    Returns composite status-byte.            */
  203. char    *name;
  204. {
  205.     char    ret;
  206.  
  207.     cold = 0;
  208.     ret = rtn = fileok(name);
  209.     outfc(CR);
  210.     if ( (rtn & (char)0x07) != 0 )
  211.         return(rtn);        /* not found or invalid    */
  212.     else do {
  213.     ret |= rtn;
  214.     for (c=0; c<26; ++c)
  215.         work[c] = SP;
  216.     work[c] = 0;
  217.     w = work;
  218.     e = explicit;
  219.     while( (*w = *e++) != 0)
  220.         ++w;
  221.     if ( (rtn & (char)0x08) != 0 ) {
  222.         e = "  sys";
  223.         while( (*w = *e++) != 0)
  224.         ++w;
  225.     }
  226.     if ( (rtn & (char)0x10) != 0 ) {
  227.         e = "  r/o";
  228.         while( (*w = *e++) != 0)
  229.         ++w;
  230.     }
  231.     *w = ',';
  232.     txtout(work);
  233.     if (++cold > 2) {  /* in 3 columns of 25 ch    */
  234.         if (outfc(CR) != 0) {
  235.         txtout("\rList aborted");
  236.         return(ret);            /* abort list    */
  237.         }
  238.         cold = 0;
  239.     }
  240.     } while ( ( (rtn = filechek(1,name,explicit)) & (char)0x01) == 0 ) ;
  241.     return(ret);
  242. }            /* End of dirprt()        */
  243.  
  244.  
  245.  
  246. char  filechek(mode,fname,nuname)    /* verify disk-file    */
  247. /* Returns standard status-byte to give situation of file;
  248.      sets up ownfcb with expanded wildcard name & checks for it;
  249.      if file exists, copies explicit name into *nuname        */
  250. char    mode, *fname, *nuname;
  251. {
  252.     char    c,  disk,  ret,  *name;
  253.     int        i,  w,  attrib;
  254.     struct    fcb    *fcb2;
  255.  
  256.     bdos(SETDMA,DMA);
  257.     name = fname;
  258.   /* validate disk-letter if any                */
  259.     if (fname[1] == ':') {        /* if disk quoted    */
  260.     disk = fname[0] & 0x5f;
  261.     fname += 2;            /* up to filename    */
  262.     if ( (disk < 'A') || (disk > 'P') )
  263.         return(0x04);        /* bad disk-letter    */
  264.     disk &= 0x3f;            /* range 1-16 = A-P    */
  265.     if (*fname == 0) {        /* disk-letter only    */
  266. #ifdef MPUZ80            /* simple for CP/M        */
  267.         fname = allfiles;        /* point to *.*        */
  268. #else                /* whole path needed for MSDOS    */
  269.         e = fname;
  270.         w = allfiles;
  271.         while ( (*e++ = *w++) != 0 )
  272.         ;            /* copy *.* into name    */
  273. #endif
  274.     }    }
  275.     else
  276.     disk = 0;
  277.     ownfcb->f_driv = disk;        /* set up drive-code    */
  278.  
  279.   /* validate name                        */
  280.     if ( (w = filexpand(fname,ownfcb->f_name)) < 0 )
  281.     return(0x02);            /* bad name        */
  282.     ret = (w > 0) ? 0x40 : 0;
  283.  
  284. #ifdef    MPUZ80            /* CP/M handling
  285.     mode += SCHFST;            /* search first or next    */
  286.     if ( (i = bdos(mode,ownfcb)) == 0xff)
  287.     return(0x01);            /* not found        */
  288.     fcb2 = DMA + (i * 32);
  289.     name = fcb2->f_name;        /* explicit name + bits    */
  290.     for (i=0; i<11; ++i) {
  291.     if (i == 8)
  292.         *nuname++ = '.';
  293.     if ( (c = (name[i] & (char)0x7f)) != SP )
  294.         *nuname++ = c;
  295.     }
  296.     if ( *(nuname-1) == '.' )
  297.     --nuname;
  298.     *nuname = 0;            /* close string        */
  299.   /* check for special conditions                */
  300.     if ( (fcb2->f_type[0] & (char)0x80) != 0 )
  301.     ret |= 0x10;            /* file r/o        */
  302.     if ( (fcb2->f_type[1] & (char)0x80) != 0 )
  303.     ret |= (char)0x08;        /* system file        */
  304.  
  305. #else                /* MSDOS handling        */
  306.     fname = name;        /* retreive original name    */
  307.     bdos(SETDMA,dmabuf);
  308.     mode += MCHFST;
  309.     attrib = 0xffff;        /* find all files/dirs        */
  310.     if (dos(mode,0,attrib,fname,0,0) == -1)
  311.     return(0x01);
  312.     name = dmabuf + MCHNAME;    /* name found            */
  313.     attrib = *(dmabuf + MCHATTRIB); /* & its attributes        */
  314.     while ( (*nuname = *name++) > SP )
  315.     ++nuname;
  316.     *nuname = 0;        /* overwrites first space/ctrl    */
  317.   /* check for special conditions                */
  318.     if ( (attrib & (char)0x01) != 0 )
  319.     ret |= (char)0x10;        /* file r/o        */
  320.     if ( (attrib & (char)0x06) != 0 )
  321.     ret |= (char)0x08;        /* system file        */
  322.     if ( (attrib & (char)0x10) != 0 )
  323.     ret |= (char)0x80;        /* directory        */
  324.     if ( (attrib & (char)0x08) != 0 ) {
  325.     w = " (Vol-Id)";
  326.     while ( (*nuname++ = *w++) != 0 )
  327.         ;
  328.     }
  329.  
  330. #endif
  331.  
  332.     if (disk == 0)
  333.     disk = bdos(CURDSK,0);        /* default disk        */
  334.     else
  335.     --disk;
  336.   /* disk now = 0-15 for A-P                    */
  337.     if (rochek(disk) != 0 )
  338.     ret |= (char)0x20;        /* disk r/o        */
  339.     return(ret);            /* normal return    */
  340. }            /* end of filechek()            */
  341.  
  342.  
  343.  
  344. char  fileok(nam)        /* check & print if bad        */
  345. /* Leaves ownfcb set up for subsequent routines;
  346.    Returns standard status-byte.                */
  347. char    *nam;
  348. {
  349.     char  ret;
  350.  
  351.     ret = filechek(0,nam,explicit);
  352.     if ( (ret & (char)0x20) != 0 )
  353.     txtout(diskro);
  354.     if ( (ret & (char)0x06) != 0 )
  355.     printf("<%s> %s ",nam,inval);
  356. #ifndef  MPUZ80            /* only for MSDOS        */
  357.     else if ( (ret & (char)0x80) != 0 )
  358.     printf("(dir) ");
  359. #endif
  360.     else if ( (ret & (char)0x01) != 0 )
  361.     printf("<%s> not found ",nam);
  362.     return(ret);
  363. }                /* end of fileok()        */
  364.  
  365.  
  366.  
  367. filexpand(fname,nuname)        /* expand & check filename    */
  368. /* returns -1 for error, 0 for OK, +1 for OK with wildcards
  369.    fname must not have a disk-letter                */
  370. char    *fname, *nuname;        /* old & new names    */
  371. {
  372.     char    c, wild;
  373.     int        i, lim;
  374.  
  375.  
  376.     for (i=0; i<11; ++i)        /* blanx to nuname    */
  377.     nuname[i] = SP;
  378.     nuname[11] = 0;
  379.  
  380.     wild = 0;
  381.     lim = 8;                /* first part        */
  382.     i = 0;
  383.  
  384.     while (i < 11) switch (c = *fname++) {
  385.  
  386.       case '?':            /* wildcard        */
  387.         wild = 1;
  388.         if (i < lim)
  389.         nuname[i++] = c;    /*  stored        */
  390.         else
  391.         return(-1);
  392.         break;
  393.  
  394.       case '*':            /* multi-wildcard    */
  395.         wild = 1;
  396.         while (i < lim)
  397.         nuname[i++] = '?';    /*  stored        */
  398.         break;
  399.  
  400.       case '.':            /* separator        */
  401.         if ( (i == 0) || (lim == 11) ) /* leading dot or    */
  402.         return(-1);        /* second dot - invalid    */
  403.         else {
  404.         i = 8;
  405.         lim = 11;
  406.         }
  407.         break;
  408.  
  409.       case 0:            /* end-of-string    */
  410.         if (i == 0)
  411.         return(-1);        /* null name        */
  412.         --fname;
  413.         i = 11;
  414.         break;
  415.  
  416.       default:            /* all others        */
  417.         if ( ( (isalnum(c) == 0) && (c != '$') ) /* bad char */
  418.           || (i >= lim) )        /* too many chars    */
  419.         return(-1);
  420.         else
  421.         nuname[i++] = c;    /*  stored        */
  422.         break;
  423.     }                /* end switch, while        */
  424.     if (*fname != 0)            /* surplus char(s)    */
  425.     wild = -1;
  426.     return(wild);
  427. }            /* end of filexpand()            */
  428.  
  429.  
  430.  
  431.  
  432. findcmd(osl)            /* structure user input        */
  433. /* Sets up cmd with cmd-no, s1 & s2 => names (zero-terminated); 
  434.    Returns number of valid items, 0 - 3; -1 if string is null;
  435.    (If command invalid, returns 0 with s2 => invalid string).    */
  436. char    *osl;
  437. {
  438.     static  char  *ospm[4];
  439.     char    c;
  440.     int        i;
  441.  
  442.     cmd = 4;
  443.     while (cmd-- > 0)        /* clear ospm[]            */
  444.     ospm[cmd] = 0;        /*  (leaves cmd = 0)        */
  445.     decol8(osl,ospm,4);
  446.     if ( (s1=ospm[0]) == 0)    /* null goes back to Kermit    */
  447.     return(-1);
  448.     if (s1[1] == 0) switch (*s1) {    /* 1-letter inputs    */
  449.     case 'Q':
  450.         kermkill(0);
  451.     case 'K':
  452.         return(-1);
  453.     case '?':
  454.         cmd = 10;
  455.         return(1);
  456.     default:
  457.         return(0);
  458.     }
  459.     if ( (s1[1] == ':') && (s1[2] == 0) ) {    /* disk-letter    */
  460.     cmd = 7;
  461.     return(1);
  462.     }
  463.  
  464.   /* identify command    */
  465.     i = 0;
  466.     while ( (s2 = cmds[++i]) != 0 ) {
  467.     s1 = ospm[0];
  468.     while ( ( (c = *s2) == *s1) && (c != 0) ) { /* match chars */
  469.         ++s1;
  470.         ++s2;
  471.     }
  472.     if (c == 0) {            /* whole command    */
  473.         cmd = (char)i;
  474.         break;
  475.     }    }
  476.     if (cmd == 0) {
  477.     s1 = 0;
  478.     s2 = ospm[0];
  479.     return(0);            /* no match        */
  480.     }
  481.  
  482.   /* set up statics & return with count    */
  483.     s1 = ospm[1];
  484.     if (*(s2 = ospm[2]) == '=')
  485.     s2 = ospm[3];
  486.     return(c);
  487.  
  488. }            /* end of findcmd()            */
  489.  
  490.  
  491.  
  492. char osaction()        /* take action on disk/os command    */
  493. /* Get cmdline from user and take action on it; on null input
  494.     return 0, else 1.                    */
  495. {
  496.     static    FILE    *tfp;
  497.     int        ic, disk, user;
  498.     char    d;
  499.  
  500.     txtout(oprompt);
  501.     keyline(osline);
  502.     upper(osline);
  503.     scrline = 0;        /* clear paging            */
  504.     if (findcmd(osline) < 0)    /* set up cmd, s1, s2        */
  505.     return(0);        /* exit on null line        */
  506.  
  507.     if (s1 == 0)
  508.     s1 = allfiles;
  509.     if (s2 == 0)
  510.     s2 = allfiles;
  511.  
  512.     switch (cmd) {
  513.  
  514.       case 0:            /* Null command        */
  515.     printmsg(" <%s> - Not a valid command.",s2);
  516.     break;
  517.  
  518.       case 1:            /* DIR            */
  519.     printf("  %s Directory for %s - ", userpath(),s1);
  520.     dirprt(s1);
  521.     break;
  522.  
  523.       case 2:            /* ERA            */
  524.       case 8:            /* DEL            */
  525.     printmsg("  DELete command: ");
  526.     if ( (dirprt(s1) & (char)0x30) != 0 ) {
  527.         outc(CR);
  528.         printf("  R/O -%s",notdel);
  529.         break;
  530.     }
  531. /* seek confirmation before deleting            */
  532.     txtout("\r  OK to delete");
  533.     if (confirm() == 0) {
  534.         printf(" Files%s",notdel);
  535.         break;
  536.     }
  537.     outc(CR);
  538.     printf("  Deleting %s: ",s1);
  539.     if (bdos(DELFIL,ownfcb) == (char)0x0ff )
  540.         printf("failed;%s",notdel);
  541.     else
  542.         txtout("Files deleted.");
  543.     break;
  544.  
  545.       case 3:            /* REN            */
  546. #ifndef    MPUZ80
  547. /* CP/M renames A <= B but MSDOS renames A => B, so switch names for MSDOS */
  548.     w = s1;
  549.     s1 = s2;
  550.     s2 = w;
  551. #endif
  552.     printf("  RENaming %s to %s; ",s2,s1);
  553.     if ( (s1[1] == ':') || (s2[1] == ':') ) {
  554.         printf("Omit driveletter;%s",notren);
  555.         break;
  556.     }
  557.   /* check new (first) name                */
  558.     if ( (rtn = filexpand(s1,work)) != 0 ) {
  559.         printf("%s %s; %s", s1, (rtn!=1) ? inval : wildcds, notren);
  560.         break;
  561.     }
  562.     rtn = filechek(0,s1,explicit);
  563.     if ( (rtn & (char)0x01) == 0 ) {
  564.         printf("%s exists -%s",s1,notren);
  565.         break;
  566.     }
  567.   /* check old (second) name                */
  568.     if ( (rtn = filexpand(s2,explicit)) != 0 ) {
  569.         printf("%s %s; %s", s2, (rtn!=1) ? inval : wildcds, notren);
  570.         break;
  571.     }
  572.     if ( ( (rtn = fileok(s2)) & (char)0x37 ) != 0) {
  573.         if ( (rtn & (char)0x10) != 0 )
  574.         txtout("R/O");
  575.         txtout(notren);
  576.         break;
  577.     }
  578.     if ( (rtn & (char)0x08) != 0 )
  579.         txtout("(sys) ");
  580.  
  581.     
  582.   /* move second name into fcb + 16            */
  583.     e = &(ownfcb->f_sydx);
  584.     *e++ = 0;            /* dummy disk    */
  585.     w = work;
  586.     user = 12;
  587.     while (user-- != 0)
  588.         *e++ = *w++;        /* new name    */
  589.     if (bdos(RENFIL,ownfcb) == (char)0xff)
  590.         txtout(" Rename FAILED.");
  591.     else
  592.         txtout(" Renamed OK.");
  593.     break;
  594.  
  595.       case 4:            /* TYPE            */
  596.     txtout("  ");
  597.     if ( (fileok(s1) & (char)0x07) != 0)
  598.         break;
  599.     printf("TYPing file <%s>:\r\r", explicit);
  600.     if ( (tfp = fopen(s1,"r")) == 0 ) 
  601.         txtout(" File inaccessible.");
  602.     else while ( (ic = getc(tfp)) != EOF ) {
  603.         c = ic;
  604.         if (c == CTLZ)
  605.         break;            /* CP/M EOF    */
  606.         if (outfc(ascch(c)) != 0)
  607.         break;
  608.     }   
  609.     outfc(CR);
  610.     if (c == CTLZ)
  611.         printf("End of File <%s>.\r",s1);
  612.     fclose(tfp);
  613.     break;
  614.  
  615. #ifdef    MPUZ80
  616.       case 5:            /* USER    (CP/M only)    */
  617.     if ( (user = atoi(s1)) > 15 )
  618.         txtout("  User > 15 not valid");
  619.     else {
  620.         bdos(GETUSR,user);
  621.         printmsg("  Now: %s", userpath());
  622.     }
  623.     break;
  624. #endif
  625.  
  626.       case 6:            /* UPATH        */
  627.     printf("  Environment: %s ",userpath());
  628.     break;
  629.  
  630.       case 7:            /* DRIVE            */
  631.     txtout("  DRIVE change: ");
  632.     disk = (*s1 & 0x5f) - 'A';
  633.     if ( (disk < 0) || (disk > 15) )
  634.         txtout("Only A-P are valid disks ");
  635.     else {
  636.         bdos(SELDSK,disk);
  637.         txtout(userpath());
  638.         if (rochek(disk) != 0)
  639.         txtout(diskro);
  640.     }
  641.     break;
  642.  
  643. #ifdef    MPUZ80
  644.      case 9:            /* CHAnge disks    (CP/M only)    */
  645.     bdos(SELDSK,0);
  646.   /* if not on drive A, r/o not permanently removed        */
  647.     printmsg("  Back on %s; Change any disk & hit RETURN ",userpath());
  648.     while (kbdin() == 0)
  649.         ;
  650.     bdos(RSTDRV,0xffff);
  651.     break;
  652. #endif
  653.  
  654.       case 10:            /* HELP or ?            */
  655.     txtout(os1);
  656.     txtout(os2);
  657.     break;
  658.  
  659.       default:
  660.     txtout("???");
  661.     break;
  662.     }                /* end switch            */
  663.     return(1);            /* normal return        */
  664. }            /* end of osaction()            */
  665.  
  666.  
  667.  
  668.  
  669. rochek(d)        /* check for disk r/o            */
  670. /* returns NZ if disk d is r/o                    */
  671. int    d;            /* disknumber 0-15        */
  672. {
  673.     if (d > 15)
  674.     return(-1);
  675.     else
  676. #ifdef    MPUZ80
  677.     return( bdoshl(GETROV,0) & (0x0001 << d) );
  678. #else                /* no-op under MSDOS        */
  679.     return(0);
  680. #endif
  681. }            /* end of rochek()            */
  682.  
  683.  
  684.  
  685. char  *userpath()    /* return environment            */
  686. /* returns address of a string of about 20 chars containing
  687.     user-number & disk etc.                    */
  688. {
  689.     int        i;
  690.     char    disk, user;
  691.  
  692.     disk = bdos(CURDSK,0) + 'A';
  693. #ifdef    MPUZ80
  694. /* CP/M - return disk & user-no                    */
  695.     user = bdos(GETUSR,0xff);
  696.     sprintf(work,"User %d, drive %c: ", user, disk);
  697. #else
  698. /* MSDOS - reutrn disk only (pathname doesnt work)        */
  699.     sprintf(work,"Drive %c: ", disk);
  700. #endif
  701.     return(work);
  702. }            /* end of userpath()            */
  703.  
  704.  
  705.  
  706. CHAR wildex(wild,line)    /* expand wildcard names        */
  707. /* Permits use of same workspace for two parameters, but
  708.     "line" must be at least 85 chars long.
  709.    Returns count of files expanded, with 80-bit set if still
  710.     more on disk.                        */
  711. char    *wild, *line;
  712. {
  713.     char    count = 0, dsk = 0, ic = 0;
  714.     char    local[14], *last, *next;
  715.  
  716.     if (wild[1] == ':')            /* disk letter        */
  717.     dsk = *wild;
  718.     next = local;
  719.     while ( (*next++ = *wild++) != 0 )
  720.     ;
  721.     last = next = line;
  722.     if (dsk != 0) {            /* disk-letter to first    */
  723.     *(++next) = dsk;
  724.     *(++next) = ':';
  725.     }
  726.     if ( (filechek(0,local,++next) & (char)0x01) == 0 ) do {
  727.     if ( (++count > 8) || (ic > 70) )
  728.         return(count + (char)0x7f);    /* count & 0x80        */
  729.     *last = SP;        /* terminator => separator    */
  730.     while ( *(++next) != 0 )
  731.         ++ic;
  732.     last = next++;
  733.     if (dsk != 0) {        /* copy disk-letter to next    */
  734.         *next++ = dsk;
  735.         *next++ = ':';
  736.     }
  737.     } while ( (filechek(1,local,next) & (char)0x01) == 0 ) ;
  738.   /* this copies next explixcit name onto line            */
  739.     else
  740.     *line = 0;        /* null line            */
  741.     return(count);
  742. }            /* end of wildex()            */
  743.  
  744. /*****************  End of file KDISK.C  ************************/
  745.  
  746.  
  747.