home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / batch / cutils10.arj / RMTREE.C < prev    next >
C/C++ Source or Header  |  1991-10-17  |  16KB  |  500 lines

  1. /*+M, RmTree.c */
  2. /************************************************************************/
  3. /************************************************************************/
  4. /*                                    */
  5. /*    COPYRIGHT (C) G. KLYNE, 1991.    All rights reserved.        */
  6. /*                                    */
  7. /*    Permission to freely distribute this software, or use it    */
  8. /*    for any purpose, is granted provided that no charge is        */
  9. /*    levied for its distribution and this notice is retained        */
  10. /*    in all copies of the source code.                */
  11. /*                                    */
  12. /************************************************************************/
  13. /************************************************************************/
  14. /*                                    */
  15. /*                                    */
  16. /*    Module name        : RmTree                */
  17. /*    File name        : RmTree.c                */
  18. /*                                    */
  19. /*                                    */
  20. /*  AMENDMENT RECORD                            */
  21. /*  ================                            */
  22. /*                                    */
  23. /*  1.    V01.0A    19-Feb-1991    Graham Klyne                */
  24. /*    Program initially created.                    */
  25. /*                                    */
  26. /*                                    */
  27. /*  PROGRAM FUNCTION                            */
  28. /*  ================                            */
  29. /*                                    */
  30. /*    This program is a simple DOS utility which removes all        */
  31. /*    empty subdirectories descending from a given directory.        */
  32. /*                                    */
  33. /*    The exit code is:                        */
  34. /*      0    No directory and/or file specified.            */
  35. /*      1    All subdirectories deleted.                */
  36. /*      4    Could not delete all subdirectories in directory.    */
  37. /*      6    Error in supplied path name.                */
  38. /*                                    */
  39. /*    Any filename and extension (as opposed to directory name) on    */
  40. /*    the command line is ignored:  all subdirectories in the        */
  41. /*    indicated directory are deleted (if possible).            */
  42. /*                                    */
  43. /*                                    */
  44. /************************************************************************/
  45. /************************************************************************/
  46. /*-M*/
  47.  
  48.  
  49. /************************************************************************/
  50. /*    External declarations used                    */
  51. /************************************************************************/
  52.  
  53. #define    LINT_ARGS
  54.  
  55. #include <ctype.h>
  56. #include <string.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <direct.h>
  60. #include <io.h>
  61. #include <dos.h>
  62.  
  63. /************************************************************************/
  64. /*    External entry points declared in this module            */
  65. /************************************************************************/
  66.  
  67.     /*    No external entry points  */
  68.  
  69.  
  70. /************************************************************************/
  71. /*    Local definitions                        */
  72. /************************************************************************/
  73.  
  74. #define FALSE 0
  75. #define TRUE  1
  76.  
  77. /************************************************************************/
  78. /*    Local type declarations                        */
  79. /************************************************************************/
  80.  
  81. typedef struct FileDetail_str
  82.     {
  83.     char Context[21] ;    /* Search context for "FindNextFile"    */
  84.     char Attributes ;    /* File attributes            */
  85.     short int Time ;    /* Time file written HHHHHMMMMMMSSSSS    */
  86.     short int Date ;    /* Date file written YYYYYYYMMMMDDDDD    */
  87.     long int Size ;        /* File size in bytes            */
  88.     char Name[13] ;        /* File name and extension        */
  89.     }
  90.     FileDetail, *FileDetail_ptr ;
  91.  
  92. /************************************************************************/
  93. /*    Local variable declarations                    */
  94. /************************************************************************/
  95.  
  96.     /*    No local variables  */
  97.  
  98.  
  99. /*+F*/
  100. /************************************************************************/
  101. /*    *-FindFirstFile,    Find first file matching given specification    */
  102. /************************************************************************/
  103. /*
  104. /*    This function finds the first file matching a given specification.
  105. /*
  106. /*  PARAMETERS
  107. /*  ----------
  108. /*    ReqPath        points to a string containing the ambiguous file
  109. /*            name (including drive and path) to be matched.
  110. /*    ReqAttr        indicates the types of files to be located:
  111. /*              0x01    Include read-only files.
  112. /*              0x02    Include hidden files.
  113. /*              0x04    Include system files.
  114. /*              0x08    Include volume identifier file.
  115. /*              0x10    Include directory files.
  116. /*            Any combination of the above options may be
  117. /*            specified.
  118. /*    FilAttr        points to a "FileDetail" structure which receives
  119. /*            additional information about the file, and other data
  120. /*            required by subsequent calls of "FindNextFile".
  121. /*    FilSize        is the size of the supplied "FilBuff" buffer.
  122. /*    FilBuff        points to a buffer which receives the filename
  123. /*            (including drive and path) as a NULL-terminated
  124. /*            string.
  125. /*
  126. /*  RESULT
  127. /*  ------
  128. /*    The result returned is FALSE if no file is found, otherwise TRUE.
  129. /*
  130. /*  NOTES
  131. /*  -----
  132. /*    This routine assumes that the current DTA and the supplied file
  133. /*    details structure both lie in the default data segment.
  134. /*
  135. /*    If the search is to include directories, the special files "."
  136. /*    and ".." may be returned.
  137. /*
  138. /*-F*/
  139.  
  140. int FindFirstFile
  141.       ( const char *ReqPath, int ReqAttr,
  142.     FileDetail *FilAttr,
  143.     int FilSize, char *FilBuff )
  144.     {
  145.     union REGS InpRegs, OutRegs ;
  146.     int SaveDTA ;
  147.     int Status ;
  148.     int Length ;
  149.     int i ;
  150.  
  151.     /*--------------------------------------------------------------*/
  152.     /*    Copy file path to result buffer                */
  153.     /*--------------------------------------------------------------*/
  154.  
  155.     Status = FALSE ;
  156.     Length = strlen( ReqPath ) ;
  157.     while ( ( Length > 0 ) &&
  158.         ( ReqPath[Length-1] != '\\' ) &&
  159.         ( ReqPath[Length-1] != '/'  ) ) Length-- ;
  160.     if ( Length+13 > FilSize )
  161.         {
  162.         printf( "RmTree: supplied path '%s' is too long\n", ReqPath ) ;
  163.         exit( 6 ) ;
  164.         }
  165.     strncpy( FilBuff, ReqPath, FilSize ) ;
  166.     FilBuff[Length] = '\0' ;
  167.  
  168.     /*--------------------------------------------------------------*/
  169.     /*    Save current DTA, and set new value            */
  170.     /*--------------------------------------------------------------*/
  171.  
  172.     InpRegs.x.ax = 0x2F00 ;
  173.     intdos( &InpRegs, &OutRegs ) ;
  174.     SaveDTA = OutRegs.x.bx ;
  175.  
  176.     InpRegs.x.ax = 0x1A00 ;
  177.     InpRegs.x.dx = FP_OFF( FilAttr ) ;
  178.     intdos( &InpRegs, &OutRegs ) ;
  179.  
  180.     /*--------------------------------------------------------------*/
  181.     /*    Find file                        */
  182.     /*--------------------------------------------------------------*/
  183.  
  184.     InpRegs.x.ax = 0x4E00 ;
  185.     InpRegs.x.cx = ReqAttr ;
  186.     InpRegs.x.dx = FP_OFF( ReqPath ) ;
  187.     intdos( &InpRegs, &OutRegs ) ;
  188.     if ( OutRegs.x.cflag == 0 ) Status = TRUE ;
  189.  
  190.     /*--------------------------------------------------------------*/
  191.     /*    Restore original DTA                    */
  192.     /*--------------------------------------------------------------*/
  193.  
  194.     InpRegs.x.ax = 0x1A00 ;
  195.     InpRegs.x.dx = SaveDTA ;
  196.     intdos( &InpRegs, &OutRegs ) ;
  197.  
  198.     /*--------------------------------------------------------------*/
  199.     /*    Sort out result                        */
  200.     /*--------------------------------------------------------------*/
  201.  
  202.     if ( Status )
  203.         {
  204.         i = 0 ;
  205.         while ( ( FilAttr->Name[i] != '\0' ) && ( i < 12 ) )
  206.         {
  207.         FilBuff[Length++] = FilAttr->Name[i++] ;
  208.         }
  209.         FilBuff[Length] = '\0' ;
  210.         }
  211.  
  212.     return Status ;
  213.     } ;    // End of function FindFirstFile
  214.  
  215.  
  216. /*+F*/
  217. /************************************************************************/
  218. /*    *-FindNextFile,    Find next file matching given specification    */
  219. /************************************************************************/
  220. /*
  221. /*    This function finds the next file matching a given specification,
  222. /*    following a previous call of "FindFirstFile" and possible calls
  223. /*    of this function.
  224. /*
  225. /*    Attributes for the required files are carried over from the
  226. /*    original call of "FindFirstFile".
  227. /*
  228. /*  PARAMETERS
  229. /*  ----------
  230. /*    ReqPath        points to a string containing the ambiguous file
  231. /*            name (including drive and path) to be matched.
  232. /*    FilAttr        points to a "FileDetail" structure which receives
  233. /*            additional information about the file, and other data
  234. /*            required by subsequent calls of "FindNextFile".
  235. /*    FilSize        is the size of the supplied "FilBuff" buffer.
  236. /*    FilBuff        points to a buffer which receives the filename
  237. /*            (including drive and path) as a NULL-terminated
  238. /*            string.
  239. /*
  240. /*  RESULT
  241. /*  ------
  242. /*    The result returned is FALSE if no file is found, otherwise TRUE.
  243. /*
  244. /*  NOTE
  245. /*  ----
  246. /*    This routine assumes that the current DTA and the supplied file
  247. /*    details structure both lie in the default data segment.
  248. /*
  249. /*-F*/
  250.  
  251. int FindNextFile
  252.       ( const char *ReqPath,
  253.     FileDetail *FilAttr,
  254.     int FilSize, char *FilBuff )
  255.     {
  256.     union REGS InpRegs, OutRegs ;
  257.     int SaveDTA ;
  258.     int Status ;
  259.     int Length ;
  260.     int i ;
  261.  
  262.     /*--------------------------------------------------------------*/
  263.     /*    Copy file path to result buffer                */
  264.     /*--------------------------------------------------------------*/
  265.  
  266.     Status = FALSE ;
  267.     Length = strlen( ReqPath ) ;
  268.     while ( ( Length > 0 ) &&
  269.         ( ReqPath[Length-1] != '\\' ) &&
  270.         ( ReqPath[Length-1] != '/'  ) ) Length-- ;
  271.     if ( Length+13 > FilSize )
  272.         {
  273.         printf( "RmTree: supplied path '%s' is too long\n", ReqPath ) ;
  274.         exit( 6 ) ;
  275.         }
  276.     strncpy( FilBuff, ReqPath, FilSize ) ;
  277.     FilBuff[Length] = '\0' ;
  278.  
  279.     /*--------------------------------------------------------------*/
  280.     /*    Save current DTA, and set new value            */
  281.     /*--------------------------------------------------------------*/
  282.  
  283.     InpRegs.x.ax = 0x2F00 ;
  284.     intdos( &InpRegs, &OutRegs ) ;
  285.     SaveDTA = OutRegs.x.bx ;
  286.  
  287.     InpRegs.x.ax = 0x1A00 ;
  288.     InpRegs.x.dx = FP_OFF( FilAttr ) ;
  289.     intdos( &InpRegs, &OutRegs ) ;
  290.  
  291.     /*--------------------------------------------------------------*/
  292.     /*    Find file                        */
  293.     /*--------------------------------------------------------------*/
  294.  
  295.     InpRegs.x.ax = 0x4F00 ;
  296.     intdos( &InpRegs, &OutRegs ) ;
  297.     if ( OutRegs.x.cflag == 0 ) Status = TRUE ;
  298.  
  299.     /*--------------------------------------------------------------*/
  300.     /*    Restore original DTA                    */
  301.     /*--------------------------------------------------------------*/
  302.  
  303.     InpRegs.x.ax = 0x1A00 ;
  304.     InpRegs.x.dx = SaveDTA ;
  305.     intdos( &InpRegs, &OutRegs ) ;
  306.  
  307.     /*--------------------------------------------------------------*/
  308.     /*    Sort out result                        */
  309.     /*--------------------------------------------------------------*/
  310.  
  311.     if ( Status )
  312.         {
  313.         i = 0 ;
  314.         while ( ( FilAttr->Name[i] != '\0' ) && ( i < 12 ) )
  315.         {
  316.         FilBuff[Length++] = FilAttr->Name[i++] ;
  317.         }
  318.         FilBuff[Length] = '\0' ;
  319.         }
  320.  
  321.     return Status ;
  322.     } ;    // End of function FindNextFile
  323.  
  324.  
  325. /*+F*/
  326. /************************************************************************/
  327. /*    *-RemoveTree,    Remove subtree of empty directories        */
  328. /************************************************************************/
  329. /*
  330. /*    This function removes all empty directories descending from the
  331. /*    specified directory.
  332. /*
  333. /*  PARAMETERS
  334. /*  ----------
  335. /*    PathSiz        is the size of the supplied opathname buffer.
  336. /*    PathBuf        points to a buffer containing a pathname whose
  337. /*            directory is the one from which all empty
  338. /*            subdirectories are to be removed.  The final
  339. /*            directory in the path must be terminated by
  340. /*            a '/' or '\' character.
  341. /*
  342. /*  RESULT
  343. /*  ------
  344. /*    The result returned is:
  345. /*      1    All subdirectories deleted.
  346. /*      4    Could not delete all subdirectories in directory.
  347. /*      6    Error in supplied path name (too long).
  348. /*
  349. /*-F*/
  350.  
  351. int RemoveTree( int PathSiz, char *PathBuf )
  352.     {
  353.     int Status ;
  354.     int More ;
  355.     char SubPath[144] ;
  356.     FileDetail FilAttr ;
  357.     int l ;
  358.     int r ;
  359.  
  360.     /*--------------------------------------------------------------*/
  361.     /*    Force filename in path to '*.*'                */
  362.     /*--------------------------------------------------------------*/
  363.  
  364.     l = strlen( PathBuf ) ;
  365.     while ( ( l > 0 ) &&
  366.         ( PathBuf[l-1] != '\\' ) &&
  367.         ( PathBuf[l-1] != '/' ) ) l-- ;
  368.     if ( l+14 >= PathSiz )
  369.         {
  370.         printf( "RmTree: path '%s' is too long\n", PathBuf ) ;
  371.         return 6 ;
  372.         }
  373.     PathBuf[l++] = '*' ;
  374.     PathBuf[l++] = '.' ;
  375.     PathBuf[l++] = '*' ;
  376.     PathBuf[l++] = '\0' ;
  377.  
  378. #if 0
  379.     printf( "RemoveTree: '%s'\n", PathBuf ) ;
  380. #endif
  381.  
  382.     /*--------------------------------------------------------------*/
  383.     /*    Delete empty subdirectories in specified directory    */
  384.     /*--------------------------------------------------------------*/
  385.  
  386.     Status = 1 ;
  387.     More   = FindFirstFile( PathBuf, 0x10, &FilAttr, 143, SubPath ) ;
  388.     while ( More )
  389.         {
  390. #if 0
  391.         printf( "Find attr 0x%02X, file '%s'\n",
  392.             FilAttr.Attributes, SubPath ) ;
  393. #endif
  394.         if ( ( FilAttr.Attributes & 0x10 ) &&
  395.          ( FilAttr.Name[0] != '.' ) )
  396.         {
  397.         l = strlen( SubPath ) ;
  398.         SubPath[l++] = '\\' ;
  399.         SubPath[l]   = '\0' ;
  400.  
  401.         r = RemoveTree( 144, SubPath ) ;
  402.         if ( r == 4 ) Status = 4 ;
  403.         else
  404.         if ( r != 1 ) return r ;
  405.  
  406.         SubPath[l-1] = '\0' ;
  407.         r = rmdir( SubPath ) ;
  408.         if ( r == 0 )
  409.             {
  410.             printf( "RmTree: Removed directory '%s'\n", SubPath ) ;
  411.             }
  412.         else
  413.             {
  414.             printf( "RmTree: Failed to remove directory '%s'\n",
  415.                 SubPath ) ;
  416.             Status = 4 ;
  417.             }
  418.         }
  419.         More = FindNextFile( PathBuf, &FilAttr, 143, SubPath ) ;
  420.         }
  421.  
  422.     return Status ;
  423.     } ;    /* End of procedure RemoveTree */
  424.  
  425.  
  426. /*+T*/
  427. /************************************************************************/
  428. /*    *-main,        Main Program                    */
  429. /************************************************************************/
  430. /*
  431. /*    This program deletes all empty subdirectories descending from the
  432. /*    directory indicated by a specified pathname.
  433. /*
  434. /*-T*/
  435.  
  436. void main( int argc, char *(argv[]), char *(envp[]) )
  437.     {
  438.     int Status ;
  439.     char FilPath[132] ;
  440.     int l ;
  441.  
  442.     /*--------------------------------------------------------------*/
  443.     /*    Entry point here                    */
  444.     /*--------------------------------------------------------------*/
  445.  
  446.     Status = 0 ;
  447.  
  448.     if ( argc < 2 )
  449.         {
  450.         printf( "Usage:  RmTree path\n"
  451.         "               Remove all empty subdirectories descending from\n"
  452.         "               the indicated directory.  Any filename specified\n"
  453.         "               in 'path' is ignored.\n" ) ;
  454.         printf( "\n"
  455.         "Exit status:   0: no file or directory specified.\n"
  456.         "               1: all subdirectories deleted.\n"
  457.         "               4: failed to delete all subdirectories.\n"
  458.         "               6: error in supplied path.\n" ) ;
  459.         printf( "\n"
  460.         "Copyright (C) 1991 Graham Klyne.  All rights reserved.\n" ) ;
  461.         exit( 0 ) ;
  462.         }
  463.  
  464.     /*--------------------------------------------------------------*/
  465.     /*    Copy path to local buffer                */
  466.     /*--------------------------------------------------------------*/
  467.  
  468.     l = strlen( argv[1] ) ;
  469.     if ( l >= 132 )
  470.         {
  471.         printf( "RmTree: supplied path '%s' is too long\n", argv[1] ) ;
  472.         exit( 6 ) ;
  473.         }
  474.     strcpy( FilPath, argv[1] ) ;
  475.  
  476.     /*--------------------------------------------------------------*/
  477.     /*    Delete subdirectories in specified directory        */
  478.     /*--------------------------------------------------------------*/
  479.  
  480.     Status = RemoveTree( 132, FilPath ) ;
  481.     if ( Status == 1 )
  482.         printf( "RmTree: All subdirectories removed\n" ) ;
  483.     else
  484.     if ( Status == 4 )
  485.         printf( "RmTree: Some subdirectories removed\n" ) ;
  486.     else
  487.         printf( "RmTree: Error with path '%s'\n", FilPath ) ;
  488.  
  489.     /*--------------------------------------------------------------*/
  490.     /*    Exit                            */
  491.     /*--------------------------------------------------------------*/
  492.  
  493.     exit( Status ) ;
  494.  
  495.     } ;    /* End of procedure main */
  496.  
  497. /************************************************************************/
  498. /*    End of module RmTree                        */
  499. /************************************************************************/
  500.