home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / programm / prog4 / dynstrng.ada < prev    next >
Encoding:
Text File  |  1991-07-01  |  14.6 KB  |  393 lines

  1.                                        -- Chapter 31 - Program 3
  2. -- This is a dynamic string package which can be used as an aid
  3. -- in writing string intensive programs.  Ada only has a static
  4. -- string capability, so this package was written as an example of
  5. -- how the Ada programming language can be expanded.
  6.  
  7. -- A dynamic string is defined as an array of characters of maximum
  8. -- length of 255.  The dynamic length of the dynamic string is
  9. -- stored in the Max_Length field of the record. So the string
  10. -- must be defined with a lower limit of 1 and an upper limit of
  11. -- whatever the desired maximum length of the string is to be. The
  12. -- subtype STRING_SIZE limits the string length when it is defined.
  13.  
  14. -- Put      Outputs a dynamic string to the monitor
  15. -- ConCat   Concatenates two dynamic strings and puts the result
  16. --           into a third dynamic string
  17. -- Copy     Copies a dynamic string to another dynamic string
  18. -- Copy     Copies a static string to a dynamic string
  19. -- Delete   Deletes a group of characters from a dynamic string
  20. -- Insert   Inserts a group of characters into a dynamic string
  21. -- Length   Returns the dynamic length of a dynamic string
  22. -- Size_Of  Returns the static length of a dynamic string
  23. -- Pos      Returns the first location of a dynamic string within
  24. --           another dynamic string
  25.  
  26. with Text_IO; use Text_IO;
  27. package DynStrng is
  28.  
  29.    subtype STRING_SIZE is INTEGER range 0..255;
  30.    type STRING_ARRAY is array(STRING_SIZE range <>) of CHARACTER;
  31.  
  32.    type DYNAMIC_STRING(Maximum_Length : STRING_SIZE) is
  33.       record
  34.          Dynamic_Length  : INTEGER range 0..255;
  35.          String_Data     : STRING_ARRAY(1..Maximum_Length);
  36.       end record;
  37.  
  38.  
  39. -- Put : Display a dynamic string on the monitor.
  40. procedure Put(Input_String : in     DYNAMIC_STRING);
  41.  
  42.  
  43. -- ConCat : Concatenation - The First_String is copied into the
  44. --             Result_String, then the Second_String is copied
  45. --             into the Result_String following the First_String.
  46. --             If all characters fit, Result is set to TRUE.
  47. --             If Result_String will not hold all characters,
  48. --             only as many as will fit are copied and Result
  49. --             is set to FALSE.
  50. --             Result = TRUE, complete copy done.
  51. --             Result = FALSE, some or all not copied
  52. procedure ConCat(First_String  : in     DYNAMIC_STRING;
  53.                  Second_String : in     DYNAMIC_STRING;
  54.                  Result_String : in out DYNAMIC_STRING;
  55.                  Result        :    out BOOLEAN);
  56.  
  57.  
  58. -- Copy : The String contained in Input_String is copied into
  59. --             the string Output_String.  This procedure is
  60. --             overloaded to include copying from either dynamic
  61. --             strings or static strings.
  62. --             Result = TRUE, complete copy done
  63. --             Result = FALSE, some or all not copied
  64. procedure Copy(Input_String  : in     DYNAMIC_STRING;
  65.                Output_String : in out DYNAMIC_STRING;
  66.                Result        :    out BOOLEAN);
  67. procedure Copy(Input_String  : in     STRING;
  68.                Output_String :    out DYNAMIC_STRING;
  69.                Result        :    out BOOLEAN);
  70.  
  71.  
  72. -- Delete : Beginning at First_Position, as many characters as are
  73. --             indicated by Number_Of_Characters are deleted from
  74. --             String_To_Modify.  If there are not that many, only
  75. --             as many as are left are deleted.
  76. --             Result = TRUE, deletion was complete
  77. --             Result = FALSE, only a partial deletion was done
  78. procedure Delete(String_To_Modify     : in out DYNAMIC_STRING;
  79.                  First_Position       : in     STRING_SIZE;
  80.                  Number_Of_Characters : in     STRING_SIZE;
  81.                  Result               :    out BOOLEAN);
  82.  
  83.  
  84. -- Insert : The string String_To_Insert is inserted into the string
  85. --             String_To_Modify begining at location Place_To_Insert
  86. --             if there is enough room.
  87. --             Result = TRUE, insert completed in full
  88. --             Result = FALSE, not enough room for full insert
  89. procedure Insert(String_To_Modify : in out DYNAMIC_STRING;
  90.                  String_To_Insert : in     DYNAMIC_STRING;
  91.                  Place_To_Insert  : in     STRING_SIZE;
  92.                  Result           :    out BOOLEAN);
  93.  
  94.  
  95. -- Length : Returns the dynamic length of the string defined by
  96. --             String_To_Measure.
  97. function Length(String_To_Measure : in DYNAMIC_STRING)
  98.                  return STRING_SIZE;
  99.  
  100.  
  101. -- Size_Of : Returns the static length of the string, the actual
  102. --             upper limit of the string definition.
  103. function Size_Of(String_To_Measure : in DYNAMIC_STRING)
  104.                  return STRING_SIZE;
  105.  
  106.  
  107. -- Pos : Position of substring - The string String_To_Search is
  108. --             searched for the string Required_String beginning
  109. --             at Place_To_Start.
  110. --             Result = TRUE, a search was possible
  111. --             Result = FALSE, no search could be made
  112. --             Location_Found = 0, no string found
  113. --             Location_Found = N, start of matching string
  114. procedure Pos(String_To_Search : in     DYNAMIC_STRING;
  115.               Required_String  : in     DYNAMIC_STRING;
  116.               Place_To_Start   : in     STRING_SIZE;
  117.               Location_Found   :    out STRING_SIZE;
  118.               Result           :    out BOOLEAN);
  119.  
  120. end DynStrng;
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128. package body DynStrng is
  129.  
  130.                -- The display procedure overloads the existing
  131.                -- Put procedures to output a dynamic string. Note
  132.                -- that the existing Put is used in this new Put.
  133. procedure Put(Input_String : in     DYNAMIC_STRING) is
  134. begin
  135.    for Index in 1..Input_String.Dynamic_Length loop
  136.       Put(Input_String.String_Data(Index));
  137.    end loop;
  138. end Put;
  139.  
  140.  
  141.  
  142.  
  143. procedure ConCat(First_String  : in     DYNAMIC_STRING;
  144.                  Second_String : in     DYNAMIC_STRING;
  145.                  Result_String : in out DYNAMIC_STRING;
  146.                  Result        :    out BOOLEAN) is
  147. Intermediate_Result : BOOLEAN;
  148. Character_Count     : STRING_SIZE;
  149. Room_Left           : STRING_SIZE;
  150. begin
  151.                        -- Copy the first into the result string
  152.    Copy(First_String,Result_String,Intermediate_Result);
  153.    if Intermediate_Result then
  154.       Character_Count := Second_String.Dynamic_Length;
  155.       Room_Left := Result_String.String_Data'LAST
  156.                                 - Result_String.Dynamic_Length;
  157.       Result := TRUE;
  158.       if Character_Count > Room_Left then
  159.          Character_Count := Room_Left;
  160.          Result := FALSE;
  161.       end if;
  162.       for Index in 1..Character_Count loop
  163.          Result_String.String_Data
  164.                  (Index + Result_String.Dynamic_Length) :=
  165.                                      Second_String.String_Data(Index);
  166.       end loop;
  167.       Result_String.Dynamic_Length :=
  168.                     Result_String.Dynamic_Length + Character_Count;
  169.    else
  170.       Result := FALSE;
  171.    end if;
  172. end ConCat;
  173.  
  174.  
  175.  
  176.  
  177.                -- This procedure overloads the name Copy to
  178.                -- copy from one dynamic string to another.
  179. procedure Copy(Input_String  : in     DYNAMIC_STRING;
  180.                Output_String : in out DYNAMIC_STRING;
  181.                Result        :    out BOOLEAN) is
  182. Character_Count : STRING_SIZE;
  183. begin
  184.                        -- First pick the smallest string size
  185.    Character_Count := Input_String.Dynamic_Length;
  186.    if Character_Count > Output_String.String_Data'LAST then
  187.       Character_Count := Output_String.String_Data'LAST;
  188.       Result := FALSE; -- The entire string didn't fit
  189.    else
  190.       Result := TRUE;  -- The entire string fit
  191.    end if;
  192.  
  193.    for Index in 1..Character_Count loop
  194.       Output_String.String_Data(Index) :=
  195.                                Input_String.String_Data(Index);
  196.    end loop;
  197.    Output_String.Dynamic_Length := Character_Count;
  198. end Copy;
  199.  
  200.  
  201.  
  202.  
  203.                -- This routine overloads the copy procedure name
  204.                -- to copy a static string into a dynamic string.
  205. procedure Copy(Input_String  : in     STRING;
  206.                Output_String :    out DYNAMIC_STRING;
  207.                Result        :    out BOOLEAN) is
  208. Character_Count : STRING_SIZE;
  209. begin
  210.                        -- First pick the smallest string size
  211.    Character_Count := Input_String'LAST;
  212.    if Character_Count > Output_String.String_Data'LAST then
  213.       Character_Count := Output_String.String_Data'LAST;
  214.       Result := FALSE; -- The entire string didn't fit
  215.    else
  216.       Result := TRUE;  -- The entire string fit
  217.    end if;
  218.  
  219.    for Index in 1..Character_Count loop
  220.       Output_String.String_Data(Index) :=
  221.                                Input_String(Index);
  222.    end loop;
  223.    Output_String.Dynamic_Length := Character_Count;
  224. end Copy;
  225.  
  226.  
  227.  
  228.  
  229. procedure Delete(String_To_Modify     : in out DYNAMIC_STRING;
  230.                  First_Position       : in     STRING_SIZE;
  231.                  Number_Of_Characters : in     STRING_SIZE;
  232.                  Result               :    out BOOLEAN) is
  233. Number_To_Delete       : STRING_SIZE;
  234. Number_To_Move         : STRING_SIZE;
  235. Last_Dynamic_Character : STRING_SIZE :=
  236.                                 String_To_Modify.Dynamic_Length;
  237. begin
  238.                          -- can we delete any at all?
  239.    if First_Position > Last_Dynamic_Character then
  240.       Result := FALSE;
  241.       return;
  242.    end if;
  243.                          -- Decide how many to delete
  244.    if (First_Position + Number_Of_Characters)
  245.                                    > Last_Dynamic_Character then
  246.       Number_To_Delete := Last_Dynamic_Character
  247.                                              - First_Position + 1;
  248.       Result := FALSE;
  249.    else
  250.       Number_To_Delete := Number_Of_Characters;
  251.       Result := TRUE;
  252.    end if;
  253.  
  254.                   -- find out how many to move back
  255.    if (Last_Dynamic_Character - (First_Position + Number_To_Delete))
  256.                                                            >= 0 then
  257.       Number_To_Move := 1 + Last_Dynamic_Character
  258.                            - (First_Position + Number_To_Delete);
  259.    else
  260.       Number_To_Move := 0;
  261.    end if;
  262.  
  263.                   -- now delete the characters by moving them back
  264.    for Index in First_Position..
  265.                           (First_Position + Number_To_Move - 1) loop
  266.       String_To_Modify.String_Data(Index) :=
  267.               String_To_Modify.String_Data(Index + Number_To_Delete);
  268.    end loop;
  269.    String_To_Modify.Dynamic_Length :=
  270.                  String_To_Modify.Dynamic_Length - Number_To_Delete;
  271. end Delete;
  272.  
  273.  
  274.  
  275.  
  276. procedure Insert(String_To_Modify : in out DYNAMIC_STRING;
  277.                  String_To_Insert : in     DYNAMIC_STRING;
  278.                  Place_To_Insert  : in     STRING_SIZE;
  279.                  Result           :    out BOOLEAN) is
  280. Number_To_Add  : STRING_SIZE;
  281. Number_To_Move : STRING_SIZE;
  282. Room_Left      : STRING_SIZE;
  283. begin
  284.                         -- Can we add any at all?
  285.    if (Place_To_Insert > String_To_Modify.String_Data'LAST) or
  286.      (Place_To_Insert > String_To_Modify.Dynamic_Length + 1) then
  287.       Result := FALSE;
  288.       return;
  289.    end if;
  290.    Result := TRUE;
  291.  
  292.                         -- How many can we add?
  293.    Number_To_Add := String_To_Modify.String_Data'LAST
  294.                                                - Place_To_Insert + 1;
  295.    if Number_To_Add > String_To_Insert.Dynamic_Length then
  296.       Number_To_Add := String_To_Insert.Dynamic_Length;
  297.    end if;
  298.  
  299.                         -- Find how many to move forward
  300.    Number_To_Move := String_To_Modify.Dynamic_Length
  301.                                              - Place_To_Insert + 1;
  302.    Room_Left := String_To_Modify.String_Data'LAST
  303.                                              - Place_To_Insert + 1;
  304.    if Room_Left < Number_To_Move then
  305.       Number_To_Move := Room_Left;
  306.    end if;
  307.  
  308.                         -- Move them forward
  309.    for Index in reverse Place_To_Insert..Place_To_Insert
  310.                                          + Number_To_Move - 1 loop
  311.       String_To_Modify.String_Data(Index + Number_To_Add) :=
  312.                                  String_To_Modify.String_Data(Index);
  313.    end loop;
  314.    for Index in 1..Number_To_Add loop
  315.       String_To_Modify.String_Data(Index + Place_To_Insert - 1) :=
  316.                                   String_To_Insert.String_Data(Index);
  317.    end loop;
  318.  
  319.                         -- Increase the length of the string
  320.    String_To_Modify.Dynamic_Length :=
  321.                    String_To_Modify.Dynamic_Length + Number_To_Add;
  322.    if String_To_Modify.Dynamic_Length >
  323.                                String_To_Modify.String_Data'LAST then
  324.       String_To_Modify.Dynamic_Length := String_To_Modify.String_Data'LAST;
  325.    end if;
  326.  
  327. end Insert;
  328.  
  329.  
  330.  
  331.  
  332.                -- This returns the dynamic length of a string
  333. function Length(String_To_Measure : in DYNAMIC_STRING)
  334.                  return STRING_SIZE is
  335. begin
  336.    return String_To_Measure.Dynamic_Length;
  337. end Length;
  338.  
  339.  
  340.  
  341.  
  342.                -- This returns the static length of a string
  343. function Size_Of(String_To_Measure : in DYNAMIC_STRING)
  344.                  return STRING_SIZE is
  345. begin
  346.    return String_To_Measure.String_Data'LAST;
  347. end Size_Of;
  348.  
  349.  
  350.  
  351.  
  352. procedure Pos(String_To_Search : in     DYNAMIC_STRING;
  353.               Required_String  : in     DYNAMIC_STRING;
  354.               Place_To_Start   : in     STRING_SIZE;
  355.               Location_Found   :    out STRING_SIZE;
  356.               Result           :    out BOOLEAN) is
  357. End_Search             : STRING_SIZE;
  358. Characters_All_Compare : BOOLEAN;
  359. begin
  360.    Location_Found := 0;
  361.                           -- can we search the string at all?
  362.    if (Place_To_Start < String_To_Search.Dynamic_Length) and
  363.            (Place_To_Start < String_To_Search.String_Data'LAST) then
  364.       Result := TRUE;
  365.    else
  366.       Result := FALSE;
  367.       return;
  368.    end if;
  369.  
  370.                           -- search the loop for the string now
  371.    End_Search := String_To_Search.Dynamic_Length -
  372.                                   Required_String.Dynamic_Length + 1;
  373.  
  374.    for Index in Place_To_Start..End_Search loop      -- search loop
  375.       Characters_All_Compare := TRUE;
  376.       for Count in 1..Required_String.Dynamic_Length loop
  377.          if Required_String.String_Data(Count) /=
  378.                  String_To_Search.String_Data(Count + Index - 1) then
  379.             Characters_All_Compare := FALSE;
  380.             exit;         -- exit loop, a character did not match
  381.          end if;
  382.       end loop;
  383.       if Characters_All_Compare then
  384.          Location_Found := Index;
  385.          return;             -- string match found, return location
  386.       end if;
  387.    end loop;  -- end search loop
  388.  
  389. end Pos;
  390.  
  391. end DynStrng;
  392.  
  393.