home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dirutl / trunk120.arc / TRUNK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-21  |  12.7 KB  |  406 lines

  1. /***************************************************************************/
  2. /***************************************************************************/
  3. /** QuickC source for TRUNK                                               **/
  4. /** command line--> QCL /c /AS /Gs /Ox TRUNK.C                            **/
  5. /**             --> LINK TRUNK.OBJ,TRUNK.EXE,,c:...\SLIBCE.LIB /ST:0x1000 **/
  6. /***************************************************************************/
  7. /***************************************************************************/
  8. /**
  9. *** TRUNK -- a replacement for the MS-DOS 'TREE' command.  TREE allows only
  10. *** one option ('/f'--similar to the one implemented in TRUNK), and its output
  11. *** is verbose and completely unsuited for passing to other programs.  TRUNK
  12. *** is fully redirectable using MS-DOS redirection and pipes.
  13. ***
  14. *** Command line option flags are evaluated in left-to-right order.
  15. *** Flags may conflict with each other, and the flag to the right takes
  16. *** precedence--e.g. the command line 'TRUNK /f /o' will print only a
  17. *** summary, no file names.
  18. ***
  19. *** One significant departure from DOS is that TRUNK considers the root to be
  20. *** a directory like any other when summarizing directory structure (obeying
  21. *** the /s or /o flag).  CHKDSK, on the other hand, reports the number of
  22. *** *subdirectories* and leaves the existence of the root directory implied.
  23. *** This difference (more semantic than functional) means that when TRUNK is
  24. *** applied to an entire disk, the number of directories reported found will
  25. *** be one greater than the number of subdirectories reported by CHKDSK.
  26. ***
  27. *** Official TRUNK soundtrack:
  28. *** "Fleetwood Mac in Chicago"  Sire: SASH 3175-2 (C) 1975, or
  29. ***                             Blue Horizon: BH 3801 (C) 1969
  30. ***
  31. *** Enjoy.
  32. **/
  33. /***************************************************************************/
  34. /***************************************************************************/
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <dos.h>
  39. #include <errno.h>
  40. #include <string.h>
  41. #include <direct.h>
  42. #include <conio.h>
  43.  
  44. #include "trunk.h"
  45.  
  46. int             dirs_found=0;
  47. int             files_found=0;
  48. unsigned        srch_attrib=_A_NORMAL | _A_RDONLY | _A_SUBDIR;
  49. int             summary=0;
  50. int             print_dirs=1;
  51. int             print_files=0;
  52. int             print_drive=0;
  53. int             print_path=1;
  54. int             force_lower=0;
  55. int             screenfull_pause=0;
  56. int             screen_lines;
  57. int             help=0;
  58. int             info=0;
  59. unsigned        search_drive;
  60. unsigned        home_drive;
  61. char            dflt_match[]="*.*";
  62. char            *match_ptr=dflt_match;
  63.  
  64.  
  65.  
  66. /***************************************************************************/
  67. /***************************************************************************/
  68. /**
  69. *** main
  70. **/
  71. /***************************************************************************/
  72. /***************************************************************************/
  73.  
  74. void main(int argc, char *argv[])
  75.  
  76. {
  77. path    current_dir;
  78. char    *home_cwd_ptr=current_dir;
  79. char    *alt_cwd_ptr=current_dir;
  80. path    search_dir;
  81. char    *search_ptr=search_dir;
  82. int     n;
  83. char    summary_buf[55];
  84.  
  85.  
  86.  
  87. /**
  88. *** Process any command line arguments that are flags.  The last argument
  89. *** is assumed to be the pathname.  Since the pathname is not required, the
  90. *** last argument may be a flag as well.  If the last argument is a flag, it
  91. *** is assumed that there is no pathname.
  92. **/
  93. if (argc > 1) {
  94.     for (n=1; n < argc; n++)    /* argv[0] always == TRUNK */
  95.         {
  96.         if (argv[n][0] == '/')
  97.             switch ( locase(argv[n][1]) ) {
  98.                 case 'y':   srch_attrib |= _A_SYSTEM;
  99.                 case 'h':   srch_attrib |= _A_HIDDEN;
  100.                             break;
  101.                 case 'n':   if (argv[n][2] == 'd')
  102.                                 print_drive=2;
  103.                             if (argv[n][2] == 'p')
  104.                                 print_path=0;
  105.                             break;
  106.                 case 'o':   print_dirs=0;
  107.                             print_files=0;
  108.                 case 's':   summary=1;
  109.                             break;
  110.                 case 'f':   print_dirs=0;
  111.                             print_files=1;
  112.                             break;
  113.                 case 'm':   if (argv[n][2])
  114.                                 match_ptr=&argv[n][2];
  115.                             break;
  116.                 case 'l':   force_lower=1; break;
  117.                 case 'p':   screenfull_pause=atoi(&argv[n][2]);
  118.                             if (screenfull_pause < 1)
  119.                                 screenfull_pause=DEFLT_SCRFULL;
  120.                             screen_lines=0;
  121.                             break;
  122.                 case 'v':   display_line(version);
  123.                             return;
  124.                 case '?':   help=1; break;
  125.                 case '$':   info=1; break;
  126.                 }
  127.         }   /* for (n=1; n < argc-1; n++) */
  128.     }
  129.  
  130. /**
  131. *** If help was requested (through the /? flag or by TRUNK ?), print a help
  132. *** message and quit.  Ditto for TRUNK information (/$).  Both of these
  133. *** options terminate TRUNK before anything interesting happens.
  134. **/
  135. if ( (help) || (argv[1][0] == '?') ) {
  136.     display_strings(help_msg);
  137.     return;
  138.     }
  139. if (info) {
  140.     display_strings(info_msg);
  141.     return;
  142.     }
  143.  
  144. /**
  145. *** If there are command line arguments, then the last one may be the
  146. *** path to search on.  If the last argument (argv[argc-1]) is not a flag,
  147. *** then it is assumed to be the search path.
  148. ***
  149. *** If there is a drive specified in the pathname which is not the current
  150. *** drive, then the current drive is switched to that drive, the current
  151. *** working directory of that drive is retrieved, and the current drive is
  152. *** reset to its original state.
  153. ***
  154. *** If there is no search path in the command line, then the current
  155. *** working directory is used as the search path.
  156. **/
  157.  
  158. /* Get the current working directory for later */
  159. getcwd(home_cwd_ptr, sizeof(path));
  160.  
  161. if ( (argc == 1) || (argv[argc-1][0] == '/') )
  162.     search_ptr=home_cwd_ptr;
  163. else {
  164.     strcpy(search_ptr, argv[argc-1]);
  165.     if ( (search_ptr[0] == home_cwd_ptr[0]) && (search_ptr[1] == ':') )
  166.         search_ptr+=2;
  167.     if (search_ptr[1] != ':')
  168.         get_targetdir(search_ptr, home_cwd_ptr);
  169.     else {
  170.         home_drive=locase(home_cwd_ptr[0])-'a'+1;
  171.         search_drive=locase(search_ptr[0])-'a'+1;
  172.         if(change_drive(search_drive) != 0) {
  173.             puts(sys_errlist[EINVAL]);
  174.             return;
  175.             }
  176.         getcwd(alt_cwd_ptr, sizeof(path));
  177.         if (search_ptr[2] == '\0')
  178.             search_ptr=alt_cwd_ptr;
  179.         get_targetdir(search_ptr, alt_cwd_ptr);
  180.         change_drive(home_drive);
  181.         }
  182.     }
  183.  
  184. /**
  185. *** go for it
  186. **/
  187. if (force_lower)
  188.     strlwr(search_ptr);
  189. if (search_ptr[0])
  190.     delve(search_ptr);
  191. if (summary) {
  192.     summary_buf[0]=' '; summary_buf[1]=' '; summary_buf[2]=' ';
  193.     itoa(dirs_found, &summary_buf[3], 10);
  194.     strcat(&summary_buf[3], " directories found, containing ");
  195.     itoa(files_found, strchr(&summary_buf[3], '\0'), 10);
  196.     strcat(&summary_buf[3], " files");
  197.     display_line(summary_buf);
  198.     }
  199. return;
  200. }
  201.  
  202.  
  203.  
  204. /***************************************************************************/
  205. /***************************************************************************/
  206. /**
  207. *** delve -- function that recursively steps down the directory structure
  208. *** of a disk, either printing directories/files or just watching them
  209. *** go by, according to the command line flags.
  210. **/
  211. /***************************************************************************/
  212. /***************************************************************************/
  213.  
  214. int delve(  char *parent_ptr )
  215.  
  216. {
  217. struct find_t   my_dta;
  218. unsigned int    find_result;
  219. path            current_path;
  220. char            *current_end;
  221.  
  222.  
  223. /**
  224. *** delve is only called on an existing directory, so this here is a valid
  225. *** directory we're in.  If appropriate, print said fact.
  226. **/
  227. ++dirs_found;
  228. if (print_dirs)
  229.     display_line( (print_path)  ?   parent_ptr+print_drive
  230.                                 :   strrchr(parent_ptr,'\\')+1);
  231.  
  232. /**
  233. *** Copy the path passed from above, and stick a backslash at the end of it.
  234. *** current_end ends up pointing to the 1st char after this backslash, which
  235. *** is the place to put file matching mask and the name of the next
  236. *** subdirectory down the chain.
  237. **/
  238. strcpy(current_path, parent_ptr);
  239. current_end=strchr(current_path,'\0');
  240. if ( *(current_end-1) != '\\')
  241.     *current_end++='\\';
  242.  
  243. /**
  244. *** First, find all the files that match the mask pointed to by match_ptr,
  245. *** and print them if appropriate.  If the /m flag has not been used by the
  246. *** user, then *match_ptr == "*.*" and all files in the subdirectory will be
  247. *** found.
  248. **/
  249. strcpy(current_end, match_ptr);
  250. find_result=_dos_findfirst(current_path, srch_attrib & ~_A_SUBDIR, &my_dta);
  251. while (find_result == 0) {
  252.     ++files_found;
  253.     if (print_files) {
  254.         strcpy(current_end, my_dta.name);
  255.         if (force_lower)
  256.             strlwr(current_end);
  257.         display_line( (print_path)  ?   current_path+print_drive
  258.                                     :   current_end);
  259.         }
  260.     find_result=_dos_findnext(&my_dta);
  261.     }
  262.  
  263. /**
  264. *** Now go through the subdirectory looking for other directories.  If a
  265. *** subdirectory is found, call delve on it
  266. **/
  267. strcpy(current_end, dflt_match);
  268. find_result=_dos_findfirst(current_path, srch_attrib, &my_dta);
  269. while (find_result == 0) {
  270.     if ( (my_dta.attrib & _A_SUBDIR) && (my_dta.name[0] != '.') ) {
  271.         strcpy(current_end, my_dta.name);
  272.         if (force_lower)
  273.             strlwr(current_end);
  274.         delve(current_path);
  275.         }
  276.     find_result=_dos_findnext(&my_dta);
  277.     }
  278.  
  279. return(0);
  280. }
  281.  
  282.  
  283.  
  284. /***************************************************************************/
  285. /***************************************************************************/
  286. /**
  287. *** get_targetdir -- TRUNK has to find the target directory in more than
  288. *** one place in the code, so this function consolidates them.  The target
  289. *** directory passed to this function can be relative to the current
  290. *** directory (such as '..'), so we chdir to that directory, ask DOS what the
  291. *** current pathname is, and place that in *target.  Finally we change back
  292. *** to the directroy whence we came.  If the target directory does not exist,
  293. *** *target is set to a null string.
  294. **/
  295. /***************************************************************************/
  296. /***************************************************************************/
  297.  
  298. char *get_targetdir(    char  *target,    /* place to put target pathname */
  299.                         char  *home       /* directory we just came from */
  300.                         )
  301.  
  302. {
  303. if (chdir(target) != 0)
  304.     target[0]='\0';
  305. else {
  306.     getcwd(target, sizeof(path));
  307.     chdir(home);
  308.     }
  309. return(target);
  310. }
  311.  
  312.  
  313.  
  314. /***************************************************************************/
  315. /***************************************************************************/
  316. /**
  317. *** change_drive -- take advantage of some quick-and-dirty method of changing
  318. *** the current logged drive.  _dos_settdrive is void(), so we have to use
  319. *** _dos_getdrive to see if the change actually took place.
  320. **/
  321. /***************************************************************************/
  322. /***************************************************************************/
  323.  
  324. int change_drive( unsigned new_drive )
  325.  
  326. {
  327. unsigned    avail_drives;
  328. unsigned    drive_now;
  329.  
  330.  
  331. _dos_setdrive(new_drive, &avail_drives);
  332. _dos_getdrive(&drive_now);
  333. return( (new_drive == drive_now) ? 0 : -1 );
  334. }
  335.  
  336.  
  337.  
  338. /***************************************************************************/
  339. /***************************************************************************/
  340. /**
  341. *** display_line -- print strings to the screen, pausing every screenful if
  342. *** the /p flag is on.
  343. **/
  344. /***************************************************************************/
  345. /***************************************************************************/
  346.  
  347. void    display_line( char *out_line )
  348.  
  349. {
  350. int     n=0;
  351. char    ch;
  352.  
  353.  
  354. puts(out_line);
  355. ++screen_lines;
  356. if ( (screenfull_pause) && (screenfull_pause == screen_lines) ) {
  357.     while( kbhit() )
  358.         getch();
  359.     while( (ch=" Strike any key to continue==>"[++n]) )
  360.         fputchar(ch);
  361.     while( !kbhit() );
  362.     while( kbhit() )
  363.         getch();
  364.     fputchar('\n');
  365.     screen_lines=0;
  366.     }
  367. return;
  368. }
  369.  
  370.  
  371.  
  372. /***************************************************************************/
  373. /***************************************************************************/
  374. /**
  375. *** display_strings -- use puts to print a series of strings to stdout until
  376. *** a null string is encountered.
  377. **/
  378. /***************************************************************************/
  379. /***************************************************************************/
  380.  
  381. void display_strings( char *msgs[] )
  382. {
  383.  
  384. while ( msgs[0][0] )
  385.     display_line( msgs++[0] );
  386. return;
  387. }
  388.  
  389.  
  390.  
  391. /***************************************************************************/
  392. /***************************************************************************/
  393. /**
  394. *** locase -- convert passed character to lower case.  made this a function
  395. *** to save a few bytes in code space.
  396. **/
  397. /***************************************************************************/
  398. /***************************************************************************/
  399.  
  400. char    locase( char ch )
  401.  
  402. {
  403.  
  404. return( ((ch >= 'A') && (ch <='Z')) ? (ch+32) : ch );
  405. }
  406.