home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / prpascal / pibpict.lzh / PICTFORM.PAS < prev   
Pascal/Delphi Source File  |  1986-01-16  |  27KB  |  582 lines

  1.  
  2. (* ------------------------------------------------------------------------ *)
  3. (*         Picture_Format --- Edit real number using picture format         *)
  4. (* ------------------------------------------------------------------------ *)
  5.  
  6. Procedure Picture_Format(     X:       Real;
  7.                               Picture: AnyStr;
  8.                           Var Result:  AnyStr;
  9.                           Var Ierr:    Integer    );
  10.  
  11. (* ------------------------------------------------------------------------ *)
  12. (*                                                                          *)
  13. (*        Procedure:  Picture_Format                                        *)
  14. (*                                                                          *)
  15. (*        Purpose:    Formats a floating-point number according to a        *)
  16. (*                    picture format.                                       *)
  17. (*                                                                          *)
  18. (*        Calling Sequence:                                                 *)
  19. (*                                                                          *)
  20. (*           Picture_Format(     X:       Real;                             *)
  21. (*                               Picture: AnyStr;                           *)
  22. (*                           Var Result:  AnyStr;                           *)
  23. (*                           Var Ierr:    Integer    );                     *)
  24. (*                                                                          *)
  25. (*             Type 'AnyStr' should be defined in the caller as             *)
  26. (*             String[255].                                                 *)
  27. (*                                                                          *)
  28. (*             X       --- Number to be encoded                             *)
  29. (*             Picture --- Picture to use in formatting X (see below)       *)
  30. (*             Result  --- Resultant formatted version of X                 *)
  31. (*             Ierr    --- Error flag                                       *)
  32. (*                         = 0:  Conversion successful                      *)
  33. (*                         = 1:  X was negative, but no picture character   *)
  34. (*                               for a sign found.  'Result' contains the   *)
  35. (*                               successful conversion of ABS( X ).         *)
  36. (*                         = 2:  Incorrect picture character found, or      *)
  37. (*                               legitimate character found in incorrect    *)
  38. (*                               position (e.g., leading comma).            *)
  39. (*                               No conversion done, and 'Result' contains  *)
  40. (*                               the null string.                           *)
  41. (*                         = 3:  More than one decimal point in picture.    *)
  42. (*                               No conversion is done, and 'Result' is     *)
  43. (*                               the null string.                           *)
  44. (*                                                                          *)
  45. (*        Calls:                                                            *)
  46. (*                                                                          *)
  47. (*           Builtin only.                                                  *)
  48. (*                                                                          *)
  49. (*        Method:                                                           *)
  50. (*                                                                          *)
  51. (*           The number X is converted to a string of digits and fill       *)
  52. (*           characters under control of the picture.                       *)
  53. (*                                                                          *)
  54. (*        Restrictions:                                                     *)
  55. (*                                                                          *)
  56. (*           The picture may not exceed 80 characters in length.            *)
  57. (*                                                                          *)
  58. (*        Description of Picture Format Characters                          *)
  59. (*        ----------------------------------------                          *)
  60. (*                                                                          *)
  61. (*           The picture format implemented by this routine resembles the   *)
  62. (*           picture formats available in PL/1 or Cobol.  It also resembles *)
  63. (*           the ED/EDMK machine instructions of IBM 360/370 machines.      *)
  64. (*                                                                          *)
  65. (*           The available picture characters are:                          *)
  66. (*                                                                          *)
  67. (*             Character                M e a n i n g                       *)
  68. (*             ---------    ---------------------------------------------   *)
  69. (*                                                                          *)
  70. (*                 9         Digit select.  The next digit is inserted into *)
  71. (*                           the result, even if it is a leading zero.  The *)
  72. (*                           first appearance of a 9 turns on the signifi-  *)
  73. (*                           indicator, meaning that all following digits,  *)
  74. (*                           even leading zeros, will be significant.       *)
  75. (*                                                                          *)
  76. (*                 B         Insert a blank in the result.                  *)
  77. (*                                                                          *)
  78. (*                 Z         Digit select like '9', but if the digit is a   *)
  79. (*                           leading zero, a blank is inserted instead.     *)
  80. (*                                                                          *)
  81. (*                 S         Inserts sign into the result, either '+' or    *)
  82. (*                           '-', depending upon the sign of X.             *)
  83. (*                                                                          *)
  84. (*                 *         Field protection -- replaces leading zeros.    *)
  85. (*                                                                          *)
  86. (*                 +         If '+' appears last or as part of the initial  *)
  87. (*                           string, it selects the sign of X (either '+'   *)
  88. (*                           or '-').  For X > 0, a '+' is output; for      *)
  89. (*                           X <= 0, a blank is output. Otherwise, '+' acts *)
  90. (*                           as a literal, and is placed directly in the    *)
  91. (*                           output.                                        *)
  92. (*                                                                          *)
  93. (*                 -         If '-' appears last or as part of the initial  *)
  94. (*                           string, it selects the sign of X.  For X < 0,  *)
  95. (*                           a '-' is output; for X >= 0, a blank.  If '-'  *)
  96. (*                           appears elsewhere, it acts as a literal, and   *)
  97. (*                           is placed directly in the output.              *)
  98. (*                                                                          *)
  99. (*                 .         Selects the decimal point.  Only one allowed   *)
  100. (*                           in the picture.                                *)
  101. (*                                                                          *)
  102. (*                 $         Replaces leading zeros with blanks and a       *)
  103. (*                           dollar sign.                                   *)
  104. (*                                                                          *)
  105. (*                 ,         Inserts comma in result if a digit appears to  *)
  106. (*                           left, else next character to left in picture   *)
  107. (*                           is used instead.  Note:  except for leading,   *)
  108. (*                           trailing, and adjacent commas, comma placement *)
  109. (*                           is not checked.                                *)
  110. (*                                                                          *)
  111. (*                 /         Inserts '/' in result.                         *)
  112. (*                                                                          *)
  113. (*                 (         Replaces leading zeros with blanks and a '('   *)
  114. (*                           if the number is negative.                     *)
  115. (*                                                                          *)
  116. (*                 )         Selects ')' if the number is negative.         *)
  117. (*                           Must be last character in picture.             *)
  118. (*                                                                          *)
  119. (*                CR         Inserts 'CR' in result if number is NEGATIVE.  *)
  120. (*                           Must appear at end of picture.                 *)
  121. (*                                                                          *)
  122. (*                DB         Inserts 'DB' in result if number is NEGATIVE.  *)
  123. (*                           Must appear at end of picture.                 *)
  124. (*                                                                          *)
  125. (*           Floating Characters                                            *)
  126. (*           -------------------                                            *)
  127. (*                                                                          *)
  128. (*           The characters (,$,+,-,S  may 'float'.  This means that the    *)
  129. (*           RIGHTMOST appearance of one of these characters in the picture *)
  130. (*           replaces the first leading zero to the left of the leftmost    *)
  131. (*           significant digit.                                             *)
  132. (*                                                                          *)
  133. (*           Other appearances to the left of the one actually used to      *)
  134. (*           replace a leading zero are replaced by leading blanks.         *)
  135. (*                                                                          *)
  136. (*           Treatment of Sign Characters                                   *)
  137. (*           ----------------------------                                   *)
  138. (*                                                                          *)
  139. (*           The rightmost appearance of a sign dictates the placement of   *)
  140. (*           the sign, and overrides any appearance of a sign request to    *)
  141. (*           the left.  This allows for trailing signs as well as initial   *)
  142. (*           signs -- but only one appears in the edited result (the        *)
  143. (*           rightmost).                                                    *)
  144. (*                                                                          *)
  145. (*           Embedded '+' or '-' signs are treated as literals, not signs.  *)
  146. (*           This provides, for example, for formatting social security     *)
  147. (*           numbers with a '-' separating the three parts.                 *)
  148. (*                                                                          *)
  149. (*           A trailing DB or CR is considered a sign request.  Thus,       *)
  150. (*           other signs to the left are not inserted into the result.      *)
  151. (*                                                                          *)
  152. (* ------------------------------------------------------------------------ *)
  153. (*                                                                          *)
  154. (*        Author:  Philip R. Burns                                          *)
  155. (*        Date:    February, 1985.                                          *)
  156. (*        Version: 1.0                                                      *)
  157. (*                                                                          *)
  158. (*        Notice:  You are free to use this routine in code you write.      *)
  159. (*                 If you do, please give proper credit.                    *)
  160. (*                                                                          *)
  161. (*        Bugs:    Report bugs and/or enhancements to me on one of the      *)
  162. (*                 following two Chicago area BBSs:                         *)
  163. (*                                                                          *)
  164. (*                 Gene Plantz's IBBS      (312) 882 4227                   *)
  165. (*                 Ron Fox's RBBS          (312) 940 6496                   *)
  166. (*                                                                          *)
  167. (* ------------------------------------------------------------------------ *)
  168.  
  169.  
  170. Const                              (* Maximum length of a picture *)
  171.    MaxPic = 80;
  172.  
  173. Const
  174.                                    (* Valid picture characters *)
  175.  
  176.    PiChar: Array[1..17] of Char = '9BSZ*+-.$,/()CRDB';
  177.  
  178. Var
  179.                                    (* Number of decimal places in result *)
  180.    Ndec:       Integer;
  181.                                    (* Location of decimal point in result *)
  182.    Decloc:     Integer;
  183.                                    (* Length of picture *)
  184.    Lpic:       Integer;
  185.                                    (* Current picture character code *)
  186.    Code:       Byte;
  187.                                    (* Result character *)
  188.    Rchar:      Char;
  189.                                    (* Sign character *)
  190.    Sign_Char:  Char;
  191.                                    (* Length of coded/edited picture *)
  192.    LPicCod:    Integer;
  193.                                    (* Encoded picture *)
  194.  
  195.    PicCod:     Array[ 1 .. MaxPic ] Of Byte;
  196.  
  197.                                    (* Last signif. digit already found    *)
  198.    Qdigs:      Boolean;
  199.                                    (* Digits from now on are significant  *)
  200.    Qsig:       Boolean;
  201.                                    (* Sign already inserted in result     *)
  202.    Qsused:     Boolean;
  203.                                    (* $ already inserted in result field  *)
  204.    Qdused:     Boolean;
  205.                                    (* ( already inserted in result field  *)
  206.    Qlpuse:     Boolean;
  207.                                    (* Decimal point found in picture      *)
  208.    Qdecf:      Boolean;
  209.                                    (* Holds converted digits of number    *)
  210.    Digits:     String[40];
  211.                                    (* Next digit to be inserted in result *)
  212.    CurDig:     Integer;
  213.                                    (* General scratch variables           *)
  214.    I:          Integer;
  215.    J:          Byte;
  216.    LastJ:      Byte;
  217.    Ch:         Char;
  218.  
  219. Label 9001;                        (* Error exit *)
  220. Label 55;                          (* For commas *)
  221.  
  222. Procedure GetNextDigit;
  223.  
  224. (* ------------------------------------------------------------------------ *)
  225. (*                                                                          *)
  226. (*     Procedure:  GetNextDigit                                             *)
  227. (*                                                                          *)
  228. (*     Purpose:    Selects the next digit of fill character to be inserted  *)
  229. (*                 in the edited result.                                    *)
  230. (*                                                                          *)
  231. (* ------------------------------------------------------------------------ *)
  232.  
  233. Var
  234.    Rchar2:    Char;
  235.  
  236. Begin (* GetNextDigit *)
  237.  
  238.    If NOT Qdigs THEN
  239.       Begin
  240.  
  241.          Rchar2 := Digits[ CurDig ];
  242.  
  243.          While( NOT ( Rchar2 In ['0'..'9',' '] ) ) Do
  244.             Begin
  245.                If CurDig > 1 Then
  246.                   Begin
  247.                      CurDig := CurDig - 1;
  248.                      Rchar2 := Digits[ CurDig ];
  249.                   End
  250.                Else
  251.                   Begin
  252.                      Rchar2 := ' ';
  253.                      Qdigs  := TRUE;
  254.                   End;
  255.             End;
  256.  
  257.          CurDig := CurDig - 1;
  258.  
  259.          If ( NOT QDIGS ) And ( RChar2 <> ' ' ) Then
  260.             Rchar := Rchar2;
  261.  
  262.       End;
  263.  
  264.    Qsused := Qsused OR (  RChar  = Sign_Char );
  265.    Qdigs  := Qdigs  OR (  RChar2 = ' '       );
  266.    Qdused := Qdused OR (  RChar  = '$'       );
  267.    Qlpuse := Qlpuse OR (  RChar  = '('       );
  268.  
  269. End   (* GetNextDigit *);
  270.  
  271. (* ------------------------------------------------------------------------ *)
  272.  
  273. Begin (* Picture_Format *)
  274.  
  275.                                    (* Initialize result to null string. *)
  276.    Result  := '';
  277.                                    (* We only look at the first MaxPic  *)
  278.                                    (* characters of the picture.        *)
  279.  
  280.    Lpic    := LENGTH( Picture );
  281.    If Lpic > MaxPic Then Lpic := MaxPic;
  282.  
  283.                                    (* Other initializations *)
  284.    Decloc  := 0;
  285.    LastJ   := 0;
  286.    LPicCod := 0;
  287.    Ierr    := 0;
  288.    Qdecf   := FALSE;
  289.  
  290.                                    (* Scan the picture and convert it *)
  291.                                    (* to control codes.  Stop if any  *)
  292.                                    (* errors are found.               *)
  293.  
  294.    For I := 1 TO Lpic Do
  295.       Begin
  296.                                    (* Get next character in picture.  *)
  297.  
  298.          Ch     := UpCase( Picture[I] );
  299.  
  300.                                    (* Get corresponding control code. *)
  301.  
  302.          J := POS( Ch , PiChar );
  303.  
  304.                                    (* If valid picture character, some *)
  305.                                    (* editing may be required.         *)
  306.          If J <> 0 Then
  307.             Begin
  308.  
  309.                Case Ch Of
  310.                                    (* If decimal point already found,  *)
  311.                                    (* trailing digits must be signif.  *)
  312.  
  313.                   'Z': If Qdecf Then J := 1;
  314.  
  315.                                    (* Check comma placement.           *)
  316.  
  317.                   ',': If ( I     = 1    ) OR
  318.                           ( I     = Lpic ) OR
  319.                           ( LastJ = 10 )   OR
  320.                           Qdecf Then
  321.                            Begin
  322.                               Ierr := 2;
  323.                               GOTO 9001;
  324.                            End;
  325.  
  326.                                    (* Check for duplicate decimal point. *)
  327.  
  328.                   '.': If DecLoc = 0 Then
  329.                           Begin
  330.                              DecLoc := I;
  331.                              Qdecf  := TRUE;
  332.                           End
  333.                        Else
  334.                           Begin
  335.                              Ierr := 3;
  336.                              GOTO 9001;
  337.                           End;
  338.  
  339.                                     (* Remove floating ( if positive X *)
  340.  
  341.                   '(': If X > 0.0 Then J := 4;
  342.  
  343.                                     (* Remove trailing ) if positive X *)
  344.  
  345.                   ')': If ( I <> LPic ) Then
  346.                           Begin
  347.                              Ierr := 2;
  348.                              GOTO 9001;
  349.                           End
  350.                        Else If X > 0.0 Then J := 0;
  351.  
  352.                                    (* Fix up CR and DB.   *)
  353.  
  354.                   'R': If ( LastJ <> 14 ) Then
  355.                           Begin
  356.                              Ierr := 2;
  357.                              GOTO 9001;
  358.                           End;
  359.  
  360.                   'B': If ( LastJ = 16 ) Then  J := 17;
  361.  
  362.                End (* Case *);
  363.  
  364.                If J > 0 Then
  365.                   Begin
  366.                      LpicCod           := LpicCod + 1;
  367.                      PicCod[ LpicCod ] := J;
  368.                   End;
  369.  
  370.             End
  371.  
  372.          Else (* Bad Picture Character *)
  373.             Begin
  374.                Ierr := 2;
  375.                GOTO 9001;
  376.             End;
  377.  
  378.          If J > 0 Then LastJ := J;
  379.  
  380.       End;
  381.  
  382.                                    (* Find Number Digits after Decimal Point *)
  383.  
  384.    Ndec   := 0;
  385.  
  386.    If ( Decloc <> 0 ) AND ( Decloc <> LPicCod ) Then
  387.       Begin
  388.  
  389.          J := Decloc + 1;
  390.  
  391.          For I := J To LPicCod Do
  392.             If ( PicCod[I] = 1 ) OR
  393.                ( PicCod[I] = 4 ) Then
  394.                Ndec   := Ndec + 1;
  395.  
  396.       End;
  397.  
  398.                                    (* Convert number to character form *)
  399.  
  400.    STR( ABS( X ) : 40 : Ndec , Digits );
  401.  
  402.                                    (* Point to last digit in conversion *)
  403.    CurDig    := 40;
  404.  
  405.                                    (* Remember sign of number *)
  406.  
  407.    If X >= 0 Then
  408.       Sign_Char := '+'
  409.    Else
  410.       Sign_Char := '-';
  411.  
  412.                                    (* Set conversion flags. *)
  413.    Qdigs  := FALSE;
  414.    Qsig   := TRUE;
  415.    Qsused := FALSE;
  416.    Qdused := FALSE;
  417.    Qlpuse := ( X >= 0.0 );
  418.  
  419.                                   (* Begin editing process.  Insert digits  *)
  420.                                   (* into result field under control of     *)
  421.                                   (* picture.                               *)
  422.  
  423.    For I := 1 To LPicCod DO
  424.       Begin    (* Picture Formatting *);
  425.  
  426.          J      := LPicCod - I + 1;
  427.          Code   := PicCod[J];
  428.          Rchar  := PiChar[ Code ];
  429.  
  430. 55:
  431.          Case Code Of
  432.                                    (* Select a digit*)
  433.              1 :  Begin
  434.                      Rchar  := '0';
  435.                      GetNextDigit;
  436.                   End;
  437.  
  438.              2 :  Rchar := ' ';    (* Insert a blank *)
  439.  
  440.              3 :  Begin            (* Insert explicit sign *)
  441.  
  442.                      Rchar := Sign_Char;
  443.  
  444.                      If ( J = LpicCod ) Then
  445.                         QsUsed := TRUE
  446.                      Else If ( J = 1 ) Then
  447.                         Begin
  448.                            If QsUsed Then Rchar := ' ';
  449.                            QsUsed := TRUE;
  450.                         End
  451.                      Else If ( PicCod[ J - 1 ] = Code ) OR
  452.                              ( PicCod[ J - 1 ] = 10   ) OR
  453.                              ( PicCod[ J - 1 ] = 7    ) Then
  454.                         Begin
  455.                            If QsUsed Then Rchar := ' ';
  456.                            GetNextDigit;
  457.                         End;
  458.  
  459.                   End;
  460.  
  461.                                    (* Select signif. digit or blank *)
  462.              4 :  Begin
  463.                      Rchar  := ' ';
  464.                      GetNextDigit;
  465.                   End;
  466.  
  467.              5 :  Begin            (* Field protection              *)
  468.                      GetNextDigit;
  469.                   End;
  470.  
  471.              6 :  Begin            (* Plus sign.                    *)
  472.  
  473.                      Rchar := Sign_Char;
  474.  
  475.                      If ( J = LpicCod ) Then
  476.                         Begin
  477.                            QsUsed := TRUE;
  478.                            If ( X < 0.0 ) Then Rchar := ' ';
  479.                         End
  480.                      Else If ( J = 1 ) Then
  481.                         Begin
  482.                            If QsUsed Then Rchar := ' ';
  483.                            QsUsed := TRUE;
  484.                         End
  485.                      Else If ( PicCod[ J - 1 ] = Code ) OR
  486.                              ( PicCod[ J - 1 ] = 10   ) OR
  487.                              ( PicCod[ J - 1 ] = 7    ) Then
  488.                         Begin
  489.                            If QsUsed Then Rchar := ' ';
  490.                            GetNextDigit;
  491.                         End
  492.                      Else
  493.                         Rchar := PiChar[6];
  494.  
  495.                   End;
  496.  
  497.              7:   Begin            (* Minus sign *)
  498.  
  499.                      Rchar := Sign_Char;
  500.  
  501.                      If ( J = LpicCod ) Then
  502.                         Begin
  503.                            QsUsed := TRUE;
  504.                            If ( X >= 0.0 ) Then Rchar := ' ';
  505.                         End
  506.                      Else If ( J = 1 ) Then
  507.                         Begin
  508.                            If ( NOT QsUsed ) AND ( X < 0.0 ) Then
  509.                               Rchar := Sign_Char
  510.                            Else
  511.                               Rchar := ' ';
  512.                            QsUsed := TRUE;
  513.                         End
  514.                      Else If ( PicCod[ J - 1 ] = Code ) OR
  515.                              ( PicCod[ J - 1 ] = 10   ) OR
  516.                              ( PicCod[ J - 1 ] = 6    ) Then
  517.                         Begin
  518.                            If QsUsed Then Rchar := ' ';
  519.                            GetNextDigit;
  520.                         End
  521.                      Else
  522.                         Rchar := PiChar[7];
  523.  
  524.                   End   (* - *);
  525.  
  526.                                    (* Decimal point.  Digits from here on   *)
  527.                                    (* may not be significant.               *)
  528.              8 :  Qsig := FALSE;
  529.  
  530.                                    (* Floating dollar sign           *)
  531.  
  532.              9 :  If Qdused Then Rchar := ' '
  533.                   Else GetNextDigit;
  534.  
  535.             10 :  Begin            (* Comma *)
  536.  
  537.                      If ( NOT ( Digits[ CurDig ] In ['0'..'9'] ) ) AND
  538.                         ( PicCod[ J - 1 ] <> 1 ) Then
  539.                         Begin
  540.                            Code  := PicCod[ J - 1 ];
  541.                            Rchar := PiChar[ Code ];
  542.                            GOTO 55;
  543.                         End;
  544.  
  545.                   End   (* , *);
  546.  
  547.                                    (* / *)
  548.  
  549.             11 :  If Qdigs THEN Rchar := ' ';
  550.  
  551.                                    (* Floating left parenthesis *)
  552.  
  553.             12 :  If Qlpuse Then Rchar := ' '
  554.                   Else GetNextDigit;
  555.  
  556.                                    (* Right parenthesis *)
  557.  
  558.             13 :  If X >= 0.0 Then Rchar := ' ';
  559.  
  560.                                    (* CR and DB *)
  561.         14..17 :  Begin
  562.                      If X >= 0.0 Then Rchar := ' ';
  563.                      QsUsed := TRUE;
  564.                   End;
  565.  
  566.          End  (* Case *);
  567.  
  568.                                    (* Insert next character into result *)
  569.          Res := Rchar + Res;
  570.  
  571.       End (* Picture Formatting *);
  572.                                    (* If number was negative, but sign *)
  573.                                    (* never inserted, report error 1.  *)
  574.  
  575.    If ( X < 0 ) AND ( NOT QsUsed ) Then Ierr := 1;
  576.  
  577. 9001: ;
  578.  
  579. End  (* Picture_Format *);
  580.  
  581. (* ------------------------------------------------------------------------ *)
  582.