/* * ATTRIB command for MS-DOS * * This is an ATTRIB command that pretty much works exactly like the * one from Microsoft with the following enhancements: * * More flexible parsing: accepts +RS +R-S +RS-HA -H/S etc. * Parameters can be in any order. * * Better error reporting, instead of just saying parameters are wrong, * it tells you exactly what it didn't like. * * /V option for verbose output * /F option for "full" listing. Shows directories & volume labels * * Walks the directory tree in a more natural manner. Ie, processes * the files in a directory FIRST, then moves on to the subdirs. * * Unambiguous specification of directories. ie: append '\' to a directory * name, otherwise it is assumed to be a filename. Microsofts ATTRIB will * happily change all files in a directory if you happen to mistype it's * name instead of a filename. * * Copyright 1995 Dave Dunfield * Freely Distributable. */ #include #include #define DIRS 500 /* Depth of directory stacking */ char *pattern = "", /* Pattern we are searching for */ path[66], /* Path we are searching */ subdir = 0, /* Indicates we are to search sub-dirs */ verbose = 0, /* Be talky */ full = 0, /* Full listing */ badopt = 0, /* A bad command option was detected */ set = 0, /* Indicates we are setting attributes */ dirstack[DIRS][13]; /* Stack of subdirectory names */ unsigned setmask = 0, /* Attribute bits to set */ clrmask = -1, /* Attribute bits to clear */ dircount = 0, /* Count of directories processed */ filecount = 0, /* Count of files processed */ dirptr = 0; /* Current position in directory stack */ static char attribs[] = { "RHSVDA" }; /* Letters for attributes */ static char help_text[] = { "\n\ Displays or changes file attributes.\n\n\ ATTRIB [+/-RASH ...] [[drive:][path]filename] [/F][/S][/V]\n\ \n\ +/- Set/Clear attribute(s).\n\ R Read-only file attribute.\n\ A Archive file attribute.\n\ S System file attribute.\n\ H Hidden file attribute.\n\ /F Full listing, show dirs and volume labels\n\ /S Processes files in all subdirectories.\n\ /V Verbose command operation.\n\n\ Copyright 1995 Dave Dunfield - Freely Distributable.\n" }; /* * Process all the files in one directory */ void process_dir(void) { unsigned plen, i, attrs, dirbase; char name[13], *ptr; plen = strlen(path); strcpy(path+plen, pattern); ++dircount; if(verbose && !set) printf("\nListing %s\n\n", path); /* Search for files & handle show/set attributes */ if(!find_first(path, -1, name, &i, &i, &attrs, &i, &i)) do { if((attrs & (DIRECTORY|VOLUME)) && !full) continue; ++filecount; strcpy(path+plen, name); if(set) { /* Setting attributes */ if(set_attr(path, (attrs & clrmask) | setmask)) printf("%s: Unable to set attributes\n", path); } else { i = 0x01; for(ptr = attribs; *ptr; ++ptr) { putc((attrs & i) ? *ptr : ' ', stdout); i <<= 1; } printf(" %s\n", path); } } while(!find_next(name, &i, &i, &attrs, &i, &i)); if(subdir) { dirbase = dirptr; strcpy(path+plen, "*.*"); if(!find_first(path, -1, name, &i, &i, &attrs, &i, &i)) do { if(*name == '.') continue; if(attrs & DIRECTORY) strcpy(dirstack[dirptr++], name); } while(!find_next(name, &i, &i, &attrs, &i, &i)); for(i=dirbase; i < dirptr; ++i) { strcpy(path+plen, dirstack[i]); strcat(path, "\\"); process_dir(); } dirptr = dirbase; } path[plen] = 0; } /* * Main program - Parse options and call process_dir */ main(int argc, char *argv[]) { int i, j; char *ptr, *ptr1, c, mode; /* Parse command options */ for(i=1; (i < argc) && !badopt; ++i) { ptr = argv[i]; mode = 0; while(*ptr) switch(c = toupper(*ptr++)) { case '/' : /* Option switch */ mode = 0; switch(c = toupper(*ptr++)) { case 'F' : /* Full listing */ full = -1; continue; case 'S' : /* Process subdirs */ subdir = -1; continue; case 'V' : verbose = -1; continue; case '?' : /* Help request */ argc = 0; badopt = -1; continue; } printf("Unknown switch: '/%c'\n", c); badopt = -1; continue; case '+' : /* Add these options */ mode = 1; continue; case '-' : /* Subtract these options */ mode = -1; continue; default: /* Default */ if(mode) { set = -1; ptr1 = attribs; for(j=1; *ptr1; j <<= 1) if(*ptr1++ == c) goto founda; printf("Unknown attribute bit: '%c'\n", c); badopt = -1; founda: if(mode > 0) setmask |= j; else clrmask &= ~j; continue; } if(*pattern) { printf("Too many file specifications.\n"); badopt = -1; } else pattern = ptr-1; ptr = ""; } } if(setmask & ~clrmask) { printf("Cannot Set & Clear same attribute\n"); badopt = -1; } if((setmask | ~clrmask) & (DIRECTORY|VOLUME)) { printf("Cannot alter DIRECTORY and VOLUME attributes\n"); badopt = -1; } if(!argc) fputs(help_text, stdout); if(badopt) exit(-1); /* Separate directory and path, establish defaults */ strcpy(path, pattern); for(i=j=0; c = path[i]; ++i) switch(c) { case ':' : case '\\' : j = i+1; } if(j) { path[j] = 0; pattern += j; } else { *path = get_drive() + 'A'; strcpy(path+1, ":\\"); if(getdir(path+3)) *path = 0; else if(path[3]) strcat(path, "\\"); } if(!*pattern) pattern = "*.*"; process_dir(); /* Display result messages */ if(!filecount) printf("File not found - %s\n", pattern); else if(verbose) { putc('\n', stdout); if(subdir) printf("%u directories and ", dircount); printf("%u files were processed.\n", filecount); } }