home *** CD-ROM | disk | FTP | other *** search
/ Programmer's ROM - The Computer Language Library / programmersrom.iso / ada / misc / dstr3.src < prev    next >
Encoding:
Text File  |  1988-05-03  |  16.3 KB  |  488 lines

  1. with TEXT_IO; 
  2. use TEXT_IO;
  3. package DYN is 
  4.  
  5.  
  6. ------------------------------------------------------------------------------
  7. --  This is a package of several string manipulation functions based on     --
  8. -- a built-in dynamic STRING type DYN_STRING.  It is an adaptation and      --
  9. -- extension of the package proposed by Sylvan Rubin of Ford Aerospace and  --
  10. -- Communications Corporation in the Nov/Dec 1984 issue of the Journal of   --
  11. -- Pascal, Ada and Modula-2.  Some new functions have been added, and much  --
  12. -- of the body code has been rewritten.                                     --
  13. ------------------------------------------------------------------------------
  14. -- R.G. Cleaveland 07 December 1984:                                        --
  15. --  Implementation initially with the Telesoft Ada version 1.3.             --
  16. -- 06 Feb 85: CHAR changed to add the optional parameter POSIT.             --
  17. -- 06 Feb 85: procedure SUBSTITUTE added.                                   --
  18. -- 05 Apr 85: procedures UPPERCASE and CHECKBYTE added.                     --
  19. -- 04 Feb 86: style and formatting changes made, some comments fixed.       --
  20. -- Ported to VERDIX VADS (VAX Ultrix version 5.1).                          --
  21. -- 10 Feb 86: Several bugs fixed - SIZE constrained, exception for '&'      --
  22. -- generating too long a string added, error in integer conversion fixed.   --
  23. -- Functions EQUALS, ">", "<=" and ">=" added.  Subtype DS_POS incorporated.--
  24. ------------------------------------------------------------------------------
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.   MAX_D_STRING_LENGTH : constant POSITIVE := 100; 
  32.     -- This is the maximum LENGTH of a dynamic string implemented with this
  33.     -- package.  This value is "arbitrary" in that any reasonable number
  34.     -- equal to or less than the maximum STRING LENGTH permitted by the
  35.     -- compiler is acceptable.  The specific value above was chosen as a
  36.     -- compromise between programmer convenience and memory space requirements.
  37.  
  38.  
  39.  
  40.   subtype DS_POS is INTEGER range 0..MAX_D_STRING_LENGTH;
  41.   
  42.   type DYN_STRING is private;
  43.  
  44.   STRING_TOO_SHORT: exception;
  45.  
  46.   
  47.   
  48.   function D_STRING(CHAR: CHARACTER)  return DYN_STRING;
  49.           -- Creates a one-byte dynamic string of contents CHAR.
  50.  
  51.   function D_STRING(STR : STRING   )  return DYN_STRING;
  52.           -- Creates a dynamic string of contents STR.
  53.  
  54.   function D_STRING(N: INTEGER;
  55.                     B: NATURAL  := 0;
  56.                     F: CHARACTER:= ' ') return DYN_STRING;
  57.   
  58.       -- for the preceding function:
  59.       --   B is the number of bytes desired in the returned string.
  60.       --     The  first byte is reserved for the sign; it will be blank
  61.       --     or '-'.  If B is 0 or unspecified the LENGTH of the
  62.       --     string returned is just enough for the sign and the
  63.       --     significant digits.  If the number would overflow B,
  64.       --     the exception STRING_TOO_SHORT is raised.
  65.  
  66.       --   F is a leading-fill CHARACTER.  If B is not zero, bytes
  67.       --     from 2 up to the first significant byte will be F.
  68.  
  69.   function D_STRING(FLT : FLOAT; AFT : INTEGER)  return DYN_STRING;
  70.     -- Creates a dynamic string representation of the number FLT
  71.     -- in fixed point notation with AFT decimal places.
  72.  
  73.   -- The following four functions convert from dynamic strings to the
  74.   -- desired representation:
  75.  
  76.   function CHAR(DSTR  : DYN_STRING;
  77.                 POSIT : POSITIVE := 1) return CHARACTER;
  78.   
  79.   function STR (DSTR: DYN_STRING) return STRING;
  80.   
  81.   function INT (DSTR: DYN_STRING) return INTEGER;
  82.   
  83.   function FLT (DSTR: DYN_STRING) return FLOAT;
  84.   
  85.   -- (No function for long integer; depends on compiler implementation)
  86.   
  87.   function LENGTH(DSTR: DYN_STRING)     return NATURAL;
  88.     -- returns the LENGTH of the dynamic string.
  89.  
  90.   function EQUALS    (DS1, DS2: DYN_STRING) return BOOLEAN;
  91.     -- true if DS1 is equal to DS2 the way Ada compares strings
  92.  
  93.   function "<"    (DS1, DS2: DYN_STRING) return BOOLEAN;
  94.     -- true if DS1 is less than DS2 the way Ada compares strings
  95.   
  96.   function "<="   (DS1, DS2: DYN_STRING) return BOOLEAN;
  97.     -- true if DS1 is less than or equal to DS2 the way Ada compares strings
  98.   
  99.   function ">"    (DS1, DS2: DYN_STRING) return BOOLEAN;
  100.     -- true if DS1 is greater than DS2 the way Ada compares strings
  101.   
  102.   function ">="   (DS1, DS2: DYN_STRING) return BOOLEAN;
  103.     -- true if DS1 is greater than or equal to DS2 the way Ada compares strings
  104.  
  105.   function "&"   (DS1, DS2: DYN_STRING) return DYN_STRING;
  106.     -- concatenates DS1 and DS2.  Raises CONSTRAINT_ERROR if LENGTH of
  107.     -- new string would exceed MAX_D_STRING_LENGTH.
  108.  
  109.   function SUBSTRING (DSTR: DYN_STRING;    -- Returns a subpart of this string
  110.                       START  : NATURAL;    -- starting at this position
  111.                       LENGTH : NATURAL)    -- and of this LENGTH.
  112.                      return DYN_STRING;
  113.  
  114.   function RIGHT (DSTR: DYN_STRING;        -- Returns the part of this string
  115.                   START  : NATURAL)        -- starting here and to the end.
  116.                  return DYN_STRING;
  117.                        
  118.   procedure SUBSTITUTE(DSTR  : in out DYN_STRING;-- Into this string
  119.                        POSIT : in POSITIVE;      -- at this position,
  120.                        C     : in CHARACTER);    -- this character
  121.                                                  -- is substituted.
  122.  
  123.   function INDEX (SOURCE_STRING : DYN_STRING; -- If this string contains
  124.                   PATTERN_STRING: DYN_STRING; -- this string starting AT or
  125.                   START_POSIT   : INTEGER)    -- AFTER this position, the
  126.                  return INTEGER;              -- position of such start
  127.                                               -- is returned.
  128.                  -- If the string lengths prohibit the search -1 is returned.
  129.                  -- If no match was found, 0 is returned.
  130.                  -- (This is like the INSTR function of BASIC).
  131.  
  132.   function RINDEX (SOURCE_STRING : DYN_STRING; -- If this string contains
  133.                    PATTERN_STRING: DYN_STRING; -- this string starting AT or
  134.                    START_POSIT   : INTEGER)    -- BEFORE this position, the
  135.                   return INTEGER;              -- position of such start
  136.                                                -- is returned.
  137.                   -- If the string lengths prohibit the search -1 is returned.
  138.                   -- If no match was found, 0 is returned.
  139.                   -- eg RINDEX(D_STRING("ABC"),D_STRING("C") ,2) =  0
  140.                   --    RINDEX(D_STRING("ABC"),D_STRING("BC"),3) = -1
  141.   
  142.   function UPPERCASE (DSTR: DYN_STRING) return DYN_STRING;
  143.                   -- Returns with all lower-case characters changed to
  144.                   -- uppercase.
  145.   function CHECKBYTE(DSTR: in DYN_STRING) return CHARACTER;
  146.                   -- Returns a printable check CHARACTER representing a
  147.                   -- logical process on the elements of the string for
  148.                   -- purposes of data validity checks.
  149.   procedure CLEAR(DSTR: in out DYN_STRING);
  150.                   -- makes DSTR a null string.
  151.  
  152. private
  153.   type DYN_STRING is
  154.     record
  155.       SIZE: INTEGER range 0..MAX_D_STRING_LENGTH;
  156.       DATA: STRING(1..MAX_D_STRING_LENGTH);
  157.     end record;
  158. end DYN;
  159.  
  160.  
  161. package body DYN is
  162.            
  163.   procedure CLEAR(DSTR: in out DYN_STRING) is
  164.     
  165.     begin
  166.       DSTR.SIZE := 0;
  167.     end CLEAR;
  168.  
  169.   function MINIMUM(VALUE1, VALUE2: NATURAL) return NATURAL is
  170.   
  171.     begin
  172.       if VALUE1 < VALUE2 then 
  173.         return VALUE1;
  174.       else 
  175.         return VALUE2;
  176.       end if;
  177.     end MINIMUM;
  178.       
  179.   function "&" (DS1, DS2: DYN_STRING) return DYN_STRING is
  180.           
  181.       DS3 : DYN_STRING;
  182.     
  183.     begin
  184.       DS3.SIZE              := DS1.SIZE + DS2.SIZE;
  185.       DS3.DATA(1..DS3.SIZE) := DS1.DATA(1..DS1.SIZE) & DS2.DATA(1..DS2.SIZE);
  186.       return DS3;
  187.     end "&";
  188.   
  189.   function D_STRING(CHAR: CHARACTER)  return DYN_STRING is
  190.           
  191.       DS : DYN_STRING;
  192.     
  193.     begin
  194.       DS.SIZE     := 1;
  195.       DS.DATA(1)  := CHAR;
  196.       return DS;
  197.     end D_STRING;
  198.   
  199.   function D_STRING(STR : STRING   )  return DYN_STRING is
  200.           
  201.       DS : DYN_STRING;
  202.     
  203.     begin
  204.       DS.SIZE                   := STR'LENGTH;
  205.       DS.DATA(1..DS.SIZE)       := STR;
  206.       return DS;
  207.     end D_STRING;
  208.   
  209.   function D_STRING(N: INTEGER;
  210.                     B: NATURAL  := 0;
  211.                     F: CHARACTER:= ' ') return DYN_STRING is
  212.       
  213.       SIGN, V        : DYN_STRING;
  214.     
  215.     begin
  216.       if N < 0 then 
  217.         SIGN := D_STRING('-');
  218.       else 
  219.         SIGN := D_STRING(' ');
  220.       end if;
  221.       if N = 0 then
  222.         V := D_STRING('0');
  223.       else
  224.         V := RIGHT(D_STRING(INTEGER'image(N)),2); 
  225.       end if;
  226.       if B /= 0 then
  227.         if B < V.SIZE + 1 then
  228.           raise STRING_TOO_SHORT;
  229.         else 
  230.           for I in 1..B-1-V.SIZE loop
  231.             V := D_STRING(F) & V;
  232.           end loop;
  233.         end if;
  234.       end if;
  235.       return SIGN & V;
  236.     end D_STRING;
  237.   
  238.           
  239.   
  240.   function D_STRING(FLT : FLOAT; AFT : INTEGER)  return DYN_STRING is
  241.           
  242.       DS : DYN_STRING;
  243.       F  : FLOAT;
  244.       L  : INTEGER;            --This should be longest integer form
  245.                                --available for the implementation.
  246.     
  247.     begin
  248.       F := FLT * (10.0 ** AFT);
  249.       L := INTEGER(F);         --See note above - implementation dependent
  250.       DS := D_STRING(L);
  251.       while DS.SIZE < AFT+1 loop
  252.           DS := SUBSTRING(DS,1,1) & D_STRING('0') & RIGHT(DS,2);
  253.       end loop;
  254.       DS := SUBSTRING(DS,1,LENGTH(DS)-AFT) & D_STRING('.')
  255.             & RIGHT(DS,LENGTH(DS)-AFT+1);
  256.       return DS;
  257.     end D_STRING;
  258.   
  259.   function CHAR(DSTR  : DYN_STRING;
  260.                 POSIT : POSITIVE := 1) return CHARACTER is
  261.     
  262.     begin
  263.       if POSIT > DSTR.SIZE then 
  264.         raise STRING_TOO_SHORT;
  265.       else 
  266.         return DSTR.DATA(POSIT);
  267.       end if;
  268.     end CHAR;
  269.   
  270.   function STR (DSTR: DYN_STRING) return STRING is
  271.     
  272.     begin
  273.       return DSTR.DATA(1..DSTR.SIZE);
  274.     end STR;
  275.   
  276.   function INT (DSTR: DYN_STRING) return INTEGER is
  277.       V: INTEGER;
  278.       L: POSITIVE;
  279.       package INT_IO is new INTEGER_IO(INTEGER);
  280.     
  281.     begin
  282.       INT_IO.GET(STR(DSTR),V,L); -- Package reference may need to be
  283.       return V;                      -- changed for validated compiler
  284.     end INT;
  285.   
  286.   function FLT (DSTR: DYN_STRING) return FLOAT is
  287.       V: FLOAT;
  288.       L: POSITIVE;
  289.       package F_IO is new FLOAT_IO(FLOAT);
  290.     
  291.     begin
  292.       F_IO.GET(STR(DSTR),V,L);  -- See comment above.
  293.       return V;
  294.     end FLT;
  295.   
  296.   function LENGTH(DSTR: DYN_STRING) return NATURAL is
  297.     
  298.     begin
  299.       return DSTR.SIZE;
  300.     end LENGTH;
  301.   
  302.   function EQUALS    (DS1, DS2: DYN_STRING) return BOOLEAN is
  303.     -- true if DS1 is equal to DS2 the way Ada compares strings
  304.     begin
  305.       if STR(DS1)=STR(DS2) then
  306.         return (TRUE);
  307.       else
  308.         return (FALSE);
  309.       end if;
  310.     end EQUALS;
  311.       
  312.   function "<" (DS1, DS2: DYN_STRING) return BOOLEAN is
  313.     -- true if DS1 is less than DS2 the way Ada compares strings
  314.       
  315.     begin
  316.       if STR(DS1) < STR(DS2) then 
  317.         return (TRUE);
  318.       else 
  319.         return (FALSE);
  320.       end if;
  321.     end "<";
  322.   
  323.   function "<="   (DS1, DS2: DYN_STRING) return BOOLEAN is
  324.     -- true if DS1 is less than or equal to DS2 the way Ada compares strings
  325.     
  326.     begin
  327.       if STR(DS1) <= STR(DS2) then 
  328.         return (TRUE);
  329.       else 
  330.         return (FALSE);
  331.       end if;
  332.     end "<=";
  333.   
  334.  
  335.   function ">"    (DS1, DS2: DYN_STRING) return BOOLEAN is
  336.     -- true if DS1 is greater than DS2 the way Ada compares strings
  337.  
  338.     begin
  339.       if STR(DS1) > STR(DS2) then
  340.         return (TRUE);
  341.       else
  342.         return (FALSE);
  343.       end if;
  344.     end ">";
  345.  
  346.   function ">="   (DS1, DS2: DYN_STRING) return BOOLEAN is
  347.     -- true if DS1 is greater than or equal to DS2 the way Ada compares strings
  348.  
  349.     begin
  350.       if STR(DS1) >= STR(DS2) then
  351.         return (TRUE);
  352.       else
  353.         return (FALSE);
  354.       end if;
  355.     end ">=";
  356.   
  357.   procedure SUBSTITUTE(DSTR  : in out DYN_STRING;-- Into this string
  358.                        POSIT : in POSITIVE;      -- at this position,
  359.                        C     : in CHARACTER) is  -- this character
  360.                                                  -- is substituted.
  361.       
  362.     begin
  363.       DSTR.DATA(POSIT) := C;
  364.       if POSIT > DSTR.SIZE then 
  365.         DSTR.SIZE := POSIT;
  366.       end if;
  367.     end SUBSTITUTE;
  368.   
  369.   function SUBSTRING (DSTR: DYN_STRING; 
  370.                       START  : NATURAL;
  371.                       LENGTH : NATURAL)
  372.                                              return DYN_STRING is
  373.         DS: DYN_STRING;
  374.         L : NATURAL := LENGTH;
  375.     
  376.     begin
  377.       if (START < 1) or (START > DSTR.SIZE) then
  378.         raise CONSTRAINT_ERROR;
  379.       else 
  380.         if DSTR.SIZE < START + L - 1 then
  381.           raise STRING_TOO_SHORT;
  382.         else  
  383.           DS.SIZE := L;
  384.           DS.DATA(1..L) := DSTR.DATA(START..START+L-1);
  385.           return DS;
  386.         end if;
  387.       end if;
  388.     end SUBSTRING;
  389.   
  390.   function RIGHT (DSTR: DYN_STRING;
  391.                   START  : NATURAL) return DYN_STRING is
  392.       
  393.     begin
  394.       return SUBSTRING(DSTR, START, LENGTH(DSTR) - START + 1);
  395.     end RIGHT;
  396.       
  397.   function INDEX(SOURCE_STRING : DYN_STRING;
  398.                  PATTERN_STRING: DYN_STRING;
  399.                  START_POSIT   : INTEGER)    return INTEGER is
  400.           
  401.           NO_MATCH        : constant INTEGER :=  0;
  402.           NO_FIT          : constant INTEGER := -1;
  403.       
  404.     begin
  405.       if SOURCE_STRING.SIZE < PATTERN_STRING.SIZE + START_POSIT - 1
  406.       or START_POSIT < 1 then
  407.         return NO_FIT;
  408.       end if;
  409.       for I in START_POSIT..SOURCE_STRING.SIZE-PATTERN_STRING.SIZE+1 loop
  410.         if SOURCE_STRING.DATA(I..I+PATTERN_STRING.SIZE-1)
  411.            = PATTERN_STRING.DATA(1..PATTERN_STRING.SIZE) then
  412.          return I;
  413.         end if;
  414.       end loop;
  415.       return NO_MATCH;
  416.     end INDEX;
  417.   
  418.   function RINDEX(SOURCE_STRING : DYN_STRING;
  419.                   PATTERN_STRING: DYN_STRING;
  420.                   START_POSIT   : INTEGER)    return INTEGER is
  421.           
  422.         NO_MATCH        : constant INTEGER := 0;
  423.         NO_FIT          : constant INTEGER := -1;
  424.       
  425.     begin
  426.       if SOURCE_STRING.SIZE < PATTERN_STRING.SIZE + START_POSIT - 1
  427.       or START_POSIT < 1 then
  428.         return NO_FIT;
  429.       end if;
  430.       for I in reverse 1..START_POSIT loop
  431.         if SOURCE_STRING.DATA(I..I+PATTERN_STRING.SIZE-1)
  432.            = PATTERN_STRING.DATA(1..PATTERN_STRING.SIZE) then 
  433.           return I;
  434.         end if;
  435.       end loop;
  436.       return NO_MATCH;
  437.     end RINDEX;
  438.   
  439.   function UPPERCASE (DSTR: DYN_STRING) return DYN_STRING is
  440.           
  441.       DS: DYN_STRING  := DSTR;
  442.       
  443.     begin
  444.       for I in 1..LENGTH(DS) loop
  445.         case DSTR.DATA(I) is
  446.           when 'a'..'z' =>
  447.             DS.DATA(I) := CHARACTER'VAL(CHARACTER'pos(DS.DATA(I))-32);
  448.           when others   => null;
  449.         end case;
  450.       end loop;
  451.       return DS;
  452.     end UPPERCASE;
  453.   
  454.   function CHECKBYTE(DSTR: in DYN_STRING) return CHARACTER is
  455.                   
  456.      -- Returns a printable check CHARACTER representing a
  457.      -- logical process on the elements of the string for
  458.      -- purposes of data validity checks.  
  459.      -- IMPLEMENTATION NOTE:  The MAX_CHECKSUM is defined
  460.      -- so as to permit identical behavior on all systems
  461.      -- which will compile the routine.  This algorithm will 
  462.      -- fail to detect a CHARACTER drop or add if that CHARACTER
  463.      -- is the close bracket ']'.
  464.           
  465.      CHECKSUM    : NATURAL          := DSTR.SIZE;
  466.      MAX_CHECKSUM: constant NATURAL := 16000;
  467.      CALC_MAX    : constant NATURAL := 16000 + CHARACTER'pos(CHARACTER'last);
  468.      MODE        : constant NATURAL := CHARACTER'pos('Z') - CHARACTER'pos('A');
  469.  
  470.     begin
  471.       for I in 1..DSTR.SIZE loop
  472.         CHECKSUM  := CHECKSUM  +
  473.                  CHARACTER'pos(DSTR.DATA(I));
  474.         if CHECKSUM > MAX_CHECKSUM then
  475.           CHECKSUM := CHECKSUM - 1000;
  476.         end if;
  477.       end loop;
  478.       CHECKSUM  := CHECKSUM  mod MODE;
  479.       return CHARACTER'VAL(CHECKSUM  + CHARACTER'pos('A'));
  480.     end CHECKBYTE;
  481.   
  482.     begin --(DYN)
  483.       null;
  484.     exception when others => PUT("[DYN EXCEPTION]");
  485.                              raise;
  486.     end DYN;
  487.  
  488.