home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs57pc3.zip / diff / pc / dirent.c < prev    next >
C/C++ Source or Header  |  1999-01-17  |  10KB  |  507 lines

  1. /* @(#)dirent.c
  2.  *
  3.  * public domain implementation of POSIX directory routines 
  4.  * for DOS, OS/2 and Win32
  5.  *
  6.  * Written by Michael Rendell ({uunet,utai}michael@garfield), August 1897
  7.  *
  8.  * Ported to OS/2 by Kai Uwe Rommel, December 1989, February 1990
  9.  * Change for HPFS support, October 1990
  10.  * Updated for better error checking and real rewinddir, February 1992
  11.  * made POSIX conforming, February 1992
  12.  * added Win32 support, December 1997
  13.  */
  14.  
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include <errno.h>
  23.  
  24. #include <dirent.h>
  25.  
  26.  
  27. #define MAGIC    0x4711
  28.  
  29. #if !defined(TRUE) && !defined(FALSE)
  30. #define TRUE    1
  31. #define FALSE   0
  32. #endif
  33.  
  34. #if defined(__OS2__) && !defined(OS2)
  35. #define OS2
  36. #endif
  37.  
  38. #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
  39. #define WIN32
  40. #endif
  41.  
  42. #if defined(__MINGW32__) && !defined(__32BIT__)
  43. #define __32BIT__
  44. #endif
  45.  
  46.  
  47. #if defined(OS2) || defined(WIN32)
  48.  
  49. #ifndef __32BIT__
  50. #define far     _far
  51. #define near    _near
  52. #define pascal  _pascal
  53. #define cdecl   _cdecl
  54. #endif
  55.  
  56. #ifdef OS2
  57. #define INCL_NOPM
  58. #define INCL_DOS
  59. #define INCL_DOSERRORS
  60. #include <os2.h>
  61. #else /* !OS2 */
  62. #define WIN32_LEAN_AND_MEAN
  63. #include <windows.h>
  64. #endif /* OS2 */
  65.  
  66. #ifdef __32BIT__
  67.  
  68. #define ALLFILES "*"
  69.  
  70. #ifdef __EMX__
  71. #include <emx/syscalls.h>
  72. static struct _find find;
  73. #define achName name
  74. #define _FindFirst(p, pd, a, pf, sf, pc)   __findfirst(p, a, pf)
  75. #define _FindNext(d, pf, sf, pc)           __findnext(pf)
  76. #define _FindClose(d)
  77. #else /* !__EMX__ */
  78.  
  79. #ifdef OS2
  80. static HDIR hdir;
  81. static ULONG count;
  82. static FILEFINDBUF3 find;
  83. #define _FindFirst(p1, p2, p3, p4, p5, p6) DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
  84. #define _FindNext(d, pf, sf, pc)           DosFindNext(d, pf, sf, pc)
  85. #define _FindClose(d)                      DosFindClose(d)
  86. #else /* !OS2 */
  87. static HANDLE hdir;
  88. static WIN32_FIND_DATA find;
  89. #define achName cFileName
  90. #define _FindFirst(p1, p2, p3, p4, p5, p6) (*p2 = FindFirstFile(p1, p4), 0)
  91. #define _FindNext(d, pf, sf, pc)           !FindNextFile(d, pf)
  92. #define _FindClose(d)                      FindClose(d)
  93. #endif /* OS2 */
  94.  
  95. #endif /* __EMX__ */
  96.  
  97. #ifndef ENOTDIR
  98. #define ENOTDIR EINVAL
  99. #endif
  100.  
  101. #ifdef __IBMC__
  102. #define S_IFMT 0xF000
  103. #endif
  104.  
  105. #else /* !__32BIT__ */
  106.  
  107. #define ALLFILES (_osmode == DOS_MODE ? "*.*" : "*")
  108.  
  109. static HDIR hdir;
  110. static USHORT count;
  111. static FILEFINDBUF find;
  112. #define _FindFirst(p1, p2, p3, p4, p5, p6) DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
  113. #define _FindNext(d, pf, sf, pc)           DosFindNext(d, pf, sf, pc)
  114. #define _FindClose(d)                      DosFindClose(d)
  115.  
  116. #endif /* __32BIT__ */
  117.  
  118. #else /* !OS2 && !WIN32 */
  119.  
  120. #define ALLFILES "*.*"
  121.  
  122. #include <dos.h>
  123.  
  124. #ifdef __TURBOC__
  125. #include <dir.h>
  126. static struct ffblk find;
  127. #define achName ff_name
  128. #define _FindFirst(p, pd, a, pf, sf, pc)   findfirst(p, pf, a)
  129. #define _FindNext(d, pf, sf, pc)           findnext(pf)
  130. #define _FindClose(d)
  131. #else /* !__TURBOC__ */
  132. static struct find_t find;
  133. #define achName name
  134. #define _FindFirst(p, pd, a, pf, sf, pc)   _dos_findfirst(p, a, pf)
  135. #define _FindNext(d, pf, sf, pc)           _dos_findnext(pf)
  136. #define _FindClose(d)
  137. #endif /* !__TURBOC__ */
  138.  
  139. #endif /* OS2 || WIN32 */
  140.  
  141.  
  142. #ifndef _A_DIR
  143. #define _A_HIDDEN   0x02
  144. #define _A_DIR      0x10
  145. #endif
  146.  
  147. int attributes = _A_DIR | _A_HIDDEN;
  148.  
  149. static int getdirent(char *);
  150. static int savedirent(DIR *);
  151. static void free_dircontents(struct d_dircontents *);
  152.  
  153.  
  154. DIR *opendir(const char *name)
  155. {
  156.   struct stat statb;
  157.   DIR *dirp;
  158.   char nbuf[_POSIX_PATH_MAX + 1];
  159.   char c;
  160.   int len;
  161.  
  162.   if ( name == NULL || *name == '\0' )
  163.   {
  164.     errno = ENOENT;
  165.     return NULL;
  166.   }
  167.  
  168.   if ( (dirp = malloc(sizeof(DIR))) == NULL )
  169.   {
  170.     errno = ENOMEM;
  171.     return NULL;
  172.   }
  173.  
  174.   strcpy(nbuf, name);
  175.   len = strlen(nbuf);
  176.  
  177.   if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1) )
  178.   {
  179.     nbuf[len - 1] = '\0';
  180.     len--;
  181.  
  182.     if ( nbuf[len - 1] == ':' )
  183.     {
  184.       strcpy(nbuf + len, "\\.");
  185.       len += 2;
  186.     }
  187.   }
  188.   else
  189.     if ( nbuf[len - 1] == ':' )
  190.     {
  191.       strcpy(nbuf + len, ".");
  192.       len++;
  193.     }
  194.  
  195.   if ( stat(nbuf, &statb) == 0 )
  196.   {
  197.     if ( (statb.st_mode & S_IFMT) != S_IFDIR )
  198.     {
  199.       free(dirp);
  200.       errno = ENOTDIR;
  201.       return NULL;
  202.     }
  203.  
  204.     if ( nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.') )
  205.       strcpy(nbuf + len - 1, ALLFILES);
  206.     else
  207.       if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1) )
  208.     strcpy(nbuf + len, ALLFILES);
  209.       else
  210.     strcat(strcpy(nbuf + len, "\\"), ALLFILES);
  211.     
  212.     _fullpath(dirp -> d_dd_name, nbuf, _POSIX_PATH_MAX);
  213.   }
  214.   else /* pattern, can't stat it, we hope it works ... */
  215.     strcpy(dirp -> d_dd_name, nbuf);
  216.  
  217.   dirp -> d_dd_id  = MAGIC;
  218.   dirp -> d_dd_loc = 0;
  219.   dirp -> d_dd_contents = NULL;
  220.  
  221.   if ( getdirent(dirp -> d_dd_name) )
  222.     do
  223.     {
  224.       if ( !savedirent(dirp) )
  225.       {
  226.     free_dircontents(dirp -> d_dd_contents);
  227.     free(dirp);
  228.     errno = ENOMEM;
  229.     return NULL;
  230.       }
  231.     }
  232.     while ( getdirent(NULL) );
  233.  
  234.   dirp -> d_dd_cp = dirp -> d_dd_contents;
  235.  
  236.   return dirp;
  237. }
  238.  
  239.  
  240. int closedir(DIR *dirp)
  241. {
  242.   if ( dirp == NULL || dirp -> d_dd_id != MAGIC )
  243.   {
  244.     errno = EBADF;
  245.     return -1;
  246.   }
  247.  
  248.   free_dircontents(dirp -> d_dd_contents);
  249.   free(dirp);
  250.  
  251.   return 0;
  252. }
  253.  
  254.  
  255. struct dirent *readdir(DIR *dirp)
  256. {
  257.   static struct dirent dp;
  258.  
  259.   if ( dirp == NULL || dirp -> d_dd_id != MAGIC )
  260.   {
  261.     errno = EBADF;
  262.     return NULL;
  263.   }
  264.  
  265.   if ( dirp -> d_dd_cp == NULL )
  266.     return NULL;
  267.  
  268.   dp.d_namlen = dp.d_reclen =
  269.     strlen(strcpy(dp.d_name, dirp -> d_dd_cp -> d_dc_entry));
  270.  
  271.   dp.d_ino = 0;
  272.  
  273.   dp.d_size = dirp -> d_dd_cp -> d_dc_size;
  274.   dp.d_mode = dirp -> d_dd_cp -> d_dc_mode;
  275.   dp.d_time = dirp -> d_dd_cp -> d_dc_time;
  276.   dp.d_date = dirp -> d_dd_cp -> d_dc_date;
  277.  
  278.   dirp -> d_dd_cp = dirp -> d_dd_cp -> d_dc_next;
  279.   dirp -> d_dd_loc++;
  280.  
  281.   return &dp;
  282. }
  283.  
  284.  
  285. void seekdir(DIR *dirp, long off)
  286. {
  287.   long i = off;
  288.   struct d_dircontents *dp;
  289.  
  290.   if ( dirp == NULL || dirp -> d_dd_id != MAGIC )
  291.   {
  292.     errno = EBADF;
  293.     return;
  294.   }
  295.  
  296.   if ( off >= 0 )
  297.   {
  298.     for ( dp = dirp -> d_dd_contents; (--i >= 0) && dp; dp = dp -> d_dc_next );
  299.  
  300.     dirp -> d_dd_loc = off - (i + 1);
  301.     dirp -> d_dd_cp = dp;
  302.   }
  303. }
  304.  
  305.  
  306. long telldir(DIR *dirp)
  307. {
  308.   if ( dirp == NULL || dirp -> d_dd_id != MAGIC )
  309.   {
  310.     errno = EBADF;
  311.     return -1;
  312.   }
  313.  
  314.   return dirp -> d_dd_loc;
  315. }
  316.  
  317.  
  318. void rewinddir(DIR *dirp)
  319. {
  320.   if ( dirp == NULL || dirp -> d_dd_id != MAGIC )
  321.   {
  322.     errno = EBADF;
  323.     return;
  324.   }
  325.  
  326.   free_dircontents(dirp -> d_dd_contents);
  327.   dirp -> d_dd_loc = 0;
  328.   dirp -> d_dd_contents = NULL;
  329.  
  330.   if ( getdirent(dirp -> d_dd_name) )
  331.     do
  332.     {
  333.       if ( !savedirent(dirp) )
  334.       {
  335.     free_dircontents(dirp -> d_dd_contents);
  336.     dirp -> d_dd_contents = NULL;
  337.     errno = ENOMEM;
  338.     break;
  339.       }
  340.     }
  341.     while ( getdirent(NULL) );
  342.  
  343.   dirp -> d_dd_cp = dirp -> d_dd_contents;
  344. }
  345.  
  346.  
  347. static void free_dircontents(struct d_dircontents *dp)
  348. {
  349.   struct d_dircontents *odp;
  350.  
  351.   while (dp)
  352.   {
  353.     if (dp -> d_dc_entry)
  354.       free(dp -> d_dc_entry);
  355.  
  356.     odp = dp;
  357.     dp = odp -> d_dc_next;
  358.     free(odp);
  359.   }
  360. }
  361.  
  362.  
  363. int savedirent(DIR *dirp)
  364. {
  365.   struct d_dircontents *dp;
  366.  
  367.   if ( (dp = malloc(sizeof(struct d_dircontents))) == NULL ||
  368.        (dp -> d_dc_entry = malloc(strlen(find.achName) + 1)) == NULL )
  369.   {
  370.     if ( dp )
  371.       free(dp);
  372.     return FALSE;
  373.   }
  374.  
  375.   if ( dirp -> d_dd_contents )
  376.   {
  377.     dirp -> d_dd_cp -> d_dc_next = dp;
  378.     dirp -> d_dd_cp = dirp -> d_dd_cp -> d_dc_next;
  379.   }
  380.   else
  381.     dirp -> d_dd_contents = dirp -> d_dd_cp = dp;
  382.  
  383.   dp -> d_dc_next = NULL;
  384.   strcpy(dp -> d_dc_entry, find.achName);
  385.  
  386. #ifdef __EMX__
  387.   dp -> d_dc_size = ((unsigned long) find.size_hi << 16) + find.size_lo;
  388.   dp -> d_dc_mode = find.attr;
  389.   dp -> d_dc_time = *(unsigned *) &(find.time);
  390.   dp -> d_dc_date = *(unsigned *) &(find.date);
  391. #else /* !__EMX__ */
  392. #ifdef OS2
  393.   dp -> d_dc_size = find.cbFile;
  394.   dp -> d_dc_mode = find.attrFile;
  395.   dp -> d_dc_time = *(unsigned *) &(find.ftimeLastWrite);
  396.   dp -> d_dc_date = *(unsigned *) &(find.fdateLastWrite);
  397. #else /* !OS2 */
  398. #ifdef WIN32
  399.   dp -> d_dc_size = find.nFileSizeLow; /* only up to 4GB */
  400.   dp -> d_dc_mode = find.dwFileAttributes;
  401.   FileTimeToDosDateTime(&(find.ftLastWriteTime), 
  402.             (LPWORD) &(dp -> d_dc_time), 
  403.             (LPWORD) &(dp -> d_dc_date));
  404. #else /* !WIN32 */
  405.   dp -> d_dc_size = find.size;
  406.   dp -> d_dc_mode = find.attrib;
  407.   dp -> d_dc_time = find.wr_time;
  408.   dp -> d_dc_date = find.wr_date;
  409. #endif /* WIN32 */
  410. #endif /* OS2 */
  411. #endif /* __EMX__ */
  412.  
  413.   return TRUE;
  414. }
  415.  
  416.  
  417. int getdirent(char *dir)
  418. {
  419.   int done;
  420.   static int lower = TRUE;
  421.  
  422.   if (dir != NULL)
  423.   {                       /* get first entry */
  424.     lower = IsFileSystemDumb(dir);
  425.  
  426. #if !defined(__EMX__) && defined(OS2)
  427.     hdir = HDIR_CREATE;
  428.     count = 1;
  429. #endif
  430.  
  431.     done = _FindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
  432.   }
  433.   else                       /* get next entry */
  434.     done = _FindNext(hdir, &find, sizeof(find), &count);
  435.  
  436.   if (done == 0)
  437.   {
  438.     if ( lower )
  439.       strlwr(find.achName);
  440.     return TRUE;
  441.   }
  442.   else
  443.   {
  444.     _FindClose(hdir);
  445.     return FALSE;
  446.   }
  447. }
  448.  
  449.  
  450. int IsFileNameValid(char *name)
  451. {
  452. #ifdef OS2
  453.   HFILE hf;
  454. #ifdef __32BIT__
  455.   ULONG uAction;
  456. #else
  457.   USHORT uAction;
  458. #endif
  459.  
  460.   switch( DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
  461.                   OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0) )
  462.   {
  463.   case ERROR_INVALID_NAME:
  464.   case ERROR_FILENAME_EXCED_RANGE:
  465.   /* case ERROR_PATH_NOT_FOUND: */
  466.     return FALSE;
  467.   case NO_ERROR:
  468.     DosClose(hf);
  469.   default:
  470.     return TRUE;
  471.   }
  472. #else
  473.   return TRUE;
  474. #endif
  475. }
  476.  
  477.  
  478. int IsFileSystemDumb(char *dir)
  479. {                         
  480. #ifdef OS2
  481.   char drive[5], path[256], name[256], ext[8];
  482.   
  483.   _splitpath(dir, drive, path, name, ext);
  484.   strcpy(name, drive);
  485.   strcat(name, path);
  486.   strcat(name, "DUMB.TEST.NAME");
  487.   
  488.   return !IsFileNameValid(name);
  489. #else
  490.   return FALSE;
  491. #endif
  492. }
  493.  
  494.  
  495. #ifdef TEST
  496. int main(void)
  497. {
  498.   DIR *dirp = opendir(".");
  499.   struct dirent *dp;
  500.  
  501.   while ( (dp = readdir(dirp)) != NULL )
  502.     printf(">%s<\n", dp -> d_name);
  503.  
  504.   return 0;
  505. }
  506. #endif
  507.