home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / directry / rm / rm.c next >
Encoding:
C/C++ Source or Header  |  1986-01-02  |  10.4 KB  |  421 lines

  1. /*
  2.  *==========================================================================
  3.  * rm      - lists all matching directory entries in a path.  wildcards are
  4.  *        allowed in the pattern. user chooses whether to delete the files.
  5.  *        a recursive search of sub-directories is supported.
  6.  *
  7.  *        usage: rm [-r] [drive:][path]filespec
  8.  *           r = recursively search sub-directories below path
  9.  *
  10.  *        compile: msc  rm;  [Microsoft C version 3.0 ]
  11.  *        link   : link rm;  [Microsoft Link ver. 3.01]
  12.  *
  13.  *        note   : the stack may be adjusted if necessary
  14.  *==========================================================================
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <ctype.h>
  19. #include <dos.h>
  20.  
  21. #define DRIVE      0x0E        /* select default drive       */
  22. #define FINDFIRST 0x4E        /* find first matching file   */
  23. #define FINDNEXT  0x4F        /* find next matching entry   */
  24. #define SETDTA      0x1A        /* set disk transfer address  */
  25.  
  26. #define SUBDIR      0x10        /* file attribute: sub-direct */
  27. #define FILES      0x00        /* file attribute: reg-files  */
  28.  
  29. #define INVALID   0x12        /* invalid search parameter   */
  30. #define NOTFOUND  0x02        /* pattern not matched          */
  31.  
  32. #define FALSE 0
  33. #define TRUE  1
  34.  
  35. #define PATHLEN   256        /* maximum length of path     */
  36. #define NAMELEN    13        /* maximum length of filename */
  37.  
  38. typedef struct            /* MS-DOS disk transfer block */
  39.     {
  40.     char sysinfo[21];        /* system information          */
  41.     char attrib;        /* file attributes          */
  42.     int  filtime;        /* time of file           */
  43.     int  fildate;        /* date of file           */
  44.     long filsize;        /* size of file in bytes      */
  45.     char fname[NAMELEN];    /* filename and extension     */
  46.     } DIR;
  47.  
  48. DIR dtawrk;            /* working DTA block          */
  49.  
  50. char basepath[PATHLEN];     /* search path if given       */
  51. char cur_path[PATHLEN];     /* current path at beginning  */
  52. char loc_path[PATHLEN];     /* local directory path       */
  53.  
  54. int basedir;            /* recursive search counter   */
  55. int found;            /* number of matching entries */
  56. int deleted;            /* number of deleted matches  */
  57.  
  58. struct SREGS segregs;        /* segment registers          */
  59. union REGS regs;        /* union for registers          */
  60.  
  61. void abend(),    usage(),   s_dta(),
  62.      s_drive(), restore(), pg_files();
  63.  
  64. /*
  65.  *=================================================================
  66.  * abnormal termination routine
  67.  *    this function is called for the following reasons:
  68.  *    1.  the filespec is too long [13 characters max.].
  69.  *    2.  the pathlength exceeds buffer space allocated [256].
  70.  *    3.  the drivespec does not exist, or is not in proper format.
  71.  *=================================================================
  72.  */
  73. void abend(msg)
  74.     char *msg;        /* termination error message */
  75.     {
  76.     restore();
  77.     fputs(msg, stderr);
  78.     exit(1);
  79.     }
  80.  
  81. /*
  82.  *=======================================================
  83.  * explain usage of utility
  84.  *    called if invalid number of parameters in command
  85.  *    line, or option parameter is invalid.
  86.  *=======================================================
  87.  */
  88. void usage()
  89.     {
  90.     fputs("usage: rm [-r] [drive:][path]filespec...\n", stderr);
  91.     exit(1);
  92.     }
  93.  
  94. /*
  95.  *=================================================
  96.  * set the Disk Transfer Address to our buffer area
  97.  * using segment register for full address.
  98.  *=================================================
  99.  */
  100. void s_dta()
  101.     {
  102.     segread(&segregs);
  103.     regs.h.ah = SETDTA;
  104.     regs.x.dx = &dtawrk;
  105.     intdosx(®s, ®s, &segregs);
  106.     }
  107.  
  108. /*
  109.  *=======================================================
  110.  * select chosen drive
  111.  *    this DOS call does not return an error value in
  112.  *    the normal way.  it returns the number of drives
  113.  *    currently available.  if the chosen drive was
  114.  *    out of this range, no drive-change was done.
  115.  *=======================================================
  116.  */
  117. void s_drive(d)
  118.     char *d;        /* drive string */
  119.     {
  120.     unsigned drv;
  121.  
  122.     drv = toupper(*d) - 'A';
  123.     regs.h.ah = DRIVE;
  124.     regs.h.dl = drv;
  125.     intdos(®s, ®s);
  126.  
  127.     if (regs.h.al < drv)
  128.     abend("\ninvalid drive...\n");
  129.     }
  130.  
  131. /*
  132.  *===============================================================
  133.  * restore drive and directory to original values
  134.  *    of course, if original working drivespec was not changed,
  135.  *    no drive-change is needed, but why add the test logic?
  136.  *===============================================================
  137.  */
  138. void restore()
  139.     {
  140.     char dr[3];     /* drive */
  141.  
  142.     strncpy(dr, cur_path, 2);
  143.     s_drive(dr);
  144.     chdir(cur_path);
  145.     }
  146.  
  147. /*
  148.  *==============================================================
  149.  * search directory(s), print all matches and query for deletion
  150.  *==============================================================
  151.  */
  152. void pg_files(xtn, str)
  153.     int  xtn;            /* extended search flag    */
  154.     char *str;            /* pattern search template */
  155.     {
  156.     char dta_buf[21];        /* system info for search  */
  157.     char query;         /* user response to match  */
  158.  
  159.     /*
  160.      * recursive search through sub-directories if requested
  161.      */
  162.  
  163.     if (xtn)
  164.     {
  165.     regs.h.ah = FINDFIRST;
  166.     regs.x.cx = SUBDIR;    /* look for directory         */
  167.     regs.x.dx = "*.";        /* wild card for directories */
  168.     intdos(®s, ®s);
  169.  
  170.     /*
  171.      * if we fail here, something is wrong.
  172.      * all directories have "." and ".."  .
  173.      */
  174.  
  175.     if (regs.x.ax == NOTFOUND || regs.x.ax == INVALID)
  176.         {
  177.         if (basedir)
  178.         {
  179.         chdir("..");
  180.         basedir--;
  181.         }
  182.         return;        /* invalid path, or no match */
  183.         }
  184.  
  185.     /*
  186.      * as long as we keep finding subdirectories
  187.      * skip past "." and ".."
  188.      */
  189.  
  190.     while (regs.x.ax != INVALID)
  191.         {
  192.         if ((dtawrk.attrib & SUBDIR) && (dtawrk.fname[0] != '.'))
  193.         {
  194.  
  195.         /*
  196.          * save our place and recurse (??)
  197.          */
  198.  
  199.         memcpy(dta_buf, dtawrk.sysinfo, 21);
  200.         chdir(dtawrk.fname);
  201.         ++basedir;
  202.         pg_files(xtn, str);
  203.  
  204.         /*
  205.          * restore our search position and
  206.          * continue the search.
  207.          */
  208.  
  209.         memcpy(dtawrk.sysinfo, dta_buf, 21);
  210.         }
  211.         regs.h.ah = FINDNEXT;
  212.         intdos(®s, ®s);
  213.         }
  214.     }
  215.  
  216.     /*
  217.      * at this point, we are either in the current directory, or
  218.      * somewhere in a subdirectory in an extended search. the
  219.      * function getcwd() tells us where we are and we print it.
  220.      */
  221.  
  222.     if (getcwd(loc_path, PATHLEN) == NULL)
  223.     abend("\ncurrent pathname exceeds buffer space...\n");
  224.  
  225.     printf("\ncurrently looking in: %s\n", loc_path);
  226.  
  227.     /*
  228.      * now we look for the pattern and print out any matches found
  229.      */
  230.  
  231.     regs.h.ah = FINDFIRST;
  232.     regs.x.cx = FILES;
  233.     regs.x.dx = str;
  234.     intdos(®s, ®s);
  235.  
  236.     if (regs.x.ax != NOTFOUND && regs.x.ax != INVALID)
  237.     {
  238.     while (regs.x.ax != INVALID)
  239.         {
  240.         printf("delete: %-15s [y/n] ", dtawrk.fname);
  241.  
  242.         if (query = getche() == 'y' || query == 'Y')
  243.         {
  244.         unlink(dtawrk.fname);
  245.         ++deleted;
  246.         }
  247.  
  248.         putchar('\n');
  249.         ++found;
  250.         regs.h.ah = FINDNEXT;
  251.         intdos(®s, ®s);
  252.         }
  253.     }
  254.  
  255.     /*
  256.      * if we were in a subdirectory, back up one
  257.      */
  258.  
  259.     if (basedir)
  260.     {
  261.     basedir--;
  262.     chdir("..");
  263.     }
  264.  
  265.     return;
  266.     }
  267.  
  268. /*
  269.  *===========================================================
  270.  * main: test parameter count, find out where we are, do some
  271.  *     rudimentary validity checking and parsing of the
  272.  *     command line parameter(s), call the search routine,
  273.  *     and print total matches found, files deleted.
  274.  *===========================================================
  275.  */
  276. main(argc, argv)
  277.     int argc;
  278.     char *argv[];
  279.     {
  280.     char drive[3];          /* drivespec         */
  281.     char pattern[NAMELEN];      /* search pattern  */
  282.     char *baseptr, *patptr;      /* parse pointers  */
  283.     int recurse;          /* scope of search */
  284.  
  285.     if (argc < 2 || argc > 3)
  286.     usage();          /* test parameter count */
  287.  
  288.     /*
  289.      * find out where we are and store it
  290.      */
  291.  
  292.     if (getcwd(cur_path, PATHLEN) == NULL)
  293.     {
  294.     fputs("\nlarger pathname buffer needed\n", stderr);
  295.     exit(1);
  296.     }
  297.  
  298.     /*
  299.      * establish a working DTA and initialize variables
  300.      */
  301.  
  302.     s_dta();
  303.     found      =    0;
  304.     basedir    =    0;
  305.     *basepath  = NULL;
  306.     drive[0]   = NULL;
  307.     pattern[0] = NULL;
  308.     baseptr    = NULL;
  309.     patptr     = NULL;
  310.     recurse    = FALSE;
  311.  
  312.     /*
  313.      * check for recursion flag
  314.      */
  315.  
  316.     if (argc == 3)
  317.     if (strcmp(*++argv, "-r") && strcmp(*argv, "-R"))
  318.         usage();
  319.     else
  320.         recurse = TRUE;
  321.  
  322.     /*
  323.      * parse search template. check for drive, path, and filespec.
  324.      */
  325.  
  326.     patptr = strrchr(*++argv, '\\');  /* look for last backslash */
  327.  
  328.     if (patptr == NULL)
  329.     {
  330.     patptr = strrchr(*argv, ':'); /* check for drivespec */
  331.  
  332.     if (patptr == NULL)
  333.         patptr = *argv;
  334.     else
  335.         ++patptr;
  336.     }
  337.     else
  338.     ++patptr;
  339.  
  340.     if (strlen(patptr) >= NAMELEN)
  341.     abend("\nsearch template too long...\n");
  342.     else
  343.     {
  344.     strcpy(pattern, patptr);
  345.     *patptr = NULL;
  346.     }
  347.  
  348.     /*
  349.      * the filespec pattern has been found, and argv
  350.      * has been shortened.  if anything is left, it
  351.      * must be a drivespec and/or pathname.
  352.      */
  353.  
  354.     if (**argv)
  355.     {
  356.     baseptr = strrchr(*argv, ':');
  357.  
  358.     if (baseptr == NULL)
  359.         baseptr = *argv;
  360.     else
  361.         ++baseptr;
  362.     }
  363.  
  364.     /*
  365.      * if we have a pathname, we must see if more than
  366.      * one backslash occurs. if we started with a
  367.      * string like "\*.h", the correct path is "\".
  368.      * if the string was "\c\*.h", the correct path is
  369.      * "\c", not "\c\".
  370.      */
  371.  
  372.     if (baseptr)
  373.     {
  374.     if (strchr(baseptr, '\\') != strrchr(baseptr, '\\'))
  375.         *(baseptr + strlen(baseptr) - 1) = NULL;
  376.  
  377.     if (strlen(baseptr) >= PATHLEN)
  378.         abend("\nsearch path too long...\n");
  379.     else
  380.         {
  381.         strcpy(basepath, baseptr);
  382.         *baseptr = NULL;
  383.         }
  384.     }
  385.  
  386.     /*
  387.      * anything left over must be a drivespec, and
  388.      * must be two characters, the first being an
  389.      * alphabetic and the second being ":".
  390.      */
  391.  
  392.     if (**argv)
  393.     if (strlen(*argv) == 2 && isalpha(**argv) && *(*argv + 1) == ':')
  394.         strcpy(drive, *argv);
  395.     else
  396.         abend("\ninvalid drive...\n");
  397.  
  398.     /*
  399.      * make the search here
  400.      */
  401.  
  402.     if (drive[0])
  403.     s_drive(drive);
  404.  
  405.     if (*basepath)
  406.     if (chdir(basepath))
  407.         abend("\ncould not access specified directory...\n");
  408.  
  409.     pg_files(recurse, pattern);
  410.  
  411.     restore();
  412.  
  413.     /*
  414.      * display the results
  415.      */
  416.  
  417.     printf("\n\nTOTAL MATCHES FOUND: %d\n", found);
  418.     printf("TOTAL FILES DELETED: %d\n", deleted);
  419.     exit(0);
  420.     }
  421.