@echo off REM PathSubs.bat - Compact the PATH statement by using SUBST for the paths in REM the list. Also allow to add or delete a path. See the REM Instructions() function for a description of how to use subst | cenvi %0.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 GOTO CENVI_EXIT Instructions() { printf("\a\n") printf("PathSubs - Keep the PATH environment variable as short as possible buy using\n") printf(" DOS's SUBST command to replace PATH directories with drive letters.\n") printf("\n") printf("SYNTAX: PathSubs [ < + | - > d:\\path ]\n") printf("\n") printf("Where: + Add a path to the PATH variable, if not already there.\n") printf(" - Remove a path from the PATH variable, if it is there.\n") printf(" d:\\path The FULL directory to add or remove from PATH.\n") printf("\n") printf("The following table shows examples of the SUBST command.\n"); printf("\n") printf("PathSubs Compacts the current path using drive substitutions\n") printf("PathSubs + D:\\UTL Add D:\UTL to the current PATH\n") printf("PathSubs - D:\\UTL Remove D:\UTL from the current PATH\n") printf("\n") } // The following code uses the path structure which has the elements: // Count : number of directories in the path // path[Count].Dir : array of Count strings, each containing a full directory // path[Count].Drive : drive letter substituted here, else 0 for not subst // and also the Subs structure which has the elements // Count : number of drives Substituted // sub[Count].Drive : array of Count drive letters substituted for Dir // sub[Count].Dir : array of Count strings for the path of each substituted driev main(ArgCount,ArgStrings) { // Decide what to do from input if ( ArgCount == 3 ) { Command = ArgStrings[1] CommandPath = ArgStrings[2] if ( Command[1] != 0 || ( Command[0] != '+' && Command[0] != '-' ) ) { // Invalid input, so just show how to use and quit Instructions() return(1) } } else if ( ArgCount != 1 ) { // Invalid input, so just show how to use and quit Instructions() return(1) } // Build lists of substituted drives and of paths Subs = BuildSubsArray() Paths = SeparatePATHIntoDirs(Subs) // implement new command based on input arguments if ( ArgCount == 3 ) { if ( Command[0] == '+' ) AddPath(CommandPath,Paths) else RemovePath(CommandPath,Paths,Subs) } CompactPaths(Paths,Subs) ShowCurrentPath(Paths) return(0) } ShowCurrentPath(p) { printf("PATH=") for ( i = 0, count = 0; i < p.Count; i++ ) { if ( p.path[i].Dir != NULL ) { if ( count++ ) printf(";") printf("%s",p.path[i].Dir) } } printf("\n") } AddPath(Dir,p) { // First check if this directory is already in the path for ( i = 0; i < p.Count; i++ ) { if ( 0 == stricmp(Dir,p.path[i].Dir) ) { printf("Directory \"%s\" is already in the PATH\n",p.path[i].Dir) return } } // was not found above in the path, and so add to end of path list strcpy(p.path[p.Count].Dir,Dir) p.path[p.Count].Drive = 0 // assume it is not substituted p.Count++ } RemovePath(Dir,p,s) { // First check that this directory is already in the path for ( i = 0; i < p.Count; i++ ) { if ( 0 == stricmp(Dir,p.path[i].Dir) ) { break } } if ( i == p.Count ) printf("Directory \"%s\" is not in the PATH\n",Dir) else { // remove this directory from the path, and remove its SUBST if ( (drive = toupper(p.path[i].Drive)) != 0 ) { // this path has a SUBSTITUTED drive, and so remove that subst drive for ( j = 0; j < s.Count; j++ ) { if ( s.sub[j].Drive == drive ) break; } s.sub[j].Drive = 0; // use DOS's SUBST utility to un-substitute this drive system("SUBST %c: /D",drive) } // set path structure to know this path is no longer there p.path[i].Drive = 0; p.path[i].Dir = NULL } } BuildSubsArray() // Subst output was piped to this program, and so use that output // to build list of substituted drives and paths they point to. // output line is of the form "G: is substituted for C:\OS2" { for ( s.Count = 0; NULL != (line=gets()); s.Count++ ) { // first letter of SUBST is the drive letter s.sub[s.Count].Drive = toupper(line[0]); // last string before whitespace is the path for ( d = line + strlen(line); d[-1] != ' '; d-- ) ; strcpy(s.sub[s.Count].Dir,d) } return(s) } SeparatePATHIntoDirs(subs) // Separate the PATH environment variable into // individual paths, return element Count to how many // paths, and setting each Dir[] element to a path. // any paths that fit into the subst array will be // replaced by their full subst path { Paths.Count = 0 p = PATH while ( NULL != p && 0 != p[0] ) { if ( ';' == p[0] ) p++ // skip semi-colons else { strcpy(NewDir,p) if ( NULL != (c = strchr(NewDir,';')) ) c[0] = 0; // check if this is a "A:\" type path and if it is substituted Paths.path[Paths.Count].Drive = 0 // assume it is not substituted if ( 0 == strcmp(NewDir+1,":\\") ) { // loop through subst to see if this is one of those for ( i = 0; i < subs.Count; i++ ) { if ( toupper(NewDir[0]) == subs.sub[i].Drive ) { // put in the real path for this substituted one NewDir = subs.sub[i].Dir Paths.path[Paths.Count].Drive = subs.sub[i].Drive break } } } strcpy(Paths.path[Paths.Count++].Dir,NewDir) p = strchr(p,';') } } return(Paths) } CompactPaths(p,s) // this writes the PATH statement in compacted form, substituting // all drives for a path whenever it can. It assumes that it will // Subst on any drive letter that isn't used already. { TempPath[0] = '\0' // restart directories from scratch SubstDir = "A:\\" // template for what a subdir looks like for ( i = 0; i < p.Count; i++ ) { if ( p.path[i].Dir != NULL ) { if ( p.path[i].Drive != 0 ) { // this path already has a drive letter substituted, and so keep it SubstDir[0] = p.path[i].Drive strcat(TempPath,SubstDir) } else if ( strlen(p.path[i].dir) <= 3 ) { // path can't get any shorter by substituting, and so keep it as it is strcat(TempPath,p.path[i].Dir) } else { // get the next drive letter for substituting drive = NextFreeDrive() if ( drive != 0 ) { // create a new SUBST drive for this path system("SUBST %c: %s",drive,p.path[i].Dir) SubstDir[0] = p.path[i].Drive = drive strcat(TempPath,SubstDir) // add this new drive to list of substituted drives strcpy(s.sub[s.Count].Dir,p.path[i].Dir) s.sub[s.Count].Drive = drive s.Count++ } else { // there are no more available free drives, and so simply add this dir strcat(TempPath,p.path[i].Dir) } } strcat(TempPath,";") } } // remove the final semi-colon TempPath[strlen(TempPath)-1] = 0 PATH=TempPath } NextSubstDrive = 'D' // this global is incremented for each drive to test NextFreeDrive() // return a character for the next available free drive letter // or '\0' if no drive available. Check if a drive is available // by seeing if there's a current path for that drive { CurDir = "C:." // this string, with drive letter substituted tested for curdir while ( NextSubstDrive <= 'Z' ) { CurDir[0] = NextSubstDrive++ if ( NULL == FullPath(CurDir) ) { return( NextSubstDrive - 1 ) } } // no free drive was found; indicate by returning 0 return '\0' } :CENVI_EXIT