home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CSAPE32.ARJ / SOURCE / OWLSCR / PCDIR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-16  |  23.2 KB  |  880 lines

  1. /*
  2.     pcdir.c
  3.  
  4.     % DOS-specific file and directory handling functions.
  5.  
  6.     6/27/90  by Mike and Ted.
  7.  
  8.     OWL-PC 1.2
  9.     Copyright (c) 1990 by Oakland Group, Inc.
  10.     ALL RIGHTS RESERVED.
  11.  
  12.     Revision History:
  13.     -----------------
  14.     10/15/90 jdc    preened Descend code
  15.     10/18/90 mla    added ..\ case to pcdir_Ascend
  16.     10/18/90 ted/jmd changed int86ds to int86 for GETDTA case
  17.     10/20/90 mla    rewrote pcdir_ascend
  18.     10/21/90 mla    added colon sensitivty to pcdir_Ascend
  19.     10/23/90 mla    added NULL path, name protection to Split
  20.     10/24/90 mla    added _IsFullSpec, allowed common 1st & 4th args in Join
  21.     10/28/90 mla    preened
  22.     10/31/90 jdc    fixed mallocs
  23.     12/05/90 ted    defined OAK_DOS to avoid confusion w/ OS/2 in oakdir.h.
  24.     12/15/90 mla    fixed return value in pcdir_StripCase
  25.     12/15/90 mla    rewrote pcdir_GetCurrDir to return absolute path and
  26.                     drive in lower case, fixed return value too.
  27.     12/15/90 mla    made pcdir_Ascend drive letter sensative.
  28. */
  29. #include "pcpriv.h"
  30.  
  31. #include <ctype.h>
  32. #include <time.h>
  33.  
  34. #include "oaktime.h"
  35.  
  36. #ifndef OAK_DOS
  37. #    define OAK_DOS
  38. #endif
  39. #include "oakdir.h"
  40. /* -------------------------------------------------------------------------- */
  41. /* Mask to ignore bit not used in the masks for odir_Open  */
  42. #define OFILE_MASK        0x07
  43.  
  44. /* DOS path separator character  */
  45. #define OFILE_SEPCHAR    '\\'
  46.  
  47. /* DOS file system attribute masks  */
  48. #define DOS_READONLY    0x01
  49. #define DOS_HIDDEN        0x02
  50. #define DOS_LABEL        0x08
  51. #define DOS_SDIR        0x10
  52. #define DOS_ALL            0x3f
  53.  
  54. /* DOS flags resister carry bit mask  */
  55. #define CARRYMASK    0x0001
  56.  
  57. /* DOS file type filter function  */
  58. OSTATIC boolean typemask(byte type, byte mask);
  59.  
  60. /* DOS dependent directory info here (what odir_type points to) */
  61. typedef struct _dta {
  62.     char        reserved[21];    /*  reserved for use by DOS  */
  63.     byte            attrib;        /*  files attributes  */
  64.     unsigned short    time;        /*  time of last write to file  */
  65.     unsigned short    date;        /*  date of last write to file  */
  66.     unsigned long    size;        /*  size of file in bytes  */
  67.     char            name[13];    /*  name of file  */
  68. } dta_struct;
  69.  
  70. typedef struct _pcdir {
  71.     boolean        first;
  72.     byte         file_type;
  73.     char        path[OFILE_PATHLEN];
  74.     dta_struct    file_dta;
  75. } pcdir_struct;
  76. /* -------------------------------------------------------------------------- */
  77.  
  78. odir_type pcdir_Open(char *user_spec, byte file_type)
  79. /*
  80.     This routine opens an oakland directory stream and returns a handle to it.
  81.     The handle is then used in calls to odir_Read, and odir_Close.
  82.     If the stream cannot be opened for any reason, or if it is empty, 
  83.     NULL is returned.
  84.     
  85.  
  86.     The first parameter is a string which should specify a path to the 
  87.     directory and a mask to use to filter the filenames in the directory.
  88.     If the first parameter is specifies only a path (no file mask), the 
  89.     indicated directory is used and the filenames are not filtered.    If the 
  90.     first parameter is NULL or "", the current directory is used and 
  91.     the filenames are not filtered.  
  92.  
  93.     The second parameter is a mask which is used to filter the directory 
  94.     entries by type.  Defined masks are:  
  95.         OFILE_ALL     - does no type filtering.  Everything available from
  96.                       the opering system.
  97.         OFILE_DIRS    - Returns subdirectories within the specified directory.
  98.         OFILE_FILES - Returns files in the specified directory.
  99.     The masks can be used alone or in combination with each other by bitwise
  100.     or'ing the masks together.  If OFILE_ALL is used in conjuction with other 
  101.     masks, it has the same effect as if used alone.
  102. */
  103. {
  104.     pcdir_struct    *odirp;
  105.     dta_struct        *olddta;
  106.     OREGS            regs;
  107.     char            *internal_spec, dummy_name[OFILE_NAMELEN];
  108.  
  109.     if ((odirp = (pcdir_struct *) omalloc(ID_ODIR, sizeof(pcdir_struct))) == NULL) {
  110.         return (NULL);
  111.     }
  112.     regs.h.ah = DOS_GETDTA;                    /*  save dta  */
  113.     oakint86(DOS_INT, ®s);
  114.     regs.x.dx = regs.x.bx;
  115.     olddta = (dta_struct *) regs.a.esdx;
  116.  
  117.     regs.h.ah = DOS_SETDTA;
  118.     regs.a.esdx = &odirp->file_dta;
  119.     regs.x.ds = regs.x.es;
  120.     oakint86ds(DOS_INT, ®s, 0);
  121.  
  122.     /*  adjust path to include a wildcard for filenames  */
  123.     if (user_spec == NULL || *user_spec == '\0') {
  124.         if ((internal_spec = (char *) omalloc(OA_NOTAG, strlen(OFILE_WILDCARD) + 1)) == NULL) {
  125.             ofree(ID_ODIR, odirp);
  126.             odirp = NULL;
  127.             return(NULL);
  128.         }
  129.         strcpy(internal_spec, OFILE_WILDCARD);
  130.     }
  131.     else {
  132.         if (user_spec[strlen(user_spec) - 1] == OFILE_SEPCHAR
  133.                 || user_spec[strlen(user_spec) - 1] == ':') {
  134.             /*  user_spec is just a path (no file mask)  */
  135.             if ((internal_spec = (char *) omalloc(OA_NOTAG, strlen(user_spec) 
  136.                     + strlen(OFILE_WILDCARD) + 1)) == NULL) {
  137.                 ofree(ID_ODIR, odirp);
  138.                 odirp = NULL;
  139.                 return(NULL);
  140.             }
  141.             strcpy(internal_spec, user_spec);
  142.             strcat(internal_spec, OFILE_WILDCARD);
  143.         }
  144.         else {
  145.             if ((internal_spec = (char *) omalloc(OA_NOTAG, strlen(user_spec) + 1))
  146.                     == NULL) {
  147.                 ofree(ID_ODIR, odirp);
  148.                 odirp = NULL;
  149.                 return(NULL);
  150.             }
  151.             strcpy(internal_spec, user_spec);
  152.         }
  153.     }
  154.                 
  155.     regs.h.ah = DOS_FINDFIRST;
  156.     regs.a.esdx = internal_spec;        /*  ds:dx -> spec  */
  157.     regs.x.ds = regs.x.es;            
  158.     regs.x.cx = DOS_ALL;  /*  gets all files, we'll filter manually  */
  159.  
  160.     /* If no matches */
  161.     if (oakint86ds(DOS_INT, ®s, strlen(internal_spec)) & CARRYMASK) {
  162.         ofree(ID_ODIR, odirp);
  163.         odirp = NULL;
  164.     }
  165.  
  166.     ofree(OA_NOTAG, internal_spec);
  167.  
  168.     regs.h.ah = DOS_SETDTA;                    /*  restore dta  */
  169.       regs.a.esdx = olddta;
  170.     regs.x.ds = regs.x.es;
  171.     oakint86ds(DOS_INT, ®s, 0);
  172.  
  173.     if (odirp == NULL) {
  174.  
  175.         return(NULL);
  176.     }
  177.  
  178.     odirp->first = TRUE;
  179.  
  180.     /*  pass requested attrs down so read can filter  */
  181.     odirp->file_type = file_type;
  182.  
  183.     /*  pass the path down so it can be appended to the filenames when output  */
  184.     pcdir_Split(user_spec, odirp->path, sizeof(odirp->path), dummy_name, sizeof(dummy_name));
  185.  
  186.     return((odir_type) odirp);
  187. }
  188. /* -------------------------------------------------------------------------- */
  189.  
  190. boolean pcdir_Read(odir_type odirpa, ofile_struct *file_info)
  191. /*
  192.     This routine reads the next entry from an oakland directory    stream.
  193.     If an entry is found to return, pcdir_Read returns TRUE.  If there
  194.     are no more entries in the stream, it returns FALSE.
  195.  
  196.     The first parameter is the directory stream from which to fetch an entry.
  197.  
  198.     The second parameter is a pointer to an ofile_struct where the information
  199.     about the entry will be stored.  Once the information has been put into 
  200.     the ofile_struct, the following macros may be used to access it:
  201.         ofile_GetType()  - returns the type of the file:  OFILE_ALL if it was
  202.                            specified in the call to odir_Open for this stream,
  203.                            OFILE_FILES for files, and OFILE_DIRS for dirs.
  204.         ofile_GetTime()  - returns an ansi struct tm with the date and time 
  205.                            the file was last modified.
  206.         ofile_GetSize()  - returns the size of the file in bytes.
  207.         ofile_GetSpec()  - returns the spec for the file including a path
  208.                            starting where the spec given to odir_Open started.
  209.     They each take a single parameter:  the ofile_struct of the entry of 
  210.     interest.  (Note:  NOT a pointer to the ofile_struct)
  211. */
  212. {
  213.     pcdir_struct    *odirp;
  214.     dta_struct        *olddta;
  215.     boolean            foundone;
  216.     OREGS            regs;
  217.  
  218.     odirp = (pcdir_struct *) odirpa;
  219.  
  220.     if (odirp == NULL) {
  221.         return(FALSE);
  222.     }
  223.  
  224.     regs.h.ah = DOS_GETDTA;            /*  save dta  */
  225.     oakint86(DOS_INT, ®s);
  226.     regs.x.dx = regs.x.bx;
  227.     olddta = (dta_struct *) regs.a.esdx;
  228.  
  229.     regs.h.ah = DOS_SETDTA;
  230.     regs.a.esdx = &odirp->file_dta;
  231.     regs.x.ds = regs.x.es;
  232.     oakint86ds(DOS_INT, ®s, 0);
  233.  
  234.     if (odirp->first) {            /* If first use the first dta full */
  235.         odirp->first = FALSE;
  236.         foundone = TRUE;
  237.     }
  238.     else {                        /* Otherwise get a new dta full */
  239.         regs.h.ah = DOS_FINDNEXT;
  240.  
  241.         if (oakint86ds(DOS_INT, ®s, 0) & CARRYMASK) { /* If no more matches  */
  242.             foundone = FALSE;
  243.         }
  244.         else {
  245.             foundone = TRUE;
  246.         }
  247.     }
  248.  
  249.     /*  if this file doesn't have at least one requested attribute,
  250.             discard it and get another  */
  251.     while (!typemask(odirp->file_dta.attrib, odirp->file_type)) {
  252.  
  253.         regs.h.ah = DOS_FINDNEXT;
  254.  
  255.         if (oakint86ds(DOS_INT, ®s, 0) & CARRYMASK) { /* If no more matches */
  256.             foundone = FALSE;
  257.             break;
  258.         }
  259.     }
  260.  
  261.     regs.h.ah = DOS_SETDTA;                    /*  restore dta  */
  262.       regs.a.esdx = olddta;
  263.     regs.x.ds = regs.x.es;
  264.     oakint86ds(DOS_INT, ®s, 0);
  265.  
  266.     if (foundone) {
  267.         /* Copy from DOS dta structure into OS-independent file_info structure */
  268.  
  269.         /*  files attributes  */
  270.         if (odirp->file_type & OFILE_ALL) {
  271.             file_info->type = OFILE_ALL;
  272.         }
  273.         else {
  274.             switch (OFILE_MASK & odirp->file_type) {
  275.             case OFILE_DIRS:
  276.             case OFILE_FILES:
  277.                 file_info->type = odirp->file_type;
  278.                 break;
  279.             case OFILE_DIRS | OFILE_FILES:
  280.                 if (odirp->file_dta.attrib & DOS_SDIR) {
  281.                     file_info->type = OFILE_DIRS;
  282.                 }
  283.                 else {
  284.                     file_info->type = OFILE_FILES;
  285.                 }
  286.                 break;
  287.             }
  288.         }
  289.  
  290.         /*  time of last write  */
  291.         file_info->time.tm_hour = (odirp->file_dta.time) >> 11;
  292.         file_info->time.tm_min  = (odirp->file_dta.time & 0x07e0) >> 5;
  293.         file_info->time.tm_sec  = (odirp->file_dta.time & 0x001f) << 1;
  294.  
  295.         /*  date of last write  */
  296.         file_info->time.tm_year = (odirp->file_dta.date >> 9) + 1980;
  297.         file_info->time.tm_mon  = (odirp->file_dta.date & 0x01e0) >> 5;
  298.         file_info->time.tm_mday = odirp->file_dta.date & 0x001f;
  299.  
  300.         /*  calculate weekday, yearday, and dst values  */
  301.         tm_Adjust(&file_info->time);
  302.  
  303.         file_info->size = odirp->file_dta.size;            /*  size of file  */
  304.  
  305.         pcdir_Join(file_info->spec, sizeof(file_info->spec), odirp->path, 
  306.             odirp->file_dta.name);                        /*  name of file  */
  307.         pcdir_StripCase(file_info->spec);
  308.     }
  309.  
  310.     return(foundone);
  311. }
  312. /* -------------------------------------------------------------------------- */
  313.  
  314. void pcdir_Close(odir_type odirp)
  315. /*
  316.     This routine closes an oakland directory stream and frees all resources
  317.     it used.
  318.  
  319.     It's single parameter is the hanlde to the stream to close.
  320. */
  321. {
  322.     if (odirp != NULL) {
  323.         ofree(ID_ODIR, odirp);
  324.     }
  325.     return;
  326. }
  327. /* -------------------------------------------------------------------------- */
  328.  
  329. boolean pcfile_Remove(char *fname_spec)
  330. /*
  331.     This routine removes (deletes) the specified file from the file system.
  332.  
  333.     It's single parameter is a string specifing a path to the file to be
  334.     removed.
  335.  
  336.     It returns TRUE if the removal took place succesfully, FALSE otherwise.
  337. */
  338. {
  339.     OREGS            regs;
  340.  
  341.     regs.h.ah = DOS_DELETE;
  342.     regs.a.esdx = fname_spec;        /*  ds:dx -> spec  */
  343.     regs.x.ds = regs.x.es;            
  344.  
  345.     return((oakint86ds(DOS_INT, ®s, 0) & CARRYMASK) ? TRUE : FALSE);
  346. }
  347. /* -------------------------------------------------------------------------- */
  348.  
  349. boolean    pcfile_IsValid(char *name, boolean wildok)
  350. /*
  351.     determines if a filename is valid under the operating system.
  352. */
  353. {
  354.     char    goodchrs[13];
  355.     int        i, dots, dot = -1;
  356.  
  357.     if (wildok == TRUE) {
  358.         strcpy(goodchrs, "@!-{}_`^~.*?");
  359.     }
  360.     else {
  361.         strcpy(goodchrs, "@!-{}_`^~.");
  362.     }
  363.  
  364.     for (dots = i = 0; name[i] != '\0'; i++) {
  365.         if (!(name[i] > 64 && name[i] < 91)            /*  [a-z]  */
  366.                 && !(name[i] > 96 && name[i] < 123)    /*  [A-Z]  */
  367.                 && !(name[i] > 47 && name[i] < 58)    /*  [0-9]  */
  368.                 && !(name[i] > 34 && name[i] < 42)    /*  [#$%&'()]  */
  369.                 && !strchr(goodchrs, name[i])) {
  370.  
  371.             return(FALSE);
  372.         }
  373.  
  374.         /*  only one dot allowed and not in the first position  */
  375.         if (name[i] == '.') {
  376.             if (++dots > 1 || i == 0) {
  377.  
  378.                 return(FALSE);
  379.             }
  380.  
  381.             dot = i;
  382.         }
  383.     }
  384.  
  385.     if (dot == -1) {  /*  there was no dot  */
  386.         if (i > 8) {
  387.  
  388.             return(FALSE);
  389.         }
  390.     }
  391.     else if (i - dot > 4 || dot > 8) {
  392.  
  393.         return(FALSE);
  394.     }
  395.  
  396.     return(TRUE);
  397. }
  398. /* -------------------------------------------------------------------------- */
  399.  
  400. boolean    pcdir_IsValid(char *dir)
  401. /*
  402.     determines if a directory is valid under the operating system.
  403. */
  404. {
  405.     char    *s, *start;
  406.     int        i;
  407.  
  408.     /*  empty string is valid (current dir)  */
  409.     if (*dir == '\0') {
  410.         return(TRUE);
  411.     }
  412.  
  413.     s = dir;
  414.  
  415. /*  drive  */
  416.     if (isalpha(*s) && *(s + 1) == ':') {
  417.         s += 2;
  418.     }
  419.  
  420. /*   main loop  */
  421.     while (*s != '\0') {
  422.  
  423.     /*  slash  */
  424.         if (*s == OFILE_SEPCHAR) {
  425.             s++;
  426.             
  427.             /*  skip all adjacent slashs  */
  428.             while (*s == OFILE_SEPCHAR) {
  429.                 s++;
  430.             }
  431.         }
  432.  
  433.     /*  directories  */
  434.         start = s;
  435.  
  436.         for (i = 0; *s != '\0' && *s != '.' && *s != OFILE_SEPCHAR; s++) {
  437.  
  438.             /*  is this a legal directory char  */
  439.             if ((*s > 64 && *s < 91)            /*  [a-z]  */
  440.                     || (*s > 96 && *s < 123)    /*  [A-Z]  */
  441.                     || (*s > 47 && *s < 58)    /*  [0-9]  */
  442.                     || (*s > 34 && *s < 42)    /*  [#$%&'()]  */
  443.                     || strchr("@!-{}_`^~", *s)) {
  444.         
  445.                 i++;    
  446.                 if (i == 8) {
  447.                     /*  skip till '.', OFILE_SEPCHAR or '\0'  */
  448.                     for (s++; *s != '.' && *s != '\0' && *s != OFILE_SEPCHAR; s++)
  449.                         ;
  450.                     break;
  451.                 }
  452.             }
  453.             else {
  454.                 return(FALSE);
  455.             }
  456.         }
  457.         
  458.         /*  now where at either a '.', OFILE_SEPCHAR or '\0' in the source string  */
  459.  
  460. /*  dot  */
  461.         /*  '..' = parent directory case  */        
  462.         if (*s == '.' && *(s + 1) == '.' 
  463.                 && (*(s + 2) == OFILE_SEPCHAR || *(s + 2) == '\0')) {
  464.             s += 2;
  465.             continue;
  466.         }
  467.  
  468.         /*  '.' = current directory case  */
  469.         if (*s == '.' && (*(s + 1) == OFILE_SEPCHAR || *(s + 1) == '\0')) {
  470.             s++;
  471.             continue;
  472.         }
  473.  
  474.         if (*s == '.') {
  475.  
  476.             /*  if the dot is the first char, this spec is invalid  */
  477.             if (s == start) {
  478.                 return(FALSE);
  479.             }
  480.             s++;
  481.  
  482.             /*  dot not allowed in last position  */
  483.             if (*s == OFILE_SEPCHAR || *s == '\0') {
  484.                 return(FALSE);
  485.             }
  486.  
  487. /*  extention  */
  488.             for (i = 0; *s != '\0' && *s != OFILE_SEPCHAR; s++) {
  489.  
  490.                 /*  is this a legal directory char  */
  491.                 if ((*s > 64 && *s < 91)            /*  [a-z]  */
  492.                         || (*s > 96 && *s < 123)    /*  [A-Z]  */
  493.                         || (*s > 47 && *s < 58)    /*  [0-9]  */
  494.                         || (*s > 34 && *s < 42)    /*  [#$%&'()]  */
  495.                         || strchr("@!-{}_`^~", *s)) {
  496.  
  497.                     i++;
  498.                     if (i > 3) {
  499.                         return(FALSE);
  500.                     }
  501.                 }
  502.                 else {
  503.                     return(FALSE);
  504.                 }
  505.             }
  506.         }
  507.     }
  508.  
  509.     return(TRUE);
  510. }
  511. /* -------------------------------------------------------------------------- */
  512.  
  513. boolean    pcdir_MakePath(char *dirbuf, int buflen, char *dir)
  514. /*
  515.     if the supplied string is not empty, we modify it to indicate a path
  516. */
  517. {
  518.     int dirlen;
  519.  
  520.     if (*dir == '\0') {
  521.         *dirbuf = '\0';
  522.  
  523.         return(TRUE);
  524.     }
  525.  
  526.     dirlen = strlen(dir);
  527.  
  528.      if (dir[dirlen - 1] == OFILE_SEPCHAR) {
  529.         if (buflen > dirlen) {
  530.             if (dirbuf != dir) {
  531.                 strcpy(dirbuf, dir);
  532.             }
  533.  
  534.             return(TRUE);
  535.         }
  536.     }
  537.     else {
  538.         if (buflen > dirlen + 1) {
  539.             if (dirbuf != dir) {
  540.                 strcpy(dirbuf, dir);
  541.             }
  542.             dirbuf[dirlen] = OFILE_SEPCHAR;
  543.             dirbuf[dirlen + 1] = '\0';
  544.  
  545.             return(TRUE);
  546.         }
  547.     }
  548.     return(FALSE);
  549. }
  550. /* -------------------------------------------------------------------------- */
  551.  
  552. boolean pcdir_Ascend(char *newpath, int maxnewpath, char *oldpath)
  553. /*
  554.     This routine forms a string representing the path to the parent directory 
  555.     of the path represented by the given string.  It does no checking with
  556.     the directory system to verify either of the paths are valid; It simply
  557.     minipulates the strings.
  558.  
  559.     The first parameter points to the location where the result string should
  560.     be stored.
  561.  
  562.     The second parameter is the size of the available space pointer to by 
  563.     the first parameter.
  564.  
  565.     The third parameter is the supplied string representing the starting path.
  566.     The path must end with the separator character for paths of the operating
  567.     system and be null terminated.  Under Dos the is '\\'.
  568.  
  569.     It returns TRUE if successful, FALSE otherwise.
  570. */
  571. {
  572.     int    i;        /*  the new path length  */
  573.  
  574.     pcdir_MakePath(newpath, maxnewpath, oldpath);
  575.     i = strlen(newpath);
  576.  
  577.     /*  can't ascend above root directory  */
  578.     if ((i == 1 && newpath[0] == OFILE_SEPCHAR) 
  579.             || (i == 3 && isalpha(newpath[0]) && newpath[1] == ':' 
  580.                 && newpath[2] == OFILE_SEPCHAR)) {
  581.  
  582.         return(FALSE);
  583.     }
  584.  
  585.     /*  if there isn't a subdir availiable to chop, append "../" to ascend  */
  586.     if (i == 0 || (newpath[i - 2] == '.' && newpath[i - 3] == '.')) {
  587.         if (i + 3 <= maxnewpath) {
  588.  
  589.             /*  strcat "../"  */
  590.             newpath[i] = '.';
  591.             newpath[i + 1] = '.';
  592.             newpath[i + 2] = OFILE_SEPCHAR;
  593.             newpath[i + 3] = '\0';
  594.  
  595.             return(TRUE);
  596.         }
  597.         return(FALSE);
  598.     }
  599.  
  600.     /*  chop last subdir  */
  601.     for (i -= 2; newpath[i] != OFILE_SEPCHAR && newpath[i] != ':' && i > 0; i--)
  602.         ;
  603.     if (newpath[i] == OFILE_SEPCHAR || newpath[i] == ':') {
  604.         newpath[i + 1] = '\0';
  605.     }
  606.     else {
  607.         *newpath = '\0';
  608.     }
  609.     return(TRUE);
  610. }
  611. /* -------------------------------------------------------------------------- */
  612.  
  613. boolean pcdir_Descend(char *newpath, int maxnewpath, char *oldpath, char *subdir)
  614. /*
  615.     This routine forms a string representing the path to a child directory 
  616.     of the path represented by the given string.  It does no checking with
  617.     the directory system to verify either of the paths are valid; It simply
  618.     minipulates the strings.
  619.  
  620.     The first parameter points to the location where the result string should
  621.     be stored.
  622.  
  623.     The second parameter is the size of the available space pointer to by 
  624.     the first parameter.
  625.  
  626.     The third parameter is the supplied string representing the starting path.
  627.     The path must end with the separator character for paths of the operating
  628.     system and be null terminated.  Under Dos the is '\\'.
  629.  
  630.     The fourth parameter is a string indicating into which subdirectory
  631.     to descend
  632.  
  633.     It returns TRUE if successful, FALSE otherwise.
  634. */
  635. {
  636.     int    oldpathlen, subdirlen;
  637.  
  638.     oldpathlen = strlen(oldpath);
  639.     subdirlen = strlen(subdir);
  640.  
  641.     if (oldpathlen + subdirlen < maxnewpath) {
  642.         if (newpath != oldpath) {
  643.             strcpy(newpath, oldpath);
  644.         }
  645.         newpath += oldpathlen;
  646.         strcpy(newpath, subdir);
  647.         newpath += subdirlen;
  648.         if (*(newpath - 1) != OFILE_SEPCHAR) {
  649.             *newpath = OFILE_SEPCHAR;
  650.             newpath++;
  651.         }
  652.         *newpath = '\0';
  653.         return(TRUE);
  654.     }
  655.     return(FALSE);
  656. }
  657. /* -------------------------------------------------------------------------- */
  658.  
  659. boolean pcdir_Split(char *spec, char *path, int maxpath, char *name, int maxname)
  660. /*
  661.     This routine separates a string representing a file spec into a string 
  662.     representing the path of the spec and a string representing the filename
  663.     of the spec.  If supplied with only a filename, it sets the path to "".
  664.     If supplied with only a path (terminated with the operating systems path
  665.     separator character), it sets the filename to "".  If supplied with "", it 
  666.     sets both the path and name to "".   It does no checking with the directory 
  667.     system to verify either the path or the filename is    valid; It simply 
  668.     manipulates the strings.
  669.  
  670.     The first parameter is the supplied file spec.
  671.  
  672.     The second parameter points to the location where the result path 
  673.     string should be stored, it can be NULL if the path is to be ignored.
  674.  
  675.     The third parameter is the size of the available space pointed to by 
  676.     the second parameter. If the second parameter is NULL, the value of 
  677.     this parameter is ignored.
  678.  
  679.     The fourth parameter points to the location where the result filename 
  680.     string should be stored, it can be NULL if the name is to be ignored.
  681.  
  682.     The fifth parameter is the size of the available space pointed to by 
  683.     the fourth parameter. If the fourth parameter is NULL, the value of 
  684.     this parameter is ignored.
  685.  
  686.  
  687.     It returns TRUE if successful, FALSE otherwise.
  688. */
  689. {
  690.     int        pathlen, namelen, i, last = -1, colon = -1;
  691.  
  692.     if (spec == NULL) {
  693.         return(FALSE);
  694.     }
  695.  
  696.     for (i = 0; spec[i] != '\0'; i++) {
  697.         if (spec[i] == OFILE_SEPCHAR) {
  698.             last = i;
  699.         }
  700.         else if (spec[i] == ':') {
  701.             colon = i;
  702.         }
  703.     }
  704.  
  705.     if (last != -1) {    /*  path and name provided  */
  706.         pathlen = last + 1;
  707.         namelen = strlen(spec + last + 1);
  708.  
  709.         if (path != NULL) {
  710.             if (pathlen < maxpath) {
  711.                 strncpy(path, spec, pathlen);
  712.                 path[pathlen] = '\0';
  713.             }
  714.             else {
  715.                 return(FALSE);
  716.             }
  717.         }
  718.         if (name != NULL) {
  719.             if (namelen < maxname) {
  720.                 strcpy(name, spec + last + 1);
  721.             }
  722.             else {
  723.                 return(FALSE);
  724.             }
  725.         }
  726.     }
  727.     else {                /*  only name provided  */
  728.         if (colon == -1) {
  729.             if (path != NULL) {
  730.                 *path = '\0';
  731.             }
  732.             if (name != NULL) {
  733.                 if (strlen(spec) < maxname) {
  734.                     strcpy(name, spec);
  735.                 }
  736.                 else {
  737.                     return(FALSE);
  738.                 }
  739.             }   
  740.         }
  741.         else {    /*  there is a colon but no slash's  */
  742.             pathlen = colon + 1;
  743.             namelen = strlen(spec + colon + 1);
  744.  
  745.             if (path != NULL) {
  746.                 if (pathlen < maxpath) {
  747.                     strncpy(path, spec, pathlen);
  748.                     path[pathlen] = '\0';
  749.                 }
  750.                 else {
  751.                     return(FALSE);
  752.                 }
  753.             }
  754.             if (name != NULL) {
  755.                 if (namelen < maxname) {
  756.                     strcpy(name, spec + colon + 1);
  757.                 }
  758.                 else {
  759.                     return(FALSE);
  760.                 }
  761.             }
  762.         }
  763.     }
  764.     return(TRUE);
  765. }
  766. /* -------------------------------------------------------------------------- */
  767.  
  768. boolean pcdir_Join(char *spec, int maxspec, char *path, char *name)
  769. /*
  770.     This routine connects a string representing the path of a spec and 
  771.     a string representing the filename of a spec to form a string representing
  772.     a complete file spec.  It does no checking with    the directory system to 
  773.     verify either of the paths or the filename are valid; 
  774.     It simply minipulates the strings.  The first and third parameters or 
  775.     the first and fourth parameters are allowed to point to the same space
  776.     since they may all be paths.
  777.  
  778.     The first parameter points to the location where the result spec 
  779.     string should be stored.
  780.  
  781.     The second parameter is the size of the available space pointer to by 
  782.     the first parameter.
  783.  
  784.     The third parameter is the supplied path.
  785.  
  786.     The fourth parameter is the supplied filename.
  787.  
  788.     It returns TRUE if successful, FALSE otherwise.
  789. */
  790. {                
  791.     int        pathlen, namelen;
  792.     char    strbuf[OFILE_PATHLEN];
  793.  
  794.     pathlen = strlen(path);
  795.     namelen = strlen(name);
  796.  
  797.     if (pathlen + namelen < maxspec) {
  798.         strcpy(strbuf, path);
  799.         strcat(strbuf, name);
  800.         strcpy(spec, strbuf);
  801.         return(TRUE);
  802.     }
  803.     else {
  804.         return(FALSE);
  805.     }
  806. }
  807. /* -------------------------------------------------------------------------- */
  808.  
  809. char *pcdir_StripCase(char *str)
  810. /*
  811.     This function converts all uppercase characters in the supplied string 
  812.     into lowercase.
  813. */
  814. {
  815.     char *string = str;
  816.  
  817.     for (;*str != '\0'; str++) {
  818.         *str = (char)otolower(*str);
  819.     }
  820.     return(string);
  821. }
  822. /* -------------------------------------------------------------------------- */
  823.  
  824. boolean pcdir_GetCurrDir(char *buf, int len)
  825. {
  826.     OREGS            regs;
  827.     boolean            ret;
  828.  
  829.     if (len >= 64 + 3) {        /*  path + 'a:\'  */
  830.  
  831.         regs.h.ah = DOS_GETDRIVE;
  832.         oakint86ds(DOS_INT, ®s, 0);
  833.         *buf = 'a' + regs.h.al;
  834.         *(buf + 1) = ':';
  835.         *(buf + 2) = OFILE_SEPCHAR;
  836.  
  837.         regs.h.ah = DOS_GETCD;
  838.         regs.a.esdx = buf + 3;        /*  ds:si -> buf + 3  */
  839.         regs.x.ds = regs.x.es;
  840.         regs.x.si = regs.x.dx;
  841.         regs.h.dl = 0;            /*  default drive  */
  842.  
  843.         ret = (oakint86ds(DOS_INT, ®s, 0) & CARRYMASK) ? FALSE : TRUE;
  844.  
  845.         if (ret == TRUE) {
  846.             pcdir_StripCase(buf + 3);
  847.         }
  848.         return(ret);
  849.     }
  850.     return(FALSE);
  851. }
  852.  
  853. /* -------------------------------------------------------------------------- */
  854.  
  855. static boolean typemask(byte type, byte mask)
  856. /*
  857.     This function is used by ofile_Read to decide if given files type
  858.     satisfies the type filter for the directory stream.
  859. */
  860. {
  861.     if (mask & OFILE_ALL) {
  862.         return(TRUE);
  863.     }
  864.  
  865.     if ((type & DOS_HIDDEN) || (type & DOS_LABEL)) {
  866.         return(FALSE);
  867.     }
  868.  
  869.     if ((mask & OFILE_FILES) && !(type & DOS_SDIR)) {
  870.         return(TRUE);
  871.     }
  872.  
  873.     if ((mask & OFILE_DIRS) && (type & DOS_SDIR)) {
  874.         return(TRUE);
  875.     }
  876.     return(FALSE);
  877. }
  878. /* -------------------------------------------------------------------------- */
  879.  
  880.