/*************************************************************************** ** J.C - Jump to dir * ** Use small model (tcc -ms -w+ -w-stv j.c) * ***************************************************************************/ /*-------------------------------------------------------------------------- TC MSC TC MSC ============= ================= ============= ================= FA_RDONLY -> _A_RDONLY struct ffblk -> struct find_t FA_HIDDEN -> _A_HIDDEN findfirst() -> _dos_findfirst() FA_SYSTEM -> _A_SYSTEM findnext() -> _dos_findnext() FA_LABEL -> _A_VOLID getdisk() -> _dos_getdrive() FA_DIREC -> _A_SUBDIR setdisk() -> _dos_setdrive() FA_ARCH -> _A_ARCH MAXPATH -> 80 --------------------------------------------------------------------------*/ unsigned _stklen = 6000; /* stack */ unsigned _heaplen = 4000; /* heap */ #define FALSE 0 #define TRUE !FALSE #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOL #define BOOL int #endif #ifndef ERRORCODE #define ERRORCODE int #endif /* error codes: */ #define E_OK 0 #define E_FAIL 1 char *pszTreeFileName(int iDrive, char *pszHomeDir); ERRORCODE eReadTreeImage(int iDrive, int *piLastInd, char *pszHomeDir); ERRORCODE eSaveTreeImage(int iDrive,int iLastInd,char *pszHomeDir); void vMakeFullPath(int iCurrentInd,char *pszPath); void vJumpDir(char *pszDirToFind, char *pszHomeDir); void vScanDirs(int iLevel, char *pszPath,struct ffblk stDTA); void vBuildTreeFile(int iDrive, char *pszHomeDir); BOOL bIsValidDrive(int iDrive); #define TREE_TABLE_SIZE 600 struct { int iLevel; /* how deep the dir is in the tree */ char szDirName[14]; /* dir name */ } arstTree[TREE_TABLE_SIZE]; int iLastIndex; /**************************************************************************/ main(int argc, char *argv[]) { char *pszTemp; char szHomeDir[MAXPATH]; if (_osmajor < 3) { printf("\nSorry - DOS 3.x required!\n"); exit(1); } strcpy(szHomeDir,argv[0]); /* program name */ pszTemp = strrchr(szHomeDir,'\\'); /* remove trailing backslash */ *pszTemp = 0; /* now we have the home dir */ if (argc > 1) { if (!stricmp(argv[1],"/r") || !stricmp(argv[1],"-r")) vBuildTreeFile(0,szHomeDir); else if (!stricmp(argv[1],"\\")) chdir("\\"); else { strupr(argv[1]); if (*(argv[1]+1) == ':') { /* Set the disk (it won't be restored even if chdir fails)*/ if (!bIsValidDrive(*argv[1])) { printf("\nInvalid drive!\n"); exit(1); } setdisk((int)(*(argv[1])-'A')); if (*(argv[1]+2) == '\\') /* X:\ */ chdir("\\"); else if (*(argv[1]+2) != 0) /* if path follows */ vJumpDir(argv[1]+2,szHomeDir); } else vJumpDir(argv[1],szHomeDir); } } else { printf("Directory Jumper v. 1.0 - Created by J Nuotia\n"); printf("Usage: J [X:]dir_name or\n"); printf(" J /r (to rescan the drive)\n\n"); printf("Examples: J win ( ÄÄÄ> \\windows)\n"); printf(" J d:text ( ÄÄÄ> d:\\word\\text)\n"); } return 0; } /**************************************************************************/ void vBuildTreeFile(int iDrive, char *pszHomeDir) { /* Builds directory table on drive 'iDrive' (0 for default,A for A: etc). ** IN: iDrive -> which drive ** pszHomeDir -> our home */ struct ffblk stDTA; int iCurrentDrive; char szPath[MAXPATH]; if (iDrive == 0) iDrive = 'A'+ getdisk(); printf("Please wait...\n"); if (iDrive) { iCurrentDrive = getdisk(); setdisk((int)(iDrive-'A')); /* change drive */ } strcpy(szPath,"\\*.*"); stDTA.ff_name[0] = '\0'; /* for compiler only, no meaning whatsoever */ memset(&arstTree,sizeof(arstTree),0); sprintf(arstTree[0].szDirName,"%c:\\",iDrive); /* make root entry */ arstTree[0].iLevel = 0; iLastIndex = 0; /* used in vScanDirs() */ vScanDirs(0,szPath, stDTA); eSaveTreeImage(iDrive,iLastIndex,pszHomeDir); if (iDrive) setdisk(iCurrentDrive); } /**************************************************************************/ void vScanDirs(int iLevel, char *pszPath,struct ffblk stDTA) { /* Walk thru all the directories. ** IN: iLevel,pszPath,stDTA -> results from the previous recursion */ BOOL bDone; int iOldLength; iOldLength = strlen(pszPath); bDone = findfirst(pszPath,&stDTA,FA_DIREC+FA_SYSTEM+FA_HIDDEN); while (!bDone) { pszPath[iOldLength] = 0; if (((stDTA.ff_attrib & FA_DIREC) == FA_DIREC) && (stDTA.ff_name[0] != '.')) { iLastIndex++; /* next free index */ if (iLastIndex == TREE_TABLE_SIZE) { /* this must be a BIG disk */ printf("\nThe disk is too complicated for me!\n"); exit(1); } arstTree[iLastIndex].iLevel = iLevel; strcpy(arstTree[iLastIndex].szDirName,stDTA.ff_name); pszPath[strlen(pszPath)-3] = 0; /* remove '*.*' */ strcat(pszPath,stDTA.ff_name); strcat(pszPath,"\\*.*"); vScanDirs(iLevel+1, pszPath, stDTA); } if (findnext(&stDTA) == -1) /* all done? */ bDone = TRUE; } } /**************************************************************************/ void vJumpDir(char *pszDirToFind, char *pszHomeDir) { /* Change dir. ** IN: pszDirToFind -> where to cd ** pszHomeDir -> our home */ int iLastNameInd; char szPath[MAXPATH]; int iDrive; int iIndex; int iOldIndex; /* current directory - we search higher index */ BOOL bFirstTry; BOOL bDone; char szCurrentPath[MAXPATH]; iDrive = 'A' + getdisk(); getcwd(szCurrentPath,MAXPATH); bFirstTry = TRUE; bDone = FALSE; while (!bDone) { if (eReadTreeImage(iDrive,&iLastNameInd,pszHomeDir) != E_OK) exit(1); iOldIndex = -1; /* now find the current path */ for (iIndex = 0; iIndex <= iLastNameInd; iIndex++) { vMakeFullPath(iIndex,szPath); if (!strcmp(szPath,szCurrentPath)) { iOldIndex = iIndex; break; } } if ((iOldIndex == -1) && (bFirstTry)) { /* the index is out-of-date*/ vBuildTreeFile(iDrive,pszHomeDir); bFirstTry = FALSE; } else if (iOldIndex == -1) { /* we already tried building it */ printf("Internal error. Sorry!\n"); /* this shouldn't happen! */ exit(1); } else bDone = TRUE; /* ok, we found it */ } /* First we try from the current dir to the end. That way we can cycle thru all the matching directories if the user tries running Jumper with the same parameter. */ for (iIndex = iOldIndex+1; iIndex <= iLastNameInd; iIndex++) { if (!strnicmp(pszDirToFind,arstTree[iIndex].szDirName, strlen(pszDirToFind))) { vMakeFullPath(iIndex,szPath); if (chdir(szPath) != 0) { printf("\nCouldn't change to %s!\n",szPath); exit(1); } exit(0); } } /* So not found... Let's try from the beginning */ for (iIndex = 0; iIndex <= iOldIndex; iIndex++) { if (!strnicmp(pszDirToFind,arstTree[iIndex].szDirName, strlen(pszDirToFind))) { vMakeFullPath(iIndex,szPath); if (chdir(szPath) != 0) { printf("\nCouldn't change to %s!\n",szPath); exit(1); } exit(0); } } printf("\nNot found!\n"); } /**************************************************************************/ void vMakeFullPath(int iCurrentInd,char *pszPath) { /* Return the full path of 'iCurrentInd' dir. ** IN: iCurrentInd -> current index ** OUT: pszPath -> the full path */ int ariMatches[20]; /* indices that are part of the name */ int iInd; int iPreviousLevel; if (iCurrentInd == 0) { /* root */ strcpy(pszPath,arstTree[0].szDirName); return; } iInd = 0; iPreviousLevel = 99; /* start from the current one */ while (arstTree[iCurrentInd].iLevel >= 0) { if (arstTree[iCurrentInd].iLevel < iPreviousLevel) { ariMatches[iInd] = iCurrentInd; iInd++; iPreviousLevel = arstTree[iCurrentInd].iLevel; } iCurrentInd--; } iInd--; strncpy(pszPath,arstTree[0].szDirName,2); /* drive spec */ pszPath[2] = '\0'; for (; iInd >= 0; iInd--) { strcat(pszPath,"\\"); strcat(pszPath,arstTree[ariMatches[iInd]].szDirName); } } /**************************************************************************/ ERRORCODE eSaveTreeImage(int iDrive,int iLastInd,char *pszHomeDir) { /* Note that the tree links must be correct. This function does only ** the actual writing. ** IN: iDrive -> which drive ** pszHomeDir -> our home ** iLastInd -> last index of the table ** Return: error code */ int iHandle; char szFileName[MAXPATH]; strcpy(szFileName,pszTreeFileName(iDrive,pszHomeDir)); iHandle = open(szFileName, O_WRONLY|O_CREAT | O_BINARY, S_IWRITE); if (iHandle == -1) { printf("Cannot open %s\n",szFileName); return E_FAIL; } if (write(iHandle,arstTree,sizeof(arstTree)) != sizeof(arstTree)) { printf("Couldn't save the index. Disk full?\n"); close(iHandle); unlink(szFileName); return E_FAIL; } /* truncate the file (we need to know the actual size when reading it) */ chsize(iHandle,(long)(sizeof(arstTree[0])*(iLastInd+1))); close(iHandle); return E_OK; } /**************************************************************************/ ERRORCODE eReadTreeImage(int iDrive, int *piLastInd, char *pszHomeDir) { /* Read tree image from file, create if one does not exist. ** IN: iDrive -> which drive ** pszHomeDir -> our home ** OUT: piLastInd -> the new last index for the table ** Return: error code */ char szFileName[MAXPATH]; long lFileSize; int iHandle; int iBytesRead; strcpy(szFileName,pszTreeFileName(iDrive,pszHomeDir)); iHandle = open(szFileName,O_RDONLY | O_BINARY); if (iHandle == -1) { vBuildTreeFile(iDrive,pszHomeDir); iHandle = open(szFileName,O_RDONLY | O_BINARY); if (iHandle == -1) { printf("Cannot open tree image file %s\n",szFileName); return E_FAIL; } } lFileSize = filelength(iHandle); iBytesRead = read(iHandle,&arstTree,(unsigned)lFileSize); if (lFileSize != (long) iBytesRead) { printf("Error reading %s\n",szFileName); close(iHandle); return E_FAIL; } close(iHandle); *piLastInd = (int) (lFileSize/sizeof(arstTree[0]))-1; /* last item */ return E_OK; /* no error */ } /**************************************************************************/ char *pszTreeFileName(int iDrive, char *pszHomeDir) { /* Return the file name of the index. ** IN: iDrive -> which drive ** pszHomeDir -> our home ** Return: the file name */ static char szPath[MAXPATH]; char szFileName[] = "JTREEx.DAT"; if (iDrive == 0) /* default drive */ szFileName[5] = 'A'+ getdisk(); else szFileName[5] = iDrive; if (strlen(pszHomeDir) == 3) /* X:\ */ sprintf(szPath,"%s%s",pszHomeDir,szFileName); else sprintf(szPath,"%s\\%s",pszHomeDir,szFileName); return szPath; } /****************************************************************************/ BOOL bIsValidDrive(int iDrive) { /* Is 'iDrive' a valid drive (phantom B: is considered valid) ** IN: iDrive -> drive to check ** Return: TRUE if valid */ char szSpec[4]; union REGS stInRegs,stOutRegs; struct SREGS stSegRegs; struct fcb stFCB; strcpy(szSpec,"X:\\"); stInRegs.x.ax = 0x2906; /* service: parse file name */ stInRegs.x.si = FP_OFF(szSpec); /* set parameters... */ stSegRegs.ds = FP_SEG(szSpec); stInRegs.x.di = FP_OFF(&stFCB); /* address of FCB */ stSegRegs.es = FP_SEG(&stFCB); szSpec[0] = (char)iDrive; intdosx(&stInRegs, &stOutRegs,&stSegRegs); if (stOutRegs.h.al != 0xFF) /* if not an error then it is valid */ return TRUE; return FALSE; }