home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d02xx
/
d0270.lha
/
ColumnSet
/
column_set.MOD
< prev
next >
Wrap
Text File
|
1989-11-06
|
16KB
|
655 lines
MODULE column_set;
(* Copyright 1989 by Kent Paul Dolan, USENet: xanthian@well.sf.ca.us *)
(* Use it as you wish, but leave me a little credit somewhere in the result! *)
(* Developed with BENCHMARK Modula-2 from Avante-Garde Software *)
(* Purpose: to lay out "words" from a file of one word per line in as many *)
(* columns as will fit across the page with at least one space between *)
(* columns. Command usage is described further down in the code. This code *)
(* was written to provide a filter in a script for making the output of the *)
(* AmigaDOS "list lformat="%S" command look like the Unix "ls" output, but *)
(* looks useful as an independent command, as well. *)
(* It is a modest attempt at mixing a Unix and an AmigaDOS command format in *)
(* a small utility, while reasonably bullet-proofing the routine from command *)
(* line errors or i/o problems. The working guts of the program, without *)
(* the frills, takes up 1/3 the source and 1/2 the runtime space; this is an *)
(* exercise in doing the job "right", for the fun of it. Kent. *)
FROM System IMPORT argc, argv, StdInput, StdOutput;
FROM InOut IMPORT WriteString, WriteInt, WriteLn, Write, Read, OpenInputFile,
OpenOutputFile, Done, CloseInput, CloseOutput, EOL;
IMPORT Terminal;
FROM Terminal IMPORT eof;
FROM FileSystem IMPORT Response, File, Lookup, Close, Delete, ReadChar,
WriteChar;
FROM Strings IMPORT CompareStringCAP, LocateChar, CopyString, Relation;
CONST
DefaultWindowWidth = 77;
TempFileName = "T:column_set.temp";
TYPE
CommandLineParam = ARRAY [0..255] OF CHAR;
VAR
Ch: CHAR;
InFile,
OutFile: CommandLineParam;
MaxLength,
WindowWidth,
ThisLength,
MaxColumns,
NumColumns,
ThisColumn,
NumSpaces,
I: INTEGER;
TempFile: File;
UsingStdInput,
UsingStdOutput,
WentOK: BOOLEAN;
(*
** Usage: column_set [[FROM | -i] infile] [[TO | -o] outfile] [[WIDTH | -w] nn]
** [[MAXCOL | -m] mm]
**
** infile is the input file, one "word" per line;
** outfile is the output file, with the same words in the same order laid out
** in columns evenly across the page or screen;
** width is the number of character positions across the screen or page;
** default is 77 to fit a standard AmigaDOS window;
** maxcol limits the number of columns of words which will be set across the
** page to less than the maximum possible; default is (width+1)/2;
**
** where infile, outfile, width and maxcol are positional parameters unless the
** keywords are present. If no infile is given, standard input is used, and
** a temporary file "column_set.temp" is created and deleted to allow a second
** pass over the input data. If an infile is given, it is closed and reopened
** for the second pass over the data. If no outfile is given, standard output
** is used.
*)
PROCEDURE usage;
BEGIN
WriteLn;
WriteString
("Usage: column_set [FROM | -i] infile [TO | -o] outfile [WIDTH | -w] ww");
WriteLn;
WriteString
(" [MAXCOL | -m] mm]");
WriteLn;
WriteString
(" or: column_set < infile > outfile [{WIDTH | -w} ww] [{MAXCOL | -m} mm]");
WriteLn;
WriteString
(" or: column_set [(WIDTH | -w} ww] [{MAXCOL | -m} mm] infile outfile");
WriteLn;
WriteString
("or other likely combinations; infile, outfile, ww, and mm are positional");
WriteLn;
WriteString
("without keywords, position independent with keywords, and mixes are read");
WriteLn;
WriteString
("by trying to pick off first the keyword parmameters, then the missing");
WriteLn;
WriteString
("positional parameters in order from what is left over.");
WriteLn;
WriteString
("'Infile' is the input file, expected to contain one 'word' per line;");
WriteLn;
WriteString
("'outfile' is the output file, which will contain the same 'words' in the");
WriteLn;
WriteString
("same order laid out in as many even columns as will fit across the");
WriteLn;
WriteString
("page or screen; 'ww' is the width of the screen or page in character");
WriteLn;
WriteString
("positions; 'mm' is the most 'words' the user wants per line, to limit");
WriteLn;
WriteString
("them below the most possible in case a sparser layout is desired.");
WriteLn;
WriteString
("If infile and/or outfile are not specified, they default to standard");
WriteLn;
WriteString
("input and output; width (ww) defaults to 77 columns to match the");
WriteLn;
WriteString
("AmigaShell window, and maxcol (mm) defaults to (width+1)/2.");
WriteLn;
WriteString
(" /s/ Kent Paul Dolan, USENet: xanthian@well.sf.ca.us");
WriteLn;
WriteLn;
RETURN;
END usage;
PROCEDURE getcmdline
(VAR infile, outfile: ARRAY OF CHAR;
VAR width: INTEGER; VAR maxcol: INTEGER): BOOLEAN;
VAR
J, MyArgc, UnusedArgs: INTEGER;
Unused: ARRAY [0..15] OF INTEGER;
PROCEDURE getwidth(VAR width: INTEGER; token: ARRAY OF CHAR): BOOLEAN;
VAR
CharIndex, DigitValue: INTEGER;
BEGIN
CharIndex := 0;
(*
WriteString(argv^[J+1]^); WriteLn;
*)
WHILE (ORD(token[CharIndex]) <> 0) DO
DigitValue := LocateChar("0123456789",token[CharIndex],0,9);
IF ( DigitValue = -1 ) THEN
WriteString("column_set: Error -- non-digit in width parameter");
WriteLn;
RETURN FALSE;
ELSE
width := 10 * width + DigitValue;
END;
CharIndex := CharIndex + 1;
END;
RETURN TRUE;
END getwidth;
PROCEDURE getmaxcol(VAR maxcol: INTEGER; token: ARRAY OF CHAR): BOOLEAN;
VAR
CharIndex, DigitValue: INTEGER;
BEGIN
CharIndex := 0;
(*
WriteString(argv^[J+1]^); WriteLn;
*)
WHILE (ORD(token[CharIndex]) <> 0) DO
DigitValue := LocateChar("0123456789",token[CharIndex],0,9);
IF ( DigitValue = -1 ) THEN
WriteString("column_set: Error -- non-digit in maxcol parameter");
WriteLn;
RETURN FALSE;
ELSE
maxcol := 10 * maxcol + DigitValue;
END;
CharIndex := CharIndex + 1;
END;
RETURN TRUE;
END getmaxcol;
BEGIN (* getcmdline *)
CopyString(infile,"");
CopyString(outfile,"");
width := 0;
UnusedArgs := 0;
FOR J := 0 TO 15 BY 1 DO
Unused[J] := 0;
END;
MyArgc := argc;
(*
WriteString("MyArgc"); WriteInt(MyArgc,4); WriteLn;
*)
(* Pull out any keyword arguments from the command line: *)
J := 1;
WHILE (J < MyArgc) DO
(*
WriteString(argv^[J]^);
*)
IF
(
( CompareStringCAP( argv^[J]^ , "-i" ) = equal )
OR
( CompareStringCAP( argv^[J]^ , "FROM" ) = equal )
) THEN
IF ( J + 1 >= MyArgc ) THEN
WriteString
("column_set: Error -- '-i' or 'FROM' was last argument on command line");
WriteLn;
RETURN FALSE;
ELSE
CopyString(infile,argv^[J+1]^);
(*
WriteString(argv^[J+1]^); WriteLn;
*)
J := J + 2;
END;
ELSIF
(
( CompareStringCAP( argv^[J]^ , "-o" ) = equal )
OR
( CompareStringCAP( argv^[J]^ , "TO" ) = equal )
) THEN
IF ( J + 1 >= MyArgc ) THEN
WriteString
("column_set: Error -- '-o' or 'TO' was last argument on command line");
WriteLn;
RETURN FALSE;
ELSE
CopyString(outfile,argv^[J+1]^);
(*
WriteString(argv^[J+1]^); WriteLn;
*)
J := J + 2;
END;
ELSIF
(
( CompareStringCAP( argv^[J]^ , "-w" ) = equal )
OR
( CompareStringCAP( argv^[J]^ , "WIDTH" ) = equal )
) THEN
IF ( J + 1 >= MyArgc ) THEN
WriteString
("column_set: Error -- '-w' or 'WIDTH' was last argument on command line");
WriteLn;
RETURN FALSE;
ELSE
width := 0;
IF ( NOT getwidth(width,argv^[J + 1]^) ) THEN
RETURN FALSE;
END;
J := J + 2;
END;
ELSIF
(
( CompareStringCAP( argv^[J]^ , "-m" ) = equal )
OR
( CompareStringCAP( argv^[J]^ , "MAXCOL" ) = equal )
) THEN
IF ( J + 1 >= MyArgc ) THEN
WriteString
("column_set: Error -- '-m' or 'MAXCOL' was last argument on command line");
WriteLn;
RETURN FALSE;
ELSE
maxcol := 0;
IF ( NOT getmaxcol(maxcol,argv^[J + 1]^) ) THEN
RETURN FALSE;
END;
J := J + 2;
END;
ELSE
Unused[UnusedArgs] := J;
UnusedArgs := UnusedArgs + 1;
J := J + 1;
END;
END;
(* Pull out any remaining positional arguments from the command line: *)
J := 0;
IF ( ( CompareStringCAP(infile,"") = equal ) AND (J < UnusedArgs) ) THEN
CopyString(infile,argv^[Unused[J]]^);
J := J + 1;
END;
IF ( ( CompareStringCAP(outfile,"") = equal ) AND (J < UnusedArgs) ) THEN
CopyString(outfile,argv^[Unused[J]]^);
J := J + 1;
END;
IF ( width = 0 ) AND (J < UnusedArgs) THEN
IF ( NOT getwidth(width,argv^[Unused[J]]^) ) THEN
RETURN FALSE;
END;
J := J + 1;
END;
IF ( width = 0) THEN
width := DefaultWindowWidth;
END;
IF ( maxcol = 0 ) AND (J < UnusedArgs) THEN
IF ( NOT getmaxcol(maxcol,argv^[Unused[J]]^) ) THEN
RETURN FALSE;
END;
J := J + 1;
END;
IF ( maxcol = 0 ) THEN
maxcol := (width + 1) DIV 2;
END;
(*
WriteLn;
*)
RETURN TRUE;
END getcmdline;
PROCEDURE writebitch;
BEGIN
WriteString("column_set: Error -- problem writing OutFile = ");
WriteString(OutFile);
WriteLn;
IF (UsingStdInput) THEN
Close(TempFile);
Delete(TempFileName);
END;
IF (NOT UsingStdOutput) THEN
CloseOutput;
END;
RETURN;
END writebitch;
BEGIN (* column_set *)
IF ( argc > 1 ) THEN
IF ( CompareStringCAP(argv^[1]^,"?") = equal ) THEN
usage;
RETURN;
END;
END;
IF ( NOT getcmdline(InFile,OutFile,WindowWidth,MaxColumns) ) THEN
WriteString("column_set: Error -- unable to correctly parse command line!");
WriteLn;
usage;
RETURN;
(*
ELSE
WriteString("InFile = "); WriteString(InFile); WriteLn;
WriteString("OutFile = "); WriteString(OutFile); WriteLn;
WriteString("WindowWidth = "); WriteInt(WindowWidth,1); WriteLn;
WriteString("MaxColumns = "); WriteInt(MaxColumns,1); WriteLn;
*)
END;
IF (CompareStringCAP(InFile,"") = equal) THEN
UsingStdInput := TRUE;
ELSE
UsingStdInput := FALSE;
END;
IF (CompareStringCAP(OutFile,"") = equal) THEN
UsingStdOutput := TRUE;
ELSE
UsingStdOutput := FALSE;
END;
IF ( UsingStdInput) THEN
Lookup(TempFile,TempFileName,TRUE);
IF (TempFile.res <> done) THEN
WriteString
("column_set: Error -- unable to open new work file T:column_set.temp");
WriteLn;
RETURN;
END;
(*
WriteString("column_set: taking data from standard input"); WriteLn;
*)
ELSE
OpenInputFile(InFile);
IF (NOT Done) THEN
WriteString("column_set: Error -- file open failed for InFile = ");
WriteString(InFile); WriteLn;
RETURN;
END;
(*
WriteString("column_set: taking data from a named file"); WriteLn;
*)
END;
MaxLength := 0;
ThisLength := 0;
WentOK := TRUE;
IF ( UsingStdInput ) THEN
Terminal.Read(Ch);
IF (eof) THEN
WriteString
("column_set: Error -- standard input looks empty in counting pass");
WentOK := FALSE;
END;
ELSE
Read(Ch);
IF (NOT Done) THEN
WriteString("column_set: Error -- input file looks empty in counting pass");
WentOK := FALSE;
END;
END;
IF (NOT WentOK) THEN
WriteLn;
Close(TempFile);
Delete(TempFileName);
IF (NOT UsingStdInput) THEN
CloseInput;
END;
RETURN;
END;
LOOP
IF ( UsingStdInput ) THEN
WriteChar(TempFile,Ch);
IF (TempFile.res = notdone) THEN
WriteString
("column_set: Error -- problem writing to file T:column_set.temp");
WriteLn;
Close(TempFile);
Delete(TempFileName);
RETURN;
END;
END;
IF (Ch <> EOL) THEN
ThisLength := ThisLength + 1;
ELSE
IF (ThisLength > MaxLength) THEN
MaxLength := ThisLength;
END;
ThisLength := 0;
END;
IF (UsingStdInput) THEN
Terminal.Read(Ch);
IF (eof) THEN
EXIT;
END;
ELSE
Read(Ch);
IF (NOT Done) THEN
EXIT;
END;
END;
END;
IF ( UsingStdInput ) THEN
Close(TempFile);
IF (TempFile.res = notdone) THEN
WriteString
("column_set: Error -- unable to close file T:column_set.temp after");
WriteString(" counting pass"); WriteLn;
RETURN;
END;
Lookup(TempFile,TempFileName,FALSE);
IF (TempFile.res <> done) THEN
WriteString
("column_set: Error -- unable to open file T:column_set.temp before");
WriteString(" writing pass"); WriteLn;
Delete(TempFileName);
RETURN;
END;
ELSE
CloseInput;
OpenInputFile(InFile);
IF (NOT Done) THEN
WriteString("column_set: Error -- File reopen failed for InFile = ");
WriteString(InFile); WriteLn;
RETURN;
END;
END;
IF (NOT UsingStdOutput) THEN
OpenOutputFile(OutFile);
IF (NOT Done) THEN
WriteString("column_set: Error -- file open failed for OutFile = ");
WriteString(OutFile); WriteLn;
Close(TempFile);
Delete(TempFileName);
RETURN;
END;
END;
NumColumns := (WindowWidth + 1) DIV (MaxLength + 1);
IF (NumColumns > MaxColumns) THEN
NumColumns := MaxColumns;
END;
IF (NumColumns > 1) THEN
NumSpaces := (WindowWidth - (NumColumns * MaxLength)) DIV (NumColumns - 1);
ELSE
NumSpaces := 0;
END;
ThisLength := 0;
ThisColumn := 0;
IF ( UsingStdInput ) THEN
ReadChar(TempFile,Ch);
IF (TempFile.res <> done) THEN
IF (TempFile.eof) THEN
WriteString
("column_set: Error -- Temporary Input File Looks Empty In Writing Pass");
WriteLn;
ELSE
WriteString
("column_set: Error -- problem reading from T:column_set.temp");
END;
Close(TempFile);
Delete(TempFileName);
IF (NOT UsingStdOutput) THEN
CloseOutput;
END;
RETURN;
END;
ELSE
Read(Ch);
IF (NOT Done) THEN
WriteString("column_set: Error -- Input File Looks Empty In Writing Pass");
WriteLn;
IF (NOT UsingStdOutput) THEN
CloseOutput;
END;
CloseInput;
RETURN;
END;
END;
LOOP
IF (Ch <> EOL) THEN
ThisLength := ThisLength + 1;
IF ( UsingStdOutput ) THEN
Terminal.Write(Ch);
(*
Module InOut "Done" documentation is buggy; omit checks after write;
Wirth didn't specify them, and BENCHMARK doesn't support them.
No way to check "Terminal" output result - not good when redirected
to a disk file that might overflow!
WriteString("column_set: Error -- problem writing standard output");
*)
ELSE
Write(Ch);
(*
Module InOut "Done" documentation is buggy; omit checks after write;
Wirth didn't specify them, and BENCHMARK doesn't support them.
IF (NOT Done) THEN
writebitch;
RETURN;
END;
*)
END;
ELSE
ThisColumn := ThisColumn + 1;
IF (ThisColumn < NumColumns) THEN
FOR I := ThisLength + 1 TO MaxLength + NumSpaces BY 1 DO
IF (UsingStdOutput) THEN
Terminal.Write(" ");
ELSE
Write(" ");
IF (NOT Done) THEN
writebitch;
RETURN;
END;
END;
END;
ELSE
IF (UsingStdOutput) THEN
Terminal.WriteLn;
ELSE
Write(EOL);
(*
Module InOut "Done" documentation is buggy; omit checks after write;
Wirth didn't specify them, and BENCHMARK doesn't support them.
IF (NOT Done) THEN
writebitch;
RETURN;
END;
*)
END;
ThisColumn := 0;
END;
ThisLength := 0;
END;
IF ( UsingStdInput ) THEN
ReadChar(TempFile,Ch);
IF (TempFile.res <> done) THEN
IF (TempFile.eof) THEN
EXIT;
ELSE
WriteString
("column_set: Error -- problem reading from T:column_set.temp");
Close(TempFile);
Delete(TempFileName);
IF (NOT UsingStdOutput) THEN
CloseOutput;
END;
RETURN;
END;
END;
ELSE
Read(Ch);
IF (NOT Done) THEN (* Unable to differentiate read error from eof *)
EXIT;
END;
END;
END;
IF (ThisColumn <> 0) THEN
IF (UsingStdOutput) THEN
Terminal.WriteLn;
ELSE
Write(EOL);
(*
Module InOut "Done" documentation is buggy; omit checks after write;
Wirth didn't specify them, and BENCHMARK doesn't support them.
IF (NOT Done) THEN
writebitch;
RETURN;
END;
*)
END;
END;
IF ( UsingStdInput ) THEN
Close(TempFile);
Delete(TempFileName);
ELSE
CloseInput;
END;
IF (NOT UsingStdOutput) THEN
CloseOutput;
END;
END column_set.