home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Programming Contest / Secret Solutions Folder / Problem 04 - Text Processing / Solution.p < prev   
Encoding:
Text File  |  1998-06-11  |  6.8 KB  |  213 lines  |  [TEXT/CWIE]

  1. (*
  2. Problem 04 - Text Processing
  3.  
  4. const
  5.     kMaxHandleSize = 1000000;
  6. const
  7.     kActionMove = 1;
  8.     kActionInsert = 2;
  9.     kActionDelete = 3;
  10.     kActionSearch = 4;
  11.     kActionSearchAndReplace = 5;
  12. const
  13.     kFlagCaseSenstitiveBit = 0;
  14.     kFlagGlobalBit = 1;
  15.     kFlagBackwardsBit = 2;
  16. type
  17.   ActionRecord = record
  18.     action: UInt32;
  19.     amount: SInt32;
  20.     flags: UInt32;
  21.     search: Str255;
  22.     replace: Str255;
  23.   end;
  24.   ActionRecordArray = array[0..0] of ActionRecord;
  25.   ActionRecordArrayPtr = ^ActionRecordArray;
  26.  
  27. procedure TextProcess( data: Handle; action_count: UInt32; actions: ActionRecordArrayPtr );
  28.  
  29. Given an unlocked handle to a block of text, you need to apply a sequence of actions to the data.  Internally, you must keep a current position pointer, 
  30. which starts at zero (ie, before the first character in the handle).  The internal position pointer is constrained between 0 and GetHandleSize(data) at all times, 
  31. and if it becomes less than zero (respectively greater than GetHandleSize), then you must reset it to zero (respectively GetHandleSize).  
  32. The handle size will never exceed 1 Meg, and you will have plenty of memory to play with.  Characters from chr(127)-chr(255) will never appear in the handle 
  33. or any strings.  In response to each of the actions you need to apply the following action:
  34.  
  35. kActionMove - move the internal position forward by the amount field (which may be negative).  (Example, kActionMove with amount set to kMaxHandleSize will set the internal pointer to be GetHandleSize( data )).
  36.  
  37. kActionInsert - Insert the replace string at the current location.  (Example, if the internal pointer is GetHandleSize( data ), then the replace string will be appended to the handle.
  38.  
  39. kActionDelete - Delete the number of characters specified by the amount field.  The internal pointer is never moved.  If the amount field is greater than the number of characters after the internal pointer, then fewer characters are deleted such that the handle is truncated at the internal pointer.
  40.  
  41. kActionSearch - search forward (backwards if the kFlagBackwardsBit is set in the flags field) for the search field (case sensitively if the kFlagCaseSenstitiveBit is set in the flags field).  The position pointer should be set to point before the first character of the string if it is found, or at GetHandleSize (zero if backwards) if not found.  If there is a match at the initial position, it is not counted (ie, kActionMove -kMaxHandleSize, kSearch 'hello', kSearch 'hello' finds the second occurance of 'hello').
  42.  
  43. kActionSearchAndReplace - as for search, but when a match is found, replace it with the replace string.  If the kFlagGlobalBit is set in the flags field, continue search until a match is not found but never search any characters of the replace string. (that is, if you replace 'aaa' with 'ABA' (case insensitively) in 'aaaaaaaa' you will get 'ABAABAaa', not 'ABABABAa')
  44.  
  45. [wow this needs some rewriting]
  46. [hmm, perhaps a text input would be better:
  47. MOVE<space><decimal number>
  48. INSERT<space><text>
  49. DELETE<space><decimal number>
  50. SEARCH<space>BACKWARDS<space>CASESENSITIVE<space><text>
  51. REPLACE<space>BACKWARDS<space>CASESENSITIVE<space>GLOBAL<space><text><seperator?><replace>
  52. ]
  53. *)
  54.  
  55. unit Solution;
  56.  
  57. interface
  58.  
  59. // Do not modify the interface
  60.  
  61.     uses
  62.         Types, Files;
  63.         
  64.     const
  65.         kMaxHandleSize = 1000000;
  66.     const
  67.         kActionMove = 1;
  68.         kActionInsert = 2;
  69.         kActionDelete = 3;
  70.         kActionSearch = 4;
  71.         kActionSearchAndReplace = 5;
  72.     const
  73.         kFlagCaseSenstitiveBit = 0;
  74.         kFlagGlobalBit = 1;
  75.         kFlagBackwardsBit = 2;
  76.     type
  77.       ActionRecord = record
  78.         action: UInt32;
  79.         amount: SInt32;
  80.         flags: UInt32;
  81.         search: Str255;
  82.         replace: Str255;
  83.       end;
  84.       ActionRecordArray = array[0..0] of ActionRecord;
  85.       ActionRecordArrayPtr = ^ActionRecordArray;
  86.  
  87.     procedure TextProcess( data: Handle; action_count: UInt32; actions: ActionRecordArrayPtr );
  88.  
  89. implementation
  90.  
  91. // Fill in your solution and then submit this folder
  92.  
  93. // Team Name: Example Solution
  94. // 25 minutes
  95.  
  96.     uses
  97.         TextUtils;
  98.  
  99.     function Pin( a, b, c: longint ): longint;
  100.     begin
  101.         if b < a then begin
  102.             b := a;
  103.         end else if b > c then begin
  104.             b := c;
  105.         end;
  106.         Pin := b;
  107.     end;
  108.  
  109.     function MatchAt( data: Handle; pos: longint; casesensitive: boolean; search: string ): boolean;
  110.         var
  111.             t: str255;
  112.     begin
  113.         MatchAt := false;
  114.         if (0 <= pos) & (pos + length(search) <= GetHandleSize( data )) then begin
  115.             t[0] := search[0];
  116.             BlockMoveData( Ptr(longint(data^)+pos), @t[1], length(search) );
  117.             if not casesensitive then begin
  118.                 UpperString( t, false );
  119.                 UpperString( search, false );
  120.             end;
  121.             MatchAt := t = search;
  122.         end;
  123.     end;
  124.  
  125.     procedure TextProcess( data: Handle; action_count: UInt32; actions: ActionRecordArrayPtr );
  126.         var
  127.             curpos: longint;
  128.             action: ActionRecord;
  129.             casesensitive, global, backwards: boolean;
  130.         
  131.         function DoSearch: boolean;
  132.         begin
  133.             DoSearch := false;
  134.             if backwards then begin
  135.                 Dec(curpos);
  136.                 while curpos >= 0 do begin
  137.                     if MatchAt( data, curpos, casesensitive, action.search ) then begin
  138.                         DoSearch := true;
  139.                         leave;
  140.                     end;
  141.                     Dec(curpos);
  142.                 end;
  143.             end else begin
  144.                 Inc(curpos);
  145.                 while curpos < GetHandleSize( data ) do begin
  146.                     if MatchAt( data, curpos, casesensitive, action.search ) then begin
  147.                         DoSearch := true;
  148.                         leave;
  149.                     end;
  150.                     Inc(curpos);
  151.                 end;
  152.             end;
  153.             curpos := Pin( 0, curpos + action.amount, GetHandleSize(data) );
  154.         end;
  155.         
  156.         var
  157.             junkl, i: longint;
  158.             found: boolean;
  159.     begin
  160.         curpos := 0;
  161.         for i := 1 to action_count do begin
  162.             action := actions^[i-1];
  163.             casesensitive := btst(action.flags,kFlagCaseSenstitiveBit);
  164.             global := btst(action.flags,kFlagGlobalBit);
  165.             backwards := btst(action.flags,kFlagBackwardsBit);
  166.             case action.action of
  167.                 kActionMove: begin
  168.                     curpos := Pin( 0, curpos + action.amount, GetHandleSize(data) );
  169.                 end;
  170.                 kActionInsert: begin
  171.                     junkl := Munger( data, curpos, nil, 0, @action.replace[1], length(action.replace) );
  172.                 end;
  173.                 kActionDelete: begin
  174.                     if action.amount > 0 then begin
  175.                         if curpos + action.amount >= GetHandleSize( data ) then begin
  176.                             SetHandleSize( data, curpos );
  177.                         end else begin
  178.                             junkl := Munger( data, curpos, nil, action.amount, @junkl, 0 );
  179.                         end;
  180.                     end;
  181.                 end;
  182.                 kActionSearch: begin
  183.                     found := DoSearch;
  184.                 end;
  185.                 kActionSearchAndReplace: begin
  186.                     while true do begin
  187.                         found := DoSearch;
  188.                         if found then begin
  189.                             junkl := Munger( data, curpos, nil, length(action.search), @action.replace[1], length(action.replace) );
  190.                             if global then begin
  191.                                 if backwards then begin
  192.                                     curpos := curpos - length(action.search) + 1;
  193.                                 end else begin
  194.                                     curpos := curpos + length(action.search) - 1;
  195.                                 end;
  196.                             end else begin
  197.                                 leave;
  198.                             end;
  199.                         end else begin
  200.                             leave;
  201.                         end;
  202.                     end;
  203.                     curpos := Pin( 0, curpos + action.amount, GetHandleSize(data) );
  204.                 end;
  205.                 otherwise begin
  206.                     DebugStr( 'bad' );
  207.                 end;
  208.             end;
  209.         end;
  210.     end;
  211.     
  212. end.
  213.