leilabd@syma.sussex.ac.uk (Leila Burrell-Davis) (04/11/89)
I would like to pass to a program the full pathname of a file whose location I give relative to the current directory. For example, if I am in directory C:\SUBA\SUB1 and give the command FOO ..\SUB2\MYFILE.EXT I would like FOO to issue the command MYPROG C:\SUBA\SUB2\MYFILE.EXT for preference, although MYPROG C:\SUBA\SUB1\..\SUB2\MYFILE.EXT would probably be ok as well. Can anyone suggest how I might do this? -- Leila Burrell-Davis, Computing Service, University of Sussex, Brighton, UK Tel: +44 273 678390 Fax: +44 273 678335 JANET: leilabd@uk.ac.sussex.syma ARPA: leilabd%syma.sussex.ac.uk@cunyvm.cuny.edu BITNET: leilabd@syma.sussex.ac.uk UUCP: leilabd@syma.uucp
nelson@sun.soe.clarkson.edu (Russ Nelson) (04/13/89)
Written for Turbo C. I can't remember if I wrote this or if it's based on some anonymous code from the IBMPC-Digest. -russ #include <string.h> #include <ctype.h> #include <dos.h> #include <dir.h> /*** rootpath -- convert a pathname argument to root based cannonical form * * rootpath determines the current directory, appends the path argument (which * may affect which disk the current directory is relative to), and qualifies * "." and ".." references. The result is a complete, simple, path name with * drive specifier. * * If the relative path the user specifies does not include a drive spec., the * default drive will be used as the base. (The default drive will never be * changed.) * * entry: relpath -- pointer to the pathname to be expanded * fullpath -- must point to a working buffer, see warning * exit: fullpath -- the full path which results * return: true if an error occurs, false otherwise * * calls: getcurdir getdisk * * warning: fullpath must point to a working buffer large enough to hold the * longest possible relative path argument plus the longest possible * current directory path. * */ int rootpath(char *relpath, char *fullpath) { int drivenum ; char tempchar; register char *lead, *follow ; /* extract drive spec */ if ((*relpath != '\0') && (relpath[1] == ':')) { drivenum = toupper(*relpath) - 'A' ; relpath += 2 ; } else drivenum = getdisk() ; fullpath[0] = (char) ('A' + drivenum) ; fullpath[1] = ':' ; /* append relpath to fullpath/base */ if (*relpath == '\\' || *relpath == '/') { /* relpath starts at base */ strcpy(fullpath+2, relpath) ; } else { /* must get base path first */ fullpath[2] = '\\'; if (getcurdir(drivenum+1, fullpath+3)) return 1; /* terrible error */ if ((*relpath != '\0') && (strlen(fullpath) > 3)) strcat(fullpath, "\\") ; strcat(fullpath, relpath) ; } /* convert path to cannonical form */ lead = fullpath ; while(*lead != '\0') { /* mark next path segment */ follow = lead ; if ((lead = strchr(follow+1, '\\')) != '\0') { char *fslash; tempchar = '\\'; if ((fslash = strchr(follow+1, '/')) != '\0') { if (fslash < lead) lead = fslash; } } else if ((lead = strchr(follow+1, '/')) != '\0') tempchar = '\\'; else { lead = fullpath + strlen(fullpath) ; tempchar = '\0'; } *lead = '\0'; /* "." segment? */ if (strcmp(follow+1, ".") == 0) { *lead = tempchar ; strcpy(follow, lead); /* remove "." segment */ lead = follow ; } /* ".." segment? */ else if (strcmp(follow+1, "..") == 0) { *lead = tempchar ; do { if (--follow < fullpath) return 1; } while (*follow != '\\') ; strcpy(follow, lead); /* remove ".." segment */ lead = follow ; } /* normal segment */ else *lead = tempchar ; } if (strlen(fullpath) == 2) /* 'D:' or some such */ strcat(fullpath, "\\") ; /* shift to upper case */ strupr(fullpath) ; return 0; } #ifdef DEBUG void main(int argc, char *argv[]) { char fullpath[64]; if (argc != 2) cputs("usage: rootpath pathname"); else { rootpath(argv[1], fullpath); cputs(fullpath); } } #endif -- --russ (nelson@clutx [.bitnet | .clarkson.edu]) America -- Socialism for the rich people, Capitalism for the rest of us. - Michael Harrington, Co-Chair, Democratic Socialists of America
fs-info@sbsvax.UUCP (Fachschaft Mathe/Info) (04/13/89)
In article <883@syma.sussex.ac.uk>, leilabd@syma.sussex.ac.uk (Leila Burrell-Davis) writes: > I would like to pass to a program the full pathname of a file > whose location I give relative to the current directory. For > example, if I am in directory C:\SUBA\SUB1 and give the command > FOO ..\SUB2\MYFILE.EXT try a change directory to the specified relative path (possibly stripping a trailing filename, and remember the old dir), and then issue a get current work directory - this will (as far as I know) always return a full pathname (including the drive, I think). > Can anyone suggest how I might do this? Hope I could. /* * Brian o'Fish * c/o Patrick Schaaf * Alter Stadtweg 69 * D-6602 Dudweiler/Saar * GERMANY * * X.400: fs-info@sbsvax.informatik.uni-saarland.dbp.de */
bkbarret@sactoh0.UUCP (Brent K. Barrett) (04/14/89)
In article <883@syma.sussex.ac.uk>, leilabd@syma.sussex.ac.uk (Leila Burrell-Davis) writes: > I would like to pass to a program the full pathname of a file > whose location I give relative to the current directory. For > example, if I am in directory C:\SUBA\SUB1 and give the command > FOO ..\SUB2\MYFILE.EXT > I would like FOO to issue the command MYPROG C:\SUBA\SUB2\MYFILE.EXT > for preference, although MYPROG C:\SUBA\SUB1\..\SUB2\MYFILE.EXT > would probably be ok as well. For what language and what type of application? If it's in C, it's a trivial matter. If in BASIC or some other language I'm not familiar with on the PC then I'm afraid I can't help you. If in C, just grab the current working directory (getcwd()), and appen the path supplied as an argument (adding a backslash if needed). -- "Thanks, Data; I noticed." Brent Barrett ..pacbell!sactoh0!bkbarret GEMAIL: B.K.BARRETT
abcscnuk@csuna.csun.edu (Naoto Kimura) (04/22/89)
In article <716@sbsvax.UUCP> fs-info@sbsvax.UUCP (Fachschaft Mathe/Info) writes: >In article <883@syma.sussex.ac.uk>, leilabd@syma.sussex.ac.uk (Leila Burrell-Davis) writes: >> I would like to pass to a program the full pathname of a file >> whose location I give relative to the current directory. For >> example, if I am in directory C:\SUBA\SUB1 and give the command >> FOO ..\SUB2\MYFILE.EXT > >try a change directory to the specified relative path (possibly stripping >a trailing filename, and remember the old dir), and then issue a get current >work directory - this will (as far as I know) always return a full pathname >(including the drive, I think). > >> Can anyone suggest how I might do this? > >Hope I could. > >/* > * Brian o'Fish > * c/o Patrick Schaaf > * Alter Stadtweg 69 > * D-6602 Dudweiler/Saar > * GERMANY > * > * X.400: fs-info@sbsvax.informatik.uni-saarland.dbp.de > */ Oh no !!! Here I go again posting Turbo pascal source ! The following unit files are included: dossvc, mymath, mystr The function to look at is FExpand in the file dossvc.pas ---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ---- unit DosSvc; (*====================================================================*\ || MODULE NAME: DosSvc || || DEPENDENCIES: System.TPU, Dos.TPU, MyStr.TPU, PtrMath.TPU || || LAST MOD ON: 8904.07 || || PROGRAMMER: Naoto Kimura || || || || DESCRIPTION: This is a library of DOS service routines. || || Included in this unit are tools for: || || Getting string form of date and time || || Obtaining name of executed program || || Obtaining values of environment variables || || Followig MCB chain || \*====================================================================*) {$S+} {Stack checking on} {$I-} {I/O checking off} {$N-} {No numeric coprocessor} Interface Uses Dos, MyStr, PtrMath; const DIR_SEPARATOR = '\'; ALT_DIR_SEPARATOR = '/'; DSK_SEPARATOR = ':'; {$IFDEF VER40} DIR_CHARS : CharSet = ['/','\']; DOS_SEP_CHARS : CharSet = ['/','\',':']; {$ELSE} DIR_CHARS : CharSet = [DIR_SEPARATOR, ALT_DIR_SEPARATOR]; DOS_SEP_CHARS : CharSet = [DIR_SEPARATOR, ALT_DIR_SEPARATOR, DSK_SEPARATOR]; {$ENDIF} MonthName : array [1..12] of string[3] = ( 'Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec' ); DayWeekName : array [0..6] of string[3] = ( 'Sun','Mon','Tue', 'Wed','Thu','Fri','Sat' ); (*--------------------------------------------------------------------*\ | NAME: DateString | | | | This function will return the string representation of the | | information in the DateTime record type. | \*--------------------------------------------------------------------*) function DateString ( DT : DateTime ) : string; (*--------------------------------------------------------------------*\ | NAME: GetSwitchChar | | | | This function will return the switch character (the character | | used to specify options) set in DOS. | \*--------------------------------------------------------------------*) function GetSwitchChar : char; (*--------------------------------------------------------------------*\ | NAME: SetSwitchChar | | | | This function will set the switch character (the character | | used to specify options) set in DOS. | \*--------------------------------------------------------------------*) procedure SetSwitchChar ( c : char ); (*--------------------------------------------------------------------*\ | NAME: FixDirChars | | | | This function transforms the forward slash character ('/') into | | the backward slash character ('\') because version 5.0 of Turbo | | Pascal will do strange things if it finds the forward slash instead | | of the backward slash in a pathname. | \*--------------------------------------------------------------------*) function FixDirChars ( Original : string ) : string; {$IFDEF VER40} type ComStr = string[127]; PathStr = string[79]; DirStr = string[67]; NameStr = string[8]; ExtStr = string[4]; (*--------------------------------------------------------------------*\ | NAME: FSplit | | | | This procedure splits a fully specified file name, and splits | | the filename into its components. | \*--------------------------------------------------------------------*) procedure FSplit ( Path : PathStr; var Dir : DirStr; var Name : NameStr; var Ext : ExtStr ); (*--------------------------------------------------------------------*\ | NAME: FExpand | | | | This function expands the file name to a fully qualified path | | file name. | \*--------------------------------------------------------------------*) function FExpand ( Path : PathStr ) : PathStr; {$ENDIF} const ExecName : NameStr = ''; (* file name of executable *) ExecPath : DirStr = ''; (* path to executable *) (*--------------------------------------------------------------------*\ | NAME: PathName | | | | This function returns the path portion of the full path filename.| | This function interprets both '/' and '\' as directory separators. | \*--------------------------------------------------------------------*) function PathName( full : string ) : string; (*--------------------------------------------------------------------*\ | NAME: BaseName | | | | This function returns the base portion of a full path filename. | | This function interprets both '/' and '\' as directory separators. | \*--------------------------------------------------------------------*) function BaseName( full : string ) : string; (*--------------------------------------------------------------------*\ | NAME: File_Exists | | | | This boolean function returns TRUE if the file exists. | \*--------------------------------------------------------------------*) function File_Exists( s : string ) : boolean; type (*----------------------------------------------------------------*\ | The following record type describes the contents of the Program | | Segment Prefix (PSP). | | | | int20H exit code | | TopOfMemory Memory size in paragraphs | | Reserved0 ??? (0) | | PSP_DOS Far call to DOS | | TerminationAddr Terminate address | | BreakExitAddr Address of break handler | | CriticalErrorAddr Address of critical error handler | | ParentPSP_Seg Parent PSP segment | | OpenFiles Open files, $ff = unused | | EnvironmentSeg Environment segment | | PSP_OldStack far pointer to processes SS:SP ??? | | PSP_Nfiles maximum open files | | PSP_aofile ofile address | | Reserved3 Unused ??? | | PSP_int21 INT 21, far return | | Reserved4 Unused ??? | | PSP_FCB1ext FCB #1 extension | | PSP_FCB1 FCB #1 | | PSP_FCB2ext FCB #2 extension | | PSP_FCB2 FCB #2 | | PSP_DMA Command Tail | | | \*----------------------------------------------------------------*) PSPtype = record int20H : word; {00} TopOfMemory : word; {02} Reserved0 : byte; {04} PSP_DOS : array [0..4] of byte; {05} TerminationAddr, {0A} BreakExitAddr, {0E} CriticalErrorAddr : pointer; {12} ParentPSP_Seg : word; {16} OpenFiles : array [0..19] of byte; {18} EnvironmentSeg : word; {2C} PSP_OldStack : pointer; {2E} PSP_Nfiles : integer; {32} PSP_aofile : pointer; {34} Reserved3 : array [0..23] of byte; {38} PSP_int21 : array [0..1] of byte; {50} Reserved4 : array [0..1] of byte; {53} PSP_FCB1ext : array [0..6] of byte; {55} PSP_FCB1 : array [0..8] of byte; {5C} PSP_FCB2ext : array [0..6] of byte; {65} PSP_FCB2 : array [0..19] of byte; {6C} PSP_DMA : array [0..127] of byte {80} end; {$IFDEF VER40} (*--------------------------------------------------------------------*\ | NAME: GetEnv | | | | This routine is patterned after the UNIX operating system call | | which obtains the value of a specified environment variable. A | | process will inherit a copy of the parent's environment. Often, the | | environment variables are used to communicate between processes. | | Here are some examples of the usage of this function: | | | | s := GetEnv('PATH')) -- Sets "s" to the list of | | directories in which executable | | programs are to be found. | | writeln(GetEnv('PROMPT')) -- Prints the value of the DOS | | command interpreter prompt. | | s := GetEnv('INITFILE') -- Sets "s" to the value of the | | environment variable "FOO". | \*--------------------------------------------------------------------*) function GetEnv( envvar : string ) : string; (*--------------------------------------------------------------------*\ | NAME: EnvCount | | | | This function returns the number of environment strings set in | | the environment. | \*--------------------------------------------------------------------*) function EnvCount : integer; (*--------------------------------------------------------------------*\ | NAME: EnvStr | | | | This function returns the Index'th environment string. The | | string returned by this function is of the form 'VAR=VALUE.' If | | Index is beyond the last environment, then it will return a null | | string. | \*--------------------------------------------------------------------*) function EnvStr( Index : integer ) : string; {$ENDIF} (*--------------------------------------------------------------------*\ | NAME: GetProgramName | | | | This routine is used to obtain the full path name of the process | | with the given prefix segment. The following example shows you how | | to obtain the name of the program executing: | | | | s := GetProgramName( System.PrefixSeg ) | \*--------------------------------------------------------------------*) function GetProgramName( PrefixSeg : word ) : string; type (*----------------------------------------------------------------*\ | The following record type describes the contents of the Program | | Segment Prefix (PSP). | | | | Signature MCB id | | Owner PSP of process owning memory block | | Size Size in paragraphs of memory block | \*----------------------------------------------------------------*) MCB_entry = record Signature : char; Owner : word; Size : word; Unused : array [0..10] of byte end; MCB_pointer = ^MCB_entry; (*--------------------------------------------------------------------*\ | NAME: GetMCBhead | | | | This procedure is used for retrieving the address of the first | | MCB (Memory Control Block). This routine makes use of an undocu- | | mented DOS service ($52). | \*--------------------------------------------------------------------*) procedure GetMCBhead ( var MCBhead : MCB_pointer ); (*--------------------------------------------------------------------*\ | NAME: AdvanceMCBptr | | | | This procedure is used for advancing the pointer to an MCB so | | that it points to the next one in the chain. | \*--------------------------------------------------------------------*) procedure AdvanceMCBptr ( var MCBhead : MCB_pointer ); Implementation const WorkBuffer : string = ''; (*--------------------------------------------------------------------*\ | NAME: DateString | | | | This function will return the string representation of the | | information in the DateTime record type. | | | | EXTERNALS: | | type DateTime (from DOS unit) | | string[] MonthName (local to unit) | \*--------------------------------------------------------------------*) function DateString ( DT : DateTime ) : string; var y : string[4]; d,h,m,s : string[2]; begin str(DT.Day:2,d); str(DT.Year:4,y); str(DT.Hour:2,h); if h[1]=' ' then h[1] := '0'; str(DT.Min:2,m); if m[1]=' ' then m[1] := '0'; str(DT.Sec:2,s); if s[1]=' ' then s[1] := '0'; DateString := MonthName[DT.Month] + ' ' + d + ' ' + y + ' ' + h + ':' + m + ':' + s end; (* DateString *) (*--------------------------------------------------------------------*\ | NAME: GetSwitchChar | | | | This function will return the switch character (the character | | used to specify options) set in DOS. | \*--------------------------------------------------------------------*) function GetSwitchChar : char; var regs : registers; begin regs.AX := $3700; intr($21,regs); GetSwitchChar := chr(regs.DL) end; (* GetSwitchChar *) (*--------------------------------------------------------------------*\ | NAME: SetSwitchChar | | | | This function will set the switch character (the character | | used to specify options) set in DOS. | \*--------------------------------------------------------------------*) procedure SetSwitchChar ( c : char ); var regs : registers; begin regs.AX := $3701; regs.DL := ord(c); intr($21,regs) end; (* SetSwitchChar *) (*--------------------------------------------------------------------*\ | NAME: FixDirChars | | | | This function transforms the forward slash character ('/') into | | the backward slash character ('\') because version 5.0 of Turbo | | Pascal will do strange things if it finds the forward slash instead | | of the backward slash in a pathname. | \*--------------------------------------------------------------------*) function FixDirChars ( Original : string ) : string; var i : integer; begin WorkBuffer := Original; for i := 1 to length(Original) do if WorkBuffer[i] = ALT_DIR_SEPARATOR then WorkBuffer[i] := DIR_SEPARATOR; FixDirChars := WorkBuffer end; (* FixDirChars *) {$IFDEF VER40} (*--------------------------------------------------------------------*\ | NAME: FSplit | | | | This procedure splits a fully specified file name, and splits | | the filename into its components. | | | | EXTERNALS: | | const DIR_SEPARATOR, ALT_DIR_SEPARATOR (local to unit) | | function RCharPos (from My_Str unit) | \*--------------------------------------------------------------------*) procedure FSplit ( Path : PathStr; var Dir : DirStr; var Name : NameStr; var Ext : ExtStr ); var i,j : integer; begin i := RCharPos(DOS_SEP_CHARS,Path); if i=0 then begin Dir := ''; j := RCharPos(['.'],Path); if j=0 then begin Name := Path; Ext := '.' end else begin Name := copy(Path,1,j-1); Ext := copy(Path,j,length(Path)-j+1) end end else begin Dir := copy(Path,1,i); j := RCharPos(['.'],copy(Path,i+1,length(Path)-i)); if j=0 then begin Name := copy(Path,i+1,length(Path)-i); Ext := '.' end else begin Name := copy(Path,i+1,j-1); Ext := copy(Path,i+j,length(Path)-i) end end end; (* FSplit *) (*--------------------------------------------------------------------*\ | NAME: FExpand | | | | This function expands the file name to a fully qualified path | | file name. | | | | EXTERNALS: | | const DIR_SEPARATOR, ALT_DIR_SEPARATOR (local to unit) | | function RCharPos (from My_Str unit) | \*--------------------------------------------------------------------*) function FExpand ( Path : PathStr ) : PathStr; var i,j : integer; TmpStr : string; begin TmpStr := Path; (* strip off any drivespec and get pwd on drive *) if Pos(DSK_SEPARATOR,TmpStr) <> 2 then GetDir(0,WorkBuffer) else if not (Path[1] in Alphabet) then GetDir(0,WorkBuffer) else begin GetDir(ord(UpCase(TmpStr[1]))-ord('A')+1, WorkBuffer); TmpStr := copy(TmpStr,3,length(TmpStr)-2) end; (* strip trailing slash on pwd of selected drive *) if WorkBuffer[length(WorkBuffer)] in DIR_CHARS then dec(WorkBuffer[0]); (* handle reference to root *) if TmpStr[1] in DIR_CHARS then begin WorkBuffer[0] := #2; while TmpStr[1] in DIR_CHARS do TmpStr := copy(TmpStr,2,length(TmpStr)-1) end; i := CharPos(DIR_CHARS,TmpStr); while i<>0 do begin if copy(TmpStr,1,i-1)='.' then TmpStr := copy(TmpStr,3,length(TmpStr)-2) else if copy(TmpStr,1,i-1)='..' then begin TmpStr := copy(TmpStr,4,length(TmpStr)-2); j := RCharPos(DIR_CHARS,WorkBuffer); if j>0 then dec(WorkBuffer[0],length(WorkBuffer)-j+1) end else begin WorkBuffer := WorkBuffer + DIR_SEPARATOR + copy(TmpStr,1,i-1); TmpStr := copy(TmpStr,i+1,length(TmpStr)-i) end; i := CharPos(DIR_CHARS,TmpStr); end; FExpand := WorkBuffer + DIR_SEPARATOR + TmpStr end; (* FExpand *) {$ENDIF} (*--------------------------------------------------------------------*\ | NAME: PathName | | | | This function returns the path portion of the full path filename.| | This function interprets both '/' and '\' as directory separators. | | | | EXTERNALS: | | const DIR_SEPARATOR, ALT_DIR_SEPARATOR, DSK_SEPARATOR | | (local to unit) | | function rpos (from My_Str unit) | | function GetDir (from DOS unit) | \*--------------------------------------------------------------------*) function PathName( full : string ) : string; var i : integer; begin i := rpos(DIR_SEPARATOR,full); if i <> 0 then PathName := copy(full,1,i-1) else begin i := rpos(ALT_DIR_SEPARATOR,full); if i <> 0 then PathName := copy(full,1,i-1) else begin i := pos(DSK_SEPARATOR,full); if i = 2 then PathName := copy(full,1,2) else begin GetDir(0,full); if full[length(full)] = DIR_SEPARATOR then full[0] := chr(length(full)-1); PathName := full end end end end; (* PathName *) (*--------------------------------------------------------------------*\ | NAME: BaseName | | | | This function returns the base portion of a full path filename. | | This function interprets both '/' and '\' as directory separators. | | | | EXTERNALS: | | const DIR_SEPARATOR, ALT_DIR_SEPARATOR, DSK_SEPARATOR | | (local to unit) | | function rpos (from My_Str unit) | \*--------------------------------------------------------------------*) function BaseName( full : string ) : string; var i : integer; begin i := rpos(DIR_SEPARATOR,full); if i <> 0 then BaseName := copy(full,i+1,length(full)-i) else begin i := rpos(ALT_DIR_SEPARATOR,full); if i <> 0 then BaseName := copy(full,i+1,length(full)-1) else begin i := rpos(DSK_SEPARATOR,full); if i <> 0 then BaseName := copy(full,i+1,length(full)-i) else BaseName := full end end end; (* BaseName *) (*--------------------------------------------------------------------*\ | NAME: File_Exists | | | | This boolean function returns TRUE if the file exists. | \*--------------------------------------------------------------------*) function File_Exists ( s : string ) : boolean; var f : text; begin assign(f,s); {$i-} reset(f); {$i+} if ioresult <> 0 then File_Exists := FALSE else begin close(f); File_Exists := TRUE end end; (* File_Exists *) {$IFDEF VER40} const EnvironmentSeg : word = 0; (*--------------------------------------------------------------------*\ | Shared variables for GetEnv, EnvCount, and EnvStr. | \*--------------------------------------------------------------------*) const i : word = 0; Count : integer = 0; found : boolean = FALSE; (*--------------------------------------------------------------------*\ | NAME: GetEnv | | | | This routine is patterned after the UNIX operating system call | | which obtains the value of a specified environment variable. A | | process will inherit a copy of the parent's environment. Often, the | | environment variables are used to communicate between processes. | | | | EXTERNALS: | | word EnvironmentSeg (local to unit) | | integer i (local to unit) | | string WorkBuffer (local to unit) | | boolean found (local to unit) | \*--------------------------------------------------------------------*) function GetEnv( envvar : string ) : string; begin (* GetEnv *) i := 0; found := false; while not (found or (mem[EnvironmentSeg:i]=0)) do begin WorkBuffer := ''; while mem[EnvironmentSeg:i] <> ord('=') do begin WorkBuffer := WorkBuffer + chr(mem[EnvironmentSeg:i]); inc(i) end; inc(i); (* skip '=' *) found := WorkBuffer = envvar; WorkBuffer := ''; while mem[EnvironmentSeg:i] <> 0 do begin WorkBuffer := WorkBuffer + chr(mem[EnvironmentSeg:i]); inc(i) end; inc(i) (* skip '\0' *) end; if found then GetEnv := WorkBuffer else GetEnv := '' end; (* GetEnv *) (*--------------------------------------------------------------------*\ | NAME: EnvCount | | | | This function returns the number of environment strings set in | | the environment. | | | | EXTERNALS: | | word EnvironmentSeg (local to unit) | | integer i (local to unit) | | string WorkBuffer (local to unit) | | boolean found (local to unit) | \*--------------------------------------------------------------------*) function EnvCount : integer; begin i := 0; Count := 0; while (mem[EnvironmentSeg:i]<>0) do begin while mem[EnvironmentSeg:i] <> 0 do inc(i); inc(i); (* skip '\0' *) inc(Count) end; EnvCount := Count end; (* EnvCount *) (*--------------------------------------------------------------------*\ | NAME: EnvStr | | | | This function returns the Index'th environment string. The | | string returned by this function is of the form 'VAR=VALUE.' If | | Index is beyond the last environment, then it will return a null | | string. | | | | EXTERNALS: | | word EnvironmentSeg (local to unit) | | integer i (local to unit) | | integer Count (local to unit) | | string WorkBuffer (local to unit) | | boolean found (local to unit) | \*--------------------------------------------------------------------*) function EnvStr( Index : integer ) : string; begin i := 0; Count := 0; if (Count>=Index) or (mem[EnvironmentSeg:i]=0) then EnvStr := '' else begin repeat WorkBuffer := ''; inc(Count); while mem[EnvironmentSeg:i] <> 0 do begin WorkBuffer := WorkBuffer + chr(mem[EnvironmentSeg:i]); inc(i) end; inc(i) (* skip '\0' *) until ((Count = Index) or (mem[EnvironmentSeg:i]=0)); if Count = Index then EnvStr := WorkBuffer else EnvStr := '' end end; (* EnvStr *) {$ENDIF} (*--------------------------------------------------------------------*\ | NAME: GetProgramName | | | | This routine is used to obtain the full path name of the process | | with the given prefix segment. | | | | EXTERNALS: | | type PSPtype (local to unit) | \*--------------------------------------------------------------------*) function GetProgramName( PrefixSeg : word ) : string; const WorkBuffer : string[255] = ''; var i, EnvSeg : word; begin i := 0; EnvSeg := PSPtype(ptr(PrefixSeg,$0)^).EnvironmentSeg; while memw[EnvSeg:i] <> 0 do i := i + 1; i := i + 4; WorkBuffer := ''; while mem[EnvSeg:i] <> 0 do begin WorkBuffer := WorkBuffer + chr(mem[EnvSeg:i]); i := i + 1 end; GetProgramName := WorkBuffer end; (* GetProgramName *) (*--------------------------------------------------------------------*\ | NAME: GetMCBhead | | | | This procedure is used for retrieving the address of the first | | MCB (Memory Control Block). This routine makes use of an undocu- | | mented DOS service ($52). | | | | EXTERNALS: | | type MCB_pointer (local to unit) | | type registers (from DOS) | | procedure DecPtr (from PtrMath) | \*--------------------------------------------------------------------*) procedure GetMCBhead ( var MCBhead : MCB_pointer ); var regs : registers; TmpPtr : ^word; begin fillchar(regs,sizeof(regs),$0); regs.AH := $52; intr($21,regs); TmpPtr := ptr(regs.ES,regs.BX); DecPtr(pointer(TmpPtr),2); MCBhead := ptr(TmpPtr^,$0) end; (* GetMCBhead *) (*--------------------------------------------------------------------*\ | NAME: AdvanceMCBptr | | | | This procedure is used for advancing the pointer to an MCB so | | that it points to the next one in the chain. | | | | EXTERNALS: | | type MCB_pointer (local to unit) | \*--------------------------------------------------------------------*) procedure AdvanceMCBptr ( var MCBhead : MCB_pointer ); begin MCBhead := ptr(seg(MCBhead^)+MCBhead^.Size+1, ofs(MCBhead^)) end; (* AdvanceMCBptr *) (*====================================================================*\ || DOS_SVC unit initialization code || ||--------------------------------------------------------------------|| || EXTERNALS: || || function PrefixSeg || \*====================================================================*) var Junk : ExtStr; begin {$IFDEF VER40} FSplit(GetProgramName(PrefixSeg),ExecPath,ExecName,Junk); EnvironmentSeg := PSPtype(ptr(PrefixSeg,$0)^).EnvironmentSeg {$ELSE} FSplit(ParamStr(0),ExecPath,ExecName,Junk) {$ENDIF} End. ---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ---- ---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ---- unit MyMath; (*====================================================================*\ || MODULE NAME: MyMath || || DEPENDENCIES: System.TPU || || LAST MOD ON: 8904.05 || || PROGRAMMER: Naoto Kimura || || || || DESCRIPTION: This unit contains miscallaneous math routines. || || Among them are the 3-D coordinate manipulation || || routines. || \*====================================================================*) {$S+} {Stack checking on} {$R+} {Range checking on} {$D-} {Debug info off} {$I-} {I/O checking off} Interface function max( a, b : integer ) : integer; function min( a, b : integer ) : integer; function sgn( x : real ) : integer; function dmax( a, b : real ) : real; function dmin( a, b : real ) : real; function dsgn( d : real ) : real; function modulo( num, modulus :integer ) : integer; function rad2deg( r : real ) : real; function deg2rad( d : real ) : real; type coord3d = record x, y, z : real end; const X_AXIS : coord3d = ( x:1.0; y:0.0; z:0.0 ); Y_AXIS : coord3d = ( x:0.0; y:1.0; z:0.0 ); Z_AXIS : coord3d = ( x:0.0; y:0.0; z:1.0 ); ZERO_VEC : coord3d = ( x:0.0; y:0.0; z:0.0 ); function DistBetween ( var s1, s2 : coord3d ) : real; function VecLength (var a : coord3d) : real; procedure Normalize (var v : coord3d); procedure ScalarMult (var v : coord3d; n : real ); procedure ScalarDivs (var v : coord3d; n : real ); procedure VecDiff (var a, b, c : coord3d); procedure VecSum (var a, b, c : coord3d); procedure CrossProduct ( a, b : coord3d; var c : coord3d ); function DotProduct (var a,b : coord3d ) : real; function AngleBetween (var a,b : coord3d ) : real; procedure rot_Z ( var v : coord3d; t : real ); procedure rot_Y ( var v : coord3d; t : real ); procedure rot_X ( var v : coord3d; t : real ); Implementation function max( a, b : integer ) : integer; begin if a > b then max := a else max := b end; (* max *) function min( a, b : integer ) : integer; begin if a > b then min := b else min := a end; (* min *) function sgn( x : real ) : integer; begin if x=0 then sgn := 0 else if x>0 then sgn := 1 else sgn := -1 end; (* sgn *) function dmax( a, b : real ) : real; begin if a > b then dmax := a else dmax := b end; (* dmax *) function dmin( a, b : real ) : real; begin if a > b then dmin := b else dmin := a end; (* dmin *) function dsgn( d : real ) : real; begin if d=0.0 then dsgn := 0.0 else if d>0.0 then dsgn := 1.0 else dsgn := -1.0 end; (* dsgn *) function modulo( num, modulus :integer ) : integer; begin num := num mod modulus; if num < 0 then modulo := num + modulus else modulo := num end; (* modulo *) function rad2deg( r : real ) : real; begin rad2deg := r * 180.0 / PI end; (* rad2deg *) function deg2rad( d : real ) : real; begin deg2rad := PI * d / 180.0 end; (* deg2rad *) function DistBetween ( var s1, s2 : coord3d ) : real; begin DistBetween := sqrt( sqr( s1.x - s2.x ) + sqr( s1.y - s2.y ) + sqr( s1.z - s2.z ) ) end; (* DistBetween *) function VecLength (var a:coord3d) : real; begin VecLength := sqrt(sqr(a.x) + sqr(a.y) + sqr(a.z)) end; (* VecLength *) procedure Normalize (var v : coord3d); var l : real; begin l := VecLength(v); if abs(l) > 0.0 then l := 1 / l else l := 0; v.x := v.y * l; v.y := v.y * l; v.y := v.y * l end; (* Normalize *) procedure ScalarMult (var v : coord3d; n : real ); begin v.x := v.x * n; v.y := v.y * n; v.z := v.z * n end; (* ScalarMult *) procedure ScalarDivs (var v : coord3d; n : real ); begin if n <> 0 then begin v.x := v.x / n; v.y := v.y / n; v.z := v.z / n end end; (* ScalarMult *) procedure VecDiff (var a, b, c : coord3d); begin c.x := a.x - b.x; c.y := a.y - b.y; c.z := a.z - b.z end; (* VecDiff *) procedure VecSum (var a, b, c : coord3d); begin c.x := a.x + b.x; c.y := a.y + b.y; c.z := a.z + b.z end; (* VecSum *) procedure CrossProduct ( a, b : coord3d; var c : coord3d ); begin c.x := a.y*b.z-b.y*a.z; c.y := -a.x*b.z+b.x*a.z; c.z := a.x*b.y-a.y*b.x end; (* CrossProduct *) function DotProduct (var a,b : coord3d ) : real; begin DotProduct := a.x*b.x+a.y*b.y+a.z*b.z end; (* DotProduct *) function AngleBetween (var a,b : coord3d ) : real; var d : coord3d; p, ang, c, s : real; begin p := VecLength(a) * VecLength(b); if p = 0 then AngleBetween := 0 else begin c := DotProduct(a,b) / p; (* can be <0, >0, =0 *) CrossProduct(a,b,d); s := VecLength(d) / p; (* always >=0 *) if c=0 then (* Y-axis *) if s=0 then AngleBetween := 0 else AngleBetween := PI/2 else begin ang := arctan(s/c); if c<0 then ang:= ang + PI; (* quadrant 2 *) AngleBetween := ang end end end; (* AngleBetween *) procedure rot_Z ( var v : coord3d; t : real ); var old : coord3d; begin old := v; v.x := old.x * cos(t) - old.y * sin(t); v.y := old.y * cos(t) + old.x * sin(t) end; (* rot_Z *) procedure rot_Y ( var v : coord3d; t : real ); var old : coord3d; begin old := v; v.z := old.z * cos(t) - old.x * sin(t); v.x := old.x * cos(t) + old.z * sin(t) end; (* rot_Y *) procedure rot_X ( var v : coord3d; t : real ); var old : coord3d; begin old := v; v.y := old.y * cos(t) - old.z * sin(t); v.z := old.z * cos(t) + old.y * sin(t) end; (* rot_X *) End. ---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ---- ---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ---- unit MyStr; (*====================================================================*\ || MODULE NAME: MyStr || || DEPENDENCIES: System.TPU, MyMath.TPU || || LAST MOD ON: 8904.21 || || PROGRAMMER: Naoto Kimura || || || || DESCRIPTION: This is a library of string handling routines. || \*====================================================================*) {$R-} {Range checking off} {$S+} {Stack checking on} {$D-} {Debug info off} {$I-} {I/O checking off} {$N-} {No numeric coprocessor} Interface uses MyMath; type CharSet = set of char; const WhiteSpace : CharSet = [' ',#9,#10,#13]; UpperCase : CharSet = ['A'..'Z']; LowerCase : CharSet = ['a'..'z']; Alphabet : CharSet = ['A'..'Z','a'..'z']; Numeric : CharSet = ['0'..'9']; AlphaNum : CharSet = ['A'..'Z','a'..'z','0'..'9']; (*--------------------------------------------------------------------*\ | NAME: RPos | | | | This function returns the lastmost matching position of "needle" | | in "HayStack." | \*--------------------------------------------------------------------*) function RPos( needle, HayStack : string ) : byte; (*--------------------------------------------------------------------*\ | NAME: CharPos | | | | This routine gives the first position of specified characters in | | the string. | \*--------------------------------------------------------------------*) function CharPos( Srch : CharSet; HayStack : string ) : byte; (*--------------------------------------------------------------------*\ | NAME: RCharPos | | | | This routine gives the last position of specified characters in | | the string. | \*--------------------------------------------------------------------*) function RCharPos( Srch : CharSet; HayStack : string ) : byte; (*--------------------------------------------------------------------*\ | NAME: RightJustify | | | | This function returns a string that has the string "Original" | | right justified in a field of length "width" of the character "pad". | | If the string is longer than the field, the string will be truncated | | at the field width. | \*--------------------------------------------------------------------*) function RightJustify( Original : string; width : byte; pad : char ) : string; (*--------------------------------------------------------------------*\ | NAME: LeftJustify | | | | This function returns a string that has the string "Original" | | left justified in a field of length "width" of the character "pad". | | If the string is longer than the field, the string will be truncated | | at the field width. | \*--------------------------------------------------------------------*) function LeftJustify( Original : string; width : byte; pad : char ) : string; (*--------------------------------------------------------------------*\ | NAME: Center | | | | This function returns a string that has the string "Original" | | centered in a field of length "width" of the character "filler". If | | the string is longer than the field, the string will be truncated at | | the field width. | \*--------------------------------------------------------------------*) function Center( Original : string; width : byte; filler : char ) : string; (*--------------------------------------------------------------------*\ | NAME: Strip | | | | This function strips off the specified characters from Original. | | Leading characters to strip off are specified in LeadSet and | | trailing characters to strip off are specifed in TrailSet. | \*--------------------------------------------------------------------*) function Strip( Original : string; LeadSet, TrailSet : CharSet ) : string; (*--------------------------------------------------------------------*\ | NAME: SkipStr | | | | This routine is used to grab a copy of the string, past the | | location of the given pattern. | \*--------------------------------------------------------------------*) function SkipStr( Original, pattern : string ) : string; (*--------------------------------------------------------------------*\ | NAME: Reverse | | | | This function returns a copy of a string that is reversed. | \*--------------------------------------------------------------------*) function Reverse( Original : string ) : string; Implementation (*--------------------------------------------------------------------*\ | NAME: RPos | | | | This function returns the lastmost matching position of "needle" | | in "HayStack." | \*--------------------------------------------------------------------*) function RPos( needle, HayStack : string ) : byte; var i : byte; begin if length(HayStack) = 0 then RPos := 0 else if length(needle) = 0 then RPos := length(HayStack) else if length(needle) > length(HayStack) then RPos := 0 else begin for i := length(HayStack)-length(needle)+1 downto 1 do if copy(HayStack,i,length(needle)) = needle then begin RPos := i; exit end; RPos := 0 end end; (* RPos *) (*--------------------------------------------------------------------*\ | NAME: CharPos | | | | This routine gives the first position of specified characters in | | the string. | \*--------------------------------------------------------------------*) function CharPos( Srch : CharSet; HayStack : string ) : byte; var i : byte; begin if (HayStack = '') or (Srch = []) then CharPos := 0 else begin for i := 1 to length(HayStack) do if HayStack[i] in Srch then begin CharPos := i; exit end; CharPos := 0 end end; (* CharPos *) (*--------------------------------------------------------------------*\ | NAME: RCharPos | | | | This routine gives the last position of specified characters in | | the string. | \*--------------------------------------------------------------------*) function RCharPos( Srch : CharSet; HayStack : string ) : byte; var i : byte; begin if (HayStack = '') or (Srch = []) then RCharPos := 0 else begin for i := length(HayStack) downto 1 do if HayStack[i] in Srch then begin RCharPos := i; exit end; RCharPos := 0 end end; (* RCharPos *) (*--------------------------------------------------------------------*\ | NAME: RightJustify | | | | This function returns a string that has the string "Original" | | right justified in a field of length "width" of the character "pad". | | If the string is longer than the field, the string will be truncated | | at the field width. | \*--------------------------------------------------------------------*) function RightJustify( Original : string; width : byte; pad : char ) : string; var result : string; begin fillchar(result[1],width,pad); result[0] := char(width); move(Original[1],result[max(width-length(Original)+1,1)], min(length(Original),width)); RightJustify := result end; (* RightJustify *) (*--------------------------------------------------------------------*\ | NAME: LeftJustify | | | | This function returns a string that has the string "Original" | | left justified in a field of length "width" of the character "pad". | | If the string is longer than the field, the string will be truncated | | at the field width. | \*--------------------------------------------------------------------*) function LeftJustify( Original : string; width : byte; pad : char ) : string; var result : string; begin fillchar(result[1],width,pad); result[0] := char(width); move(Original[1],result[min(width-length(Original)+1,1)], min(length(Original),width)); LeftJustify := result end; (* LeftJustify *) (*--------------------------------------------------------------------*\ | NAME: Center | | | | This function returns a string that has the string "s" centered | | in a field of length "len" of the character "filler". If the string | | is longer than the field, the string will be truncated at the field | | width. | \*--------------------------------------------------------------------*) function Center( Original : string; width : byte; filler : char ) : string; var off : byte; result : string; begin result[0] := char(width); fillchar(result[1],width,filler); off := max(((width-length(Original)) div 2)+1,1); move(Original[1],result[off],min(length(Original),width)); Center := result end; (* Center *) (*--------------------------------------------------------------------*\ | NAME: Strip | | | | This function strips off the specified characters from Original. | | Leading characters to strip off are specified in LeadSet and | | trailing characters to strip off are specifed in TrailSet. | \*--------------------------------------------------------------------*) function Strip( Original : string; LeadSet, TrailSet : CharSet ) : string; var Left, Right : byte; stop : boolean; begin Left := 1; Right := length(Original); if Left>Right then stop := FALSE else stop := not (Original[Left] in LeadSet) and not (Original[Right] in TrailSet); while not (stop or (Right<Left)) do begin stop := TRUE; if Original[Left] in LeadSet then begin inc(Left); stop := FALSE end; if Original[Right] in TrailSet then begin dec(Right); stop := FALSE end end; if stop then Strip := copy(Original,Left,Right-Left+1) else Strip := '' end; (* Strip *) (*--------------------------------------------------------------------*\ | NAME: SkipStr | | | | This routine is used to grab a copy of the string, past the | | location of the given pattern. | \*--------------------------------------------------------------------*) function SkipStr( original, pattern : string ) : string; begin SkipStr := copy(original, pos(pattern,original)+length(pattern), length(original)) end; (* SkipStr *) (*--------------------------------------------------------------------*\ | NAME: Reverse | | | | This function returns a copy of a string that is reversed. | \*--------------------------------------------------------------------*) function Reverse( Original : string ) : string; var i,j : byte; result : string; begin result[0] := Original[0]; j := length(Original); for i := 1 to length(Original) do begin result[i] := Original[j]; dec(j) end; Reverse := result end; (* Reverse *) end. ---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ---- //-n-\\ Naoto Kimura _____---=======---_____ (abcscnuk@csuna.csun.edu) ====____\ /.. ..\ /____==== // ---\__O__/--- \\ Enterprise... Surrender or we'll \_\ /_/ send back your *&^$% tribbles !!