Program Tab2Space; { Language : Turbo Pascal 2.00A Author: Rick Housh 5811 W. 85th Terr. Overland Park, KS 66207 Compuserve PIN 72466,212 } {Replaces tabs in a text file with a number of spaces which is the difference between the current place on the line and the next fixed tab setting. Tab settings can be between 1 and 9. The default is eight. Unlike other similar programs, does not just add a specified number of spaces to the current position, but advances only to the next fixed tab space. For safety, requires an unused file name for the output file, and leaves the input file intact. It is up to the user to rename and delete the files, as required. Does not accept wildcard characters in file names, for obvious reasons. Does not allow the console as either the input or output file, and does not allow the printer as input file, also for obvious reasons. Very portable code. Will compile for CP/M, MS-DOS, PC-DOS. } { First, the global declarations.} TYPE AnyString = STRING [255]; VAR Infile, Outfile: Text; Str: AnyString; ch: Char; F1, F2: AnyString; Err, i, j, k, l, t, x, y, x1, y1: Integer; Tabs: Real; Ans, P3: STRING [1]; PROCEDURE UpString(VAR Strg: AnyString); {Upcases a string. Syntax is Upstring(whatever)} {AnyString is Type String[255]} VAR ch: Char; st: AnyString; i: Integer; BEGIN st := ''; FOR i := 1 TO length(Strg) DO BEGIN ch := upcase(Strg[i]); st := st + ch; END; Strg := st; END; {Procedure UpString} PROCEDURE AbortIfAnyWildCards(VAR FName: AnyString); BEGIN IF (Pos('?', FName) <> 0) OR (Pos('*', FName) <> 0) THEN BEGIN WriteLn(#7'Sorry, no wild cards allowed.'); Halt; END; IF FName = '' THEN BEGIN WriteLn(#7'No input file specified. Aborting...'); Halt; END; END; {Procedure AbortIfAnyWildCards} PROCEDURE AbortIfNullInput(VAR FName: AnyString); BEGIN IF FName = '' THEN BEGIN WriteLn(#7'No file name specified. Aborting...'); Halt; END; END; {Procedure AbortIfNullInput} BEGIN {Main Program} {First, initialize variables} P3 := ''; F1 := ''; F2 := ''; l := 0; t := 0; Tabs := 0.0; {Now, display some information.} WriteLn( 'This program, given the name of an existing file, and the name of' ); WriteLn( 'a different output file, will convert all tabs in the input file' ); WriteLn( 'to spaces in the output file. Unlike other such programs, it does' ); WriteLn( 'not insert X number of spaces for each tab, but advances to the next' ); WriteLn( 'fixed tab. E.G., if the tab is encountered at space 12 on the line,' ); WriteLn( 'and tabs are set at 8, only 4 spaces will be inserted in place of' ); WriteLn('the tab in the output file. Looks much nicer that way.'); {Now, get user input.} WriteLn; Write('Name of input file: '); ReadLn(F1); UpString(F1); AbortIfAnyWildCards(F1); AbortIfNullInput(F1); IF (F1 = 'LST') OR (F1 = 'LST:') THEN {If some idiot is using the printer} {as input, then abort.} BEGIN WriteLn('The printer is not an input device!'); WriteLn('Aborting.'); Halt; END; Assign(Infile, F1); {$I-} Reset(Infile); {Open infile for read} {$I+} Err := IOResult; IF Err <> 0 THEN {If not exist then error message and exit.} BEGIN WriteLn(#7'Input file ', F1, ' not found.'); Halt; END; Write('Name of output file: '); ReadLn(F2); UpString(F2); AbortIfAnyWildCards(F2); AbortIfNullInput(F2); IF (F1 = F2) THEN {If infile and outfile same then} BEGIN {abort with error message.} WriteLn(#7'You cannot copy a file to itself.'); WriteLn('Input and Output files must have different names.'); Halt; END; IF (F1 = 'CON') OR (F2 = 'CON') OR (F1 = 'CON:') OR (F2 = 'CON') THEN BEGIN {If the console was specified as either} {the input or output device, abort.} WriteLn('You cannot use the console as input or output.'); WriteLn('Aborting.'); END; Assign(Outfile, F2); {$I-} Reset(Outfile); {Open outfile for read (Just to see if it's there)} {$I+} Err := IOResult; IF Err = 0 THEN {If exist, ask whether to overwrite.} BEGIN WriteLn('Output file ', F2, ' already exists.'); Write('Want to overwrite it [Y/N]? '); REPEAT Read(kbd, Ans); IF Ans <> '' THEN Ans := upcase(Ans); UNTIL (Ans = 'Y') OR (Ans = 'N'); IF Ans = 'N' THEN {If not OK to overwrite outfile} BEGIN {then clean up, and} Close(Infile); Close(Outfile); Halt; END; END; {If outfile not exist or OK to overwrite, then open.} WriteLn; {$I-} Rewrite(Outfile); {$I+} Err := IOResult; IF Err = $F1 THEN {If target directory is full, then exit } BEGIN WriteLn('Directory on target disk is full.'); WriteLn('Program aborted.', #7); Close(Infile); Halt; END; {Now find out how many spaces the user wants to assign to tabs.} Write( 'Number of spaces (1 - 9) to substitute for each tab : ' ); ReadLn(P3); IF (P3 = '') OR (P3 < '0') OR (P3 > '9') THEN P3 := '8';{If anything is wrong default to 8.} ch := P3; {Convert String to char to use in Set} IF ch IN ['1'..'9'] THEN {If ASCII 1 - 9 use it else default to 8.} val(ch, i, Err) {Turbo P. requires Err, although it's impossible} ELSE i := 8; {O.K. NOW WE DO IT!} ClrScr; WriteLn(' TAB2SPC'); WriteLn(' By Rick Housh'); WriteLn; {Prepare for messages.} WriteLn('Replacing tabs in ', F1, ' with spaces in ', F2, '.'); IF i = 1 THEN WriteLn('Tab set at each single space.'); IF i = 2 THEN WriteLn('Tabs set at intervals of two spaces.'); IF i = 3 THEN WriteLn('Tabs set at each third space.'); IF i > 3 THEN WriteLn('Tabs set at each ', i, 'th space.'); WriteLn('Wait. Processing.'); x := 1; y := 6; GotoXY(x, y); Write('Lines processed: '); x := 18; GotoXY(x, y); Write(' 0'); {Write initial zero for # of lines} x1 := 1; {Screen pos for tab value} y1 := 7; GotoXY(x1, y1); Write('Tabs converted: '); x1 := 18; GotoXY(x1, y1); Write(' 0'); {Write initial val. for tabs converted.} WHILE NOT EOF(Infile) DO BEGIN {$I-} ReadLn(Infile, Str); {Now read a line from infile.} {$I+} Err := IOResult; IF Err = $F0 THEN {If target disk has no more space, then exit.} BEGIN WriteLn; WriteLn('Target disk full. Program aborted.'); WriteLn('Output file ', F2, ' erased.', #7); Close(Infile); Close(Outfile); Erase(Outfile); Halt; END; l := succ(l); {Increment line counter.} t := 0; {Set line tab counter to zero.} REPEAT {Algorithm to switch tabs to spaces} {The "guts" of the program.} k := Pos(#9, Str); {Get location of 1st tab} IF k > 0 THEN {If there is at least one} BEGIN {then} t := succ(t); {Increment tab count for this line} j := k; {Assign temp. variable to position in line} Delete(Str, j, 1); {Delete the tab in the line} Insert(' ', Str, j); {and replace it with the first space.} j := succ(j); {Increment place in line} {and adjust for difference} {caused by count from 1 instead} {of from zero.} WHILE ((j - 1) MOD i <> 0) DO BEGIN Insert(' ', Str, j); {Stick in a space at that} {position} j := succ(j); {and increment position in line} END; {then} {loop back and add another space,} {unless} END; {we are at tab stop (i).} UNTIL k = 0; {Loop back to see if another tab.} {$I-} WriteLn(Outfile, Str); {If not, then write line to outfile,} Err := IOResult; IF Err = $F0 THEN {If target disk full then abort} BEGIN WriteLn; WriteLn('Target disk full. Program aborted.'); WriteLn('Output file ', F2, ' erased.', #7); Close(Infile); Close(Outfile); Erase(Outfile); Halt; END; {Tell user how many lines have been processed.} GotoXY(x, y); ClrEol; Write(l: 8); {and print total lines,} {And how many tabs have been converted.} IF (Tabs + t) > Tabs THEN BEGIN {If we converted any tabs then} Tabs := Tabs + t; {increment the total number of tabs} GotoXY(x1, y1); ClrEol; Write(Tabs: 8: 0); {then print total tabs,} END; END; Close(Infile); {clean up,} Close(Outfile); GotoXY(x1, y1); WriteLn; WriteLn; WriteLn('Finished'); {and exit to DOS or CP/M, as may be.} WriteLn('Input file was ', F1); WriteLn('Output file is ', F2); Halt; END. {Main Program}