home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / dirutl / alldir.arc / ALLDIR.C
Text File  |  1988-07-27  |  14KB  |  493 lines

  1. /* ALLDIR.C  a program to traverse DOS's tree-structured directory, looking
  2.    for the file(s) specified. They are then displayed on the screen.
  3.    Basically, I got damned tired of DOS not being able to tell me what's
  4.    where.
  5.     The basic traverse from directory to directory portion is a
  6.    very versatile toy around which many useful utilities can (and will,
  7.    I'm sure!) be written. Here's another one of them. I'll do more as time
  8.    and inclination permits, but I'll turn this one loose because I think
  9.    it's useful.
  10.     This is written for MSDOS 2.0 or better, using the LATTICE C Compiler,
  11.    on a Compaq. 7-20-84 jjw   
  12.    ps I know this could be shortened drastically and speeded up by 
  13.    combining some of the modules into larger functions, but this way was
  14.    much easier to write & de-bug modularly and so I left it that way. Also,
  15.    some of the modules might be useful in themselves to build into a
  16.    library. This program differs from most C code I've seen before because
  17.    1.) it does something useful.
  18.    2.) it does not have pointers to pointers to arrays of pointers to functions
  19.        returning pointers. It is easy and straight-forward, at the expense of
  20.        some speed and length.
  21.    3.) it is commented. Not extensively, but fairly well. The hard parts have
  22.        to do with the dirstak, which is not a stack but a queue (dirqueue
  23.        looked too silly to me and d_queue made me think of peanut buster
  24.        parfaits). If puzzled, follow it through but keep the msdos manual
  25.        handy to see what byte is what.
  26.    If you have any questions about this, drop me a note. I frequent almost
  27.    every tech-oriented CPM bulletin board around Chicago, Il. 
  28.    Name is John Welch, or just jjw.
  29.            2397 John Smith Dr. Apt B
  30.            Schaumburg, Il 60194 */
  31.  
  32. #include "dos.h"
  33. #include "stdio.h"
  34.  
  35. main(argc,argv)
  36. int argc;
  37. char *argv[];
  38. {
  39. char look[15],start[100],init_dir[100],drive[2],flag1,stuff[100];
  40. int first,last,temp,temp1,ret;
  41.  
  42. printf("ALLDIR.C Ver 1.00 1-25-85 John J. Welch\n");
  43. printf("(for help, type ALLDIR HELP)\n\n");
  44.  
  45. if (argc == 1)
  46.  {
  47.   /* get the filename to erase */ 
  48.   printf("Filename to find -->");
  49.   scanf("%s",look);
  50.  
  51.   /* get the drive we're going to do the erasing on */
  52.   printf("Enter the drive letter -->");
  53.   scanf("%s",stuff);
  54.   drive[1] = stuff[0];
  55.  
  56.   /* get starting directory */
  57.   printf("Directory to start in (absolute path from root) -->");
  58.   scanf("%s",start);
  59.  
  60.   /* do we want to do all sub-directories, too, or just this one? */
  61.   printf("Traverse all sub-directories under this one -->");
  62.   scanf("%s",stuff);
  63.   if ((stuff[0] == 'y') || (stuff[0] == 'Y'))
  64.    flag1 = 1; /* if they specified Y, set the flag */
  65.   else
  66.    flag1 = 0; /* anything but Y or y means NO */
  67.  
  68.   }
  69. else
  70.  {
  71.   if (argc != 2)
  72.    {
  73. HERE:
  74.     printf("For prompts, just type ALLDIR.\n");
  75.     printf("Command line syntax is ALLDIR [drive:][starting path]file.ext[/y]\n");
  76.     printf("where [drive:] is optional drive,\n");
  77.     printf("  [starting path] is optional path to start at,\n");
  78.     printf("  file.ext is the file name (wildcards ok) to look for,\n");
  79.     printf("  [/y] is optionally if you want to do all sub-directories under the\n");
  80.     printf("  starting directory (default value is no).\n");
  81.     return;
  82.    }
  83.   else
  84.    {
  85.     if ((strcmp(argv[1],"HELP") == 0) || (strcmp(argv[1],"help") == 0))
  86.      goto HERE;
  87.  
  88.     first = 0; /* first character of the command line */
  89.     drive[1] = 255; /* set up to default to current drive */
  90.     flag1 = 0; /* default it to not do sub-dirs */
  91.     if (argv[1][1] == ':') /* if there was a drive specified, pick the letter */
  92.     { /*off and store it someplace */
  93.      drive[1] = argv[1][0];
  94.      first = 2; /* now, the first character in the command line is #2 */
  95.     }
  96.     last = strlen(argv[1]); /* get the length of the command line */
  97.     if (argv[1][last-2] == '/') /* if they used the toggle, set it up */
  98.     {
  99.      if ((argv[1][last-1] == 'y') || (argv[1][last-1] == 'Y'))
  100.       flag1 = 1; /* if they specified Y, set the flag */
  101.      else
  102.       flag1 = 0; /* anything but Y or y means NO */
  103.      last -= 2; /* bump the last character down */
  104.      argv[1][last] = 0; /* and now, null terminate the command line */
  105.     }
  106.  
  107.     for (temp = last; ((argv[1][temp] != ':') && (temp >= first) && (argv[1][temp] != '\\')); temp--); /* find last \ */
  108.  
  109.     for (temp1 = first; temp1 < temp+1; temp1++) /* get pathname (if any) */
  110.     {start[temp1-first] = argv[1][temp1];}
  111.     start[temp1-first] = 0; /* null terminate it */
  112.  
  113.     for (temp1 = temp+1; temp1 <= last; temp1++) /* get the filename to look for */
  114.     {look[temp1-(temp+1)] = argv[1][temp1];}
  115.     look[temp1-(temp+1)] = 0; /* null terminate this */
  116.  
  117.    }
  118.   }
  119.  
  120. /* get the drive we started in */
  121. get_drive(drive);
  122.  
  123. if (drive[1] == 255) /* if the default was for current drive, use it */
  124.  drive[1] = drive[0];
  125. else /* otherwise, normalize whatever they typed in to start with a=0 */
  126.  if ((drive[1] > 'A') && (drive[1] < 'Z'))
  127.    drive[1] = drive[1] - 'A';
  128.  else
  129.    drive[1] = drive[1] - 'a';
  130.  
  131. /* change to the starting drive */
  132. ret=chg_drive(drive[1]);
  133.  
  134. if (ret < drive[1])
  135.   printf("invalid drive selected...\n");
  136. else
  137.  {
  138.   /* get the directory we started in */
  139.   init_dir[0] = '\\';
  140.   get_dir(init_dir+1);
  141.  
  142.   if (start[0] == 0) /* if there was no starting path, use the current one */
  143.    strcpy(start,init_dir);
  144.  
  145.   /* do the actual work */
  146.   doit(look,start,flag1);
  147.  
  148.   /* change back to the initial drive */
  149.   chg_drive(drive[0]);
  150.  
  151.   /* now, change back to the initial directory */
  152.   chg_dir(init_dir);
  153.  } /* end else */
  154.  
  155. } /* end function */
  156.  
  157. doit(look,start,flag1)
  158. char *look,*start,flag1;
  159.  
  160. {
  161.  char file[3],name[128],*dirstak,curdir[140],*getmem();
  162.  int ret,tmp,top_ndx,bottom_ndx;
  163.  
  164.  dirstak = getmem(10000); /* get a hunk of memory for the directory queue */
  165.  if (dirstak == 0) /* if the getmem returned a null, error */
  166.  {printf("not enough memory...\n");
  167.   return;}
  168.  
  169. /* set the DTA to someplace we can use */
  170.  put_dta(name);
  171.  
  172.  top_ndx = 0;    /* set pointer to top of directory queue */
  173.  bottom_ndx = 0; /* set pointer to bottom of queue */
  174.  
  175.  /* put the starting directory in the queue */
  176.  for (tmp = 0; start[tmp] != 0; tmp++)
  177.   {dirstak[bottom_ndx++] = start[tmp];}
  178.  dirstak[bottom_ndx++] = 0;
  179.  
  180.  while (top_ndx != bottom_ndx)
  181.   {
  182.    /* check for any sub-directories */
  183.    ret = dirscan(file,name,curdir,dirstak,&top_ndx,&bottom_ndx);
  184.  
  185.    if (ret != 3)
  186.     {
  187.      /* run through the directory, querying for each file */
  188.      filscan(look,name);
  189.     }
  190.  
  191.    /* if only do this one directory, end here */
  192.    if (flag1 == 0)
  193.    {
  194.     rlsmem(dirstak,10000);
  195.     return(1);
  196.    }
  197.  
  198.   } /* end while loop */
  199.   rlsmem(dirstak,10000);
  200.  
  201. } /* end function */
  202.  
  203. dirscan(file,name,curdir,dirstak,top_ptr,bot_ptr)
  204. char *file,*name,*curdir,*dirstak;
  205. int *top_ptr,*bot_ptr;
  206. {
  207.  int ret,tmp,top_ndx,bottom_ndx,*p_file;
  208.  
  209.  bottom_ndx = *bot_ptr;
  210.  top_ndx = *top_ptr;
  211.  
  212.  /* initialize the file name for the directory search */
  213.  file[0] = '*';
  214.  file[1] = '.';
  215.  file[2] = 0;
  216.  
  217.  tmp = 0;
  218.  for (top_ndx; dirstak[top_ndx] != 0; top_ndx++)
  219.   { curdir[tmp++] = dirstak[top_ndx];}
  220.  curdir[tmp] = 0;
  221.  ++top_ndx;
  222.  ret = chg_dir(curdir);
  223.  if (ret != 3)
  224.   {
  225.    printf("\n\n     %s\n",curdir);
  226.    find_dir(name,file,curdir,dirstak,&bottom_ndx);
  227.   }
  228.  *bot_ptr = bottom_ndx;
  229.  *top_ptr = top_ndx;
  230.  
  231.  return(ret);
  232. }
  233.  
  234. find_dir(name,file,curdir,dirstak,bot_ndx)
  235. char *name,*file,*curdir,*dirstak;
  236. int *bot_ndx;
  237. {
  238.  int ret,tmp,bottom_ndx;
  239.  unsigned temp;
  240.  
  241.  bottom_ndx = *bot_ndx; /* set the local variable = the real thing. */
  242.  
  243. /* search for first directory entry */
  244.  temp = 0x0010;
  245.  ret = srch1st(file,temp);
  246.  
  247. /* while the return from search is successful, check for dir attribute
  248.    and make sure it isn't a . or .. entry, put the whole pathname (null
  249.    terminated) at the bottom of the queue */
  250.  
  251.  while (ret != 18)
  252.  { if ((name[21] == 0x10) && (name[30] != '.'))
  253.    {
  254.     for (tmp = 0; curdir[tmp] != 0; tmp++)
  255.     {dirstak[bottom_ndx] = curdir[tmp];
  256.      ++bottom_ndx;}
  257.     if (curdir[1] != 0)
  258.      {dirstak[bottom_ndx++] = '\\';}  
  259.    for (tmp = 30; name[tmp] != 0; tmp++)
  260.     {dirstak[bottom_ndx] = name[tmp];
  261.      ++bottom_ndx;}
  262.    dirstak[bottom_ndx++] = 0;
  263.  
  264.    } /* end if */
  265.     ret = srchnext(file); /* get another directory entry */
  266.  } /* end while */
  267.  
  268.  *bot_ndx = bottom_ndx; /*now restore the real value to its proper place */
  269.  
  270. } /* end function */
  271.  
  272. filscan(look,name)
  273. char *look,*name;
  274. {
  275.  int ret,numb;
  276.  char tmp,line[35],flag;
  277.  unsigned temp;
  278.  long make_line(),total;
  279.  
  280.  total = 0;
  281.  numb = 0;
  282.  flag = 0;
  283.  temp = 0x0000;
  284.  ret = srch1st(look,temp); /* start looking for files */
  285.  
  286.  while (ret != 18)
  287.  {
  288.   total += make_line(line,name);
  289.   numb++;
  290.   printf(line);
  291.   if (flag == 0)
  292.   {printf("         ");
  293.    flag = 1;}
  294.   else
  295.   {printf("\n");
  296.    flag = 0;}
  297.  
  298.   ret = srchnext(look); /* get another directory entry */
  299.  } /* end while */
  300.  if (flag == 1)
  301.   printf("\n");
  302.  printf("  --> %d files, total space = %8lu<--\n",numb,total);
  303.  
  304. } /* end function */
  305.  
  306. put_dta(p_dta)
  307. char *p_dta;
  308. {
  309.  union REGS inreg;
  310.  union REGS outreg;
  311.  
  312.  inreg.h.ah = 0x1a;
  313.  inreg.x.dx = p_dta;
  314.  
  315.  intdos(&inreg,&outreg);
  316.  
  317.  return(0);
  318. }
  319.  
  320. srch1st(p_file,attr)
  321. int *p_file;
  322. unsigned attr;
  323. {
  324.  union REGS inreg;
  325.  union REGS outreg;
  326.  
  327.  inreg.h.ah = 0x4e;
  328.  inreg.x.cx = attr;
  329.  inreg.x.dx = p_file;
  330.  
  331.  intdos(&inreg,&outreg);
  332.  
  333.  return(outreg.x.ax);
  334. }
  335.  
  336. srchnext(p_file)
  337. int *p_file;
  338. {
  339.  union REGS inreg;
  340.  union REGS outreg;
  341.  
  342.  inreg.h.ah = 0x4f;
  343.  
  344.  intdos(&inreg,&outreg);
  345.  
  346.  return(outreg.x.ax);
  347. }
  348.  
  349. chg_dir(curdir)
  350. char *curdir;
  351. {
  352.  union REGS inreg;
  353.  union REGS outreg;
  354.  
  355.  inreg.h.ah = 0x3b;
  356.  inreg.x.dx = curdir;
  357.  
  358.  intdos(&inreg,&outreg);
  359.  
  360.  return(outreg.x.ax);
  361. }
  362.  
  363. get_dir(temp)
  364. char *temp;
  365. {
  366.  union REGS inreg;
  367.  union REGS outreg;
  368.  
  369.  inreg.h.ah = 0x47;
  370.  inreg.h.dl = 0; /* relative drive */
  371.  inreg.x.si = temp; /* where to put the pathname */
  372.  
  373.  intdos(&inreg,&outreg);
  374.  
  375.  return(outreg.x.ax);
  376. }
  377.  
  378. get_drive(where)
  379. char *where;
  380. {
  381.  union REGS inreg;
  382.  union REGS outreg;
  383.  
  384.  inreg.h.ah = 0x19;
  385.  
  386.  intdos(&inreg,&outreg);
  387.  
  388.  *where = outreg.h.al;
  389. }
  390.  
  391. era_file(which)
  392. char *which;
  393. {
  394.  union REGS inreg;
  395.  union REGS outreg;
  396.  
  397.  inreg.h.ah = 0x41;
  398.  inreg.x.dx = which; /* pointer to filename */
  399.  
  400.  intdos(&inreg,&outreg);
  401.  
  402.  /* there's no easy way to check for errors, so don't even do it.
  403.     dos returns error flag in carry flag, LATTICE C can't access it without
  404.     your own assembler routine. I have one, but it's a bit hairy. For those
  405.     who insist on doing things right, drop me a note. jjw */
  406. }
  407.  
  408. chg_drive(drive)
  409. char drive;
  410. {
  411.  union REGS inreg;
  412.  union REGS outreg;
  413.  
  414.  inreg.h.ah = 0x0e;
  415.  inreg.h.dl = drive;
  416.  
  417.  intdos(&inreg,&outreg);
  418.  
  419.  return(outreg.h.al);
  420. }
  421.  
  422.  
  423. /************************************************************************/
  424. /*                         make_line()                                  */
  425. /*           make the line of directory info to be printed              */
  426. /*                                                                      */
  427. /************************************************************************/
  428.  
  429. long make_line(dst,nam)
  430. char *dst,*nam;
  431. {
  432.  unsigned g1,g2,g3; /* garbage variables */
  433.  char flag,temp; /* flagged or not, temporary counter */
  434.  char name[9],ext[5],*where; /* hold the file name & extension, which place to put filename */
  435.  int ret; /* true if we are did not go off the bottom of the dir */
  436.  long size,g7,t1,t2,t3; /* size of file in bytes, temp variables */
  437.  char direct[23]; 
  438.  
  439.  t1 = 256; /* offset for high size low */
  440.  t2 = 65536; /* offset for low size high */
  441.  t3 = 16777216; /* offset for high size high */
  442.  
  443.   for (temp = 24; temp != 43; temp++) /* load the date, size and name */
  444.   { direct[temp-21] = nam[temp]; /* put the char into the dir area */ }
  445.  
  446.   for (temp = 0; temp != 6; temp++) /* blank out the extension */
  447.   { ext[temp] = 0; }
  448.  
  449.   for (temp = 0; temp != 10; temp++) /* blank out the file name */
  450.   { name[temp] = 0; }
  451.  
  452.   where = name; /* start by putting the name in the name */
  453.  
  454.   for (temp = 0; temp <= 12; temp++) /* copy over the file name */
  455.   { if (direct[9+temp] == '.') /* if we hit the seperator between name & ext, */
  456.     {
  457.      where = ext; /*switch over to the extension */
  458.      temp++; /* skip to next character */
  459.     }
  460.     if (direct[9+temp] == 0) /* if we're at the end of the string, stop */
  461.      temp = 13; /* exit condition */
  462.     else
  463.     {
  464.      *where = direct[9+temp]; /* copy the char over to the array */
  465.      where++; /* increment pointer */
  466.     }
  467.   }
  468.  
  469.     g1 = direct[4]; /* will be the year */
  470.     g2 = direct[4]*256+direct[3]; /* will be the month */
  471.     g3 = direct[3]; /* will be the day */
  472.  
  473.     g7 = direct[5]; /* compute size in bytes */
  474.     size = g7;
  475.     g7 = direct[6];
  476.     size = size + (g7*t1);
  477.     g7 = direct[7];
  478.     size = size + (g7*t2);
  479.     g7 = direct[8];
  480.     size = size + (g7*t3); /* will be the file size in bytes */
  481.  
  482.     /* shift things around to get rid of un-necessary bits */
  483.     g1 >>= 1; /* right-shift month by 1 */
  484.     g2 <<= 7; /* left-shift day by 7 */
  485.     g2 >>= 12; /* then right-shift by 12 to drop off garbage bits */
  486.     g3 &= 0x1f; /* mask off garbage bits to get the year */
  487.  
  488.     sprintf(dst,"%-8s.%-3s  %02d-%02d-%02d %8lu",name,ext,g2,g3,g1+80,size);
  489.     /* make a useful string out of the flag, name, date and size */
  490.  
  491. return(size);
  492.