home *** CD-ROM | disk | FTP | other *** search
- Program PRINTF;
-
- {
- By : Darrell Flenniken 70015,143 20 August 85
-
- PRINTF is a program that implements a formatted print routine
- in the style of that in the 'C' language.
-
- The heart of this routine is a 'hack' to allow a variable
- number of arguments and argument types to be passed to a
- Pascal Procedure via a 'string of pointers'.
-
- Use:
- Printf(Device,Control String,_(arg1)+...+_(argn));
-
- Where :
- 1.) Device is Con or Lst
- 2.) Control String
-
- The Control String contains literal constants and/or print
- formatting control sequences. Print format control sequences
- are Escaped with a leading '%' and have the following form:
-
- %W:Dd ....... decimal format
- %W:i ....... integer format
- %W:s ....... string format
- %W:u ....... unsigned integer format
- %W:h ....... hexidecimal (hhhh) format
- %W:b ....... binary format
- %t ....... next tab(8) field
- %n ....... cr/lf pair
- %% ....... allow printing of %
-
- W = the total field width for argument
- D = decimal precision (reals only)
- W is optional for all types
- :D is required for reals
-
- a '-' following will force left justification in
- field, right justification is the default.
-
- 3.) _(arg)
- The '_' function returns a string containing the binary
- address of the arg. Multiple args are concatenated.
- The '_' was chosen as the function name to keep it short
- and avoid collisions with other identifiers.
-
- NOTES:
- 1.) Very little error checking is performed by these routines.
- Failure to use proper syntax often leads to hung system.
- 2.) MS-DOS Specific, appropriate changes for CP/M can be made
- in '_' and 'GetArg' for 2 Byte Pointers.
-
-
- Enjoy....
- }
-
-
- TYPE
- String4 = String[4];
- String80 = String[80];
-
-
- Function _(VAR Item):String4;
- { Return the Address of Item as a String }
- BEGIN
- _ := Chr(Lo(Seg(Item)))+Chr(Hi(Seg(Item)))+
- Chr(Lo(Ofs(Item)))+Chr(Hi(Ofs(Item)))
- END;
-
-
- Procedure PrintF(VAR Dev:Text;Format,ArgVec:String80);
- { Print N Items pointed to in ArgVec using Format on Dev [ Con,Lst ] }
- CONST
- Hex : Array[0..15] OF Char = '0123456789ABCDEF';
- TYPE
- VecPtr = ^VecItem;
- VecItem = RECORD
- CASE Integer OF
- 1 : (I:Integer);
- 2 : (R:Real);
- 3 : (S:String80);
- END;
- VAR
- Fws,Dps : String[6];
- Fw,Dp,X,E : Integer;
- TOut,LineOut : String[255];
- Left : Boolean;
- Arg : VecPtr;
-
- Function GetArg:VecPtr;
- { Return a Pointer from ArgVec }
- BEGIN
- GetArg := Ptr((Ord(ArgVec[2]) Shl 8) + Ord(ArgVec[1]),
- (Ord(ArgVec[4]) Shl 8) + Ord(ArgVec[3]));
- Delete(ArgVec,1,4);
- END { GetArg };
-
- Function SStr(Num:Integer;Ch:Char):String80;
- { Return a String of length=Num composed of Char }
- VAR
- Temp : String80;
- BEGIN
- IF Num <= 0 THEN SStr := '' ELSE BEGIN
- FillChar(Temp[1],Num,Ch);
- Temp[0] := Chr(Num);
- SStr := Temp;
- END;
- END { SStr };
-
- BEGIN { PrintF }
- X := 1;
- LineOut := '';
- WHILE X < Length(Format) DO BEGIN
- Fws := '0';
- Dps := '0';
- WHILE (Format[X] <> '%') AND (X < Length(Format)) DO BEGIN
- LineOut := LineOut+Format[X];
- X := Succ(X);
- END;
- IF Format[X] = '%' THEN BEGIN
- X := Succ(X);
- IF Format[X] = '-' THEN BEGIN
- Left := TRUE;
- X := Succ(X);
- END ELSE
- Left := FALSE;
- WHILE Format[X] IN ['0'..'9'] DO BEGIN
- Fws := Fws+Format[X];
- X := Succ(X);
- END;
- Val(Fws,Fw,E);
- IF Format[X] = ':' THEN BEGIN
- X := Succ(X);
- WHILE Format[X] IN ['0'..'9'] DO BEGIN
- Dps := Dps+Format[X];
- X := Succ(X);
- END;
- END;
- Val(Dps,Dp,E);
- IF NOT (Format[X] IN ['%','t','n']) THEN
- Arg := GetArg;
- TOut := '';
- CASE Format[X] OF
- 's' : TOut := Arg^.S; { String }
- 'i' : Str(Arg^.I,TOut); { Signed Integer }
- 'd' : Str(Arg^.R:0:DP,TOut); { Decimal }
- 'n' : TOut := #13+#10; { CR/LF }
- 't' : TOut := SStr(8-(Length(LineOut) mod 8),' '); { Tab }
- 'h' : TOut := Hex[Hi(Arg^.I) Shr 4]+ { Hex }
- Hex[Hi(Arg^.I) AND $F]+
- Hex[Lo(Arg^.I) Shr 4]+
- Hex[Lo(Arg^.I) AND $F];
- 'b' : FOR E := 15 DOWNTO 0 DO { Binary }
- TOut := TOut+Chr(((Arg^.I Shr E) AND 1)+$30);
- 'u' : IF Arg^.I < 0 THEN { Unsigned Integer }
- Str(Arg^.I+65536.0:0:0,TOut)
- ELSE
- Str(Arg^.I,TOut);
- '%' : TOut := '%'; { % sign }
- END { CASE };
- IF Left THEN
- LineOut := LineOut+TOut+SStr(Fw-Length(TOut),' ')
- ELSE
- LineOut := LineOut+SStr(Fw-Length(TOut),' ')+TOut;
- X := Succ(X);
- END { IF Format[X] = '%' };
- END { WHILE X < LengthFormat) };
- Write(Dev,LineOut);
- END { PrintF };
-
- { Examples of Use }
-
- VAR
- x,x2,x3,x4 : integer;
- y : real;
- z,Fstr : string[80];
-
- BEGIN
- x := 32767;
- x2 := 3;
- x3 := 345;
- x4 := -999;
- y := -999.456;
- z := 'sam i am';
- Fstr := 'test %% %20s %-12i %-:2d %h %b%n';
-
- PrintF(Con,'test %20s %-12i %-12:2d %h %b%n',_(z)+_(x)+_(y)+_(x)+_(x));
- PrintF(Con,'test %-20s %12u %12:2d %h %b%n',_(z)+_(x)+_(y)+_(x)+_(x));
- PrintF(Con,FStr,_(z)+_(x)+_(y)+_(x)+_(x));
- PrintF(Con,'%i%t%i%t%i%t%i',_(x)+_(x2)+_(x3)+_(x4));
- PrintF(Lst,'test %20s %-12i %-12:2d %h %b%n',_(z)+_(x)+_(y)+_(x)+_(x));
- PrintF(Lst,'test %-20s %12i %12:2d %h %b%n',_(z)+_(x)+_(y)+_(x)+_(x));
- END.