home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / GET10.ZIP / GETSTR.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-11-09  |  21.1 KB  |  789 lines

  1. procedure getstr
  2.  
  3.    (str_prompt:       string;
  4.     atr,atc:          byte;     {row,col}
  5. var instr:            string;   {string to edit}
  6.     picture:          string;   {input picture/mask}
  7.     maxstrlen:        plusbyte; {maximum length of string, 1..255}
  8.     status:           byte);
  9.  
  10. begin
  11.  
  12.   getstring(str_prompt,Default_pattr,atr,atc,Default_dattr,
  13.             Default_cursor_attr,instr,picture,maxstrlen,status);
  14. end;
  15.  
  16.  
  17. procedure getstring
  18.  
  19.    (str_prompt:       string;
  20.     pattr,                      {prompt attribute}
  21.     atr,atc,                    {row,col}
  22.     attr,cursor_attr: byte;     {string & cursor attributes}
  23. var instr:            string;   {string to edit}
  24.     picture:          string;   {input picture/mask}
  25.     maxstrlen:        plusbyte; {maximum length of string, 1..255}
  26.     status:           byte);
  27.  
  28. {
  29.   This procedure gets a string from the screen. A variety of editing commands
  30.   are supported. The string need not be contiguous, it may contain embedded
  31.   characters on display and can be validated on character by character basis.
  32. }
  33.  
  34. var
  35.     I,
  36.     NumberOfCharacters,
  37.     NumberOfMarkers: integer;
  38.  
  39.     SizeOfSubstring1,
  40.     oldcp:           byte; {type byte to enable use of 0 as signal value}
  41.  
  42.     breaks,line_offset: byte;
  43.  
  44.     firstcp,
  45.     fromcp:          plusbyte; {cursor position: 1..255}
  46.  
  47.     original_string: string;
  48.  
  49.     lettertype,
  50.     picsel,                {not to be confused with pixel!}
  51.     letter:          char;
  52.  
  53.     mandatory,
  54.     fixed_length,
  55.     StringIsContiguous,
  56.     ValidateOff,
  57.     PictureAllX,
  58.     OldOverwrite,
  59.     LocalInsLock,
  60.     finished:        boolean;
  61.  
  62.     charpos:         array [1..255] of byte;
  63.     chartype:        array [1..255] of CharacterSetType;
  64.     charcase:        array [1..255] of boolean;
  65.  
  66.     fmarray:         array [1..255] of record
  67.                        location:   byte; {screen location}
  68.                        markerchar: char; {field marker}
  69.                      end;
  70.  
  71. procedure gotocp (newcp: byte);
  72. {
  73.   This procedure can use an unblinking cursor made using a video attribute
  74.   or the "real thing." Both are used if overwrite is on and a video cursor
  75.   is in use.
  76. }
  77. var fattr: byte;
  78.  
  79. procedure position_real_cursor;
  80. begin
  81.   gotorc(atr,charpos[newcp]);
  82. end;
  83.  
  84. begin
  85.   if (FieldCursor <> 0) then
  86.     fattr := FieldCursor
  87.   else fattr := attr;
  88.  
  89.   if cursor_attr <> attr then {using video attibute for cursor}
  90.  
  91.     begin
  92.       if oldcp <> newcp then
  93.         begin
  94.           if oldcp <> 0 then {remove old cursor}
  95.             Qattr(atr,charpos[oldcp],1,1,fattr);
  96.           if not finished then  {make a new one}
  97.             Qattr(atr,charpos[newcp],1,1,cursor_attr);
  98.         end;
  99.  
  100.       if overwrite then
  101.         position_real_cursor;
  102.     end
  103.  
  104.   else position_real_cursor;
  105.  
  106.   oldcp := cp;
  107.   cp := newcp;
  108. end;
  109.  
  110.  
  111. procedure show_string;
  112. var I,
  113.     fattr,
  114.     PicAttr,
  115.     strlen: byte;
  116.  
  117. function StringIsUnbroken: boolean;
  118. begin
  119.   StringIsUnbroken := (NumberOfMarkers = 0) and StringIsContiguous;
  120. end;
  121.  
  122. begin
  123.   oldcp := 0;
  124.  
  125.   if EditingField and not (finished or escaped) then
  126.     begin
  127.       if FieldCursor <> 0 then
  128.         fattr := FieldCursor;
  129.       if PicCursor <> 0 then
  130.         PicAttr := PicCursor;
  131.       end
  132.   else
  133.     begin
  134.       fattr := attr;
  135.       PicAttr := fattr;
  136.     end;
  137.  
  138. {
  139.   Output field markers
  140. }
  141.  
  142.   I := 1;
  143.   while fmarray[I].location <> 0 do
  144.     begin
  145.       Qwrite(atr,fmarray[I].location,PicAttr,fmarray[I].markerchar);
  146.       inc(I);
  147.     end;
  148.  
  149. {
  150.   Blank from end of string to end of field
  151. }
  152.  
  153.   strlen := length(instr);
  154.   if StringIsUnbroken then
  155.     Qfill(atr,atc + strlen,1,maxstrlen - strlen,fattr,' ')
  156.   else if strlen < maxstrlen then
  157.     for I := succ(strlen) to maxstrlen do
  158.       Qwrite(atr,charpos[I],fattr,' ');
  159.  
  160. {
  161.   Output string
  162. }
  163.  
  164.   if PasswordField then
  165.     for I := 1 to length(instr) do
  166.       Qwrite(atr,charpos[I],fattr,PasswordChar)
  167.   else
  168.     begin
  169.       if StringIsUnbroken then
  170.  
  171.        if not top_n_tail and (instr = original_string) then    {needn't rewrite}
  172.           Qattr(atr,charpos[1],1,ord(instr[0]),fattr)          {... change attr}
  173.        else QwriteA(atr,charpos[1],fattr,ord(instr[0]),instr[1])
  174.  
  175.       else {string contains field markers or is not contiguous}
  176.  
  177.         for I := 1 to length(instr) do
  178.            Qwrite(atr,charpos[I],fattr,instr[I]);
  179.  
  180. (*
  181.         To show duff characters in string using RedAttr:
  182.  
  183.         begin
  184.           if (instr[I] in CharacterSet[chartype[I]].CharSet) or
  185.             (chartype[I] = AnyCharacter) then
  186.             chattr := fattr
  187.           else chattr := RedAttr;
  188.           Qwrite(atr,pred(atc) + charpos[I],chattr,instr[I]);
  189.         end;
  190. *)
  191.     end;
  192. end;
  193.  
  194.  
  195. procedure show_cursor;
  196. {
  197.  Sets cursor type. See GET.DOC.
  198. }
  199. begin
  200.   gotocp(cp);
  201.   if overwrite then
  202.     SetCursor(CursorOn or CursorUnderline)
  203.   else {insert}
  204.     if cursor_attr = attr then
  205.       SetCursor(CursorOn or CursorBlock)   {not using video cursor}
  206.     else ModCursor(CursorOff); {using video cursor}
  207. end;
  208.  
  209.  
  210. procedure restore_string;
  211. begin
  212.   instr := original_string;
  213.   show_string;
  214. end;
  215.  
  216.  
  217. procedure validate_field;
  218.  
  219. procedure check_character_types;
  220. var I: byte;
  221. begin
  222.   I := 1;
  223.   while (I <= length(instr)) and Error2LineClear do
  224.     if (instr[I] in CharacterSet[chartype[I]].CharSet) or
  225.       (chartype[I] = AnyCharacter) then
  226.       inc(I)
  227.     else
  228.       begin
  229.         error2(CharacterSet[chartype[I]].CharacterSetName
  230.                + CharacterWord + RequiredWord);
  231.         cp := I; {put the cursor on the bad character}
  232.       end;
  233. end;
  234.  
  235. begin
  236.   finished := PasswordField or ValidateOff;
  237.   if not finished then
  238.     begin
  239.       clearerror2;
  240.       if not PictureAllX then
  241.         check_character_types;
  242.  
  243.       if Error2LineClear then
  244.  
  245.         if (instr = '') then
  246.           if not mandatory then
  247.             finished := true
  248.           else error2(Null_input_not_allowed)
  249.         else if fixed_length and (ord(instr[0]) <> maxstrlen) then
  250.                error2(Fixed_length_input_required)
  251.              else finished := true;
  252.     end;
  253. end;
  254.  
  255.  
  256. procedure enter_a_letter (letter: char);
  257. {
  258.   Fixed length fields are completed automatically when a character is
  259.   entered in the last character position, but not otherwise -- even
  260.   if the field is full (i.e., insertion of characters before the end
  261.   of the field will not effect field completion).
  262.  
  263.   validate_field is executed in case a field has been moved into with the
  264.   cursor on the last character position and a character entered. E.g.,
  265.   cursor moves from field 2 here to field 1:
  266.  
  267.           field 1       field 2
  268.  content   ABC_      <- anything
  269.  picture   999X         XXXXXXXX
  270.  
  271.  Note that the contents of field 1 are invalid
  272.  
  273. }
  274. begin
  275.   if ForceUppercase then
  276.     letter := upcase(letter);
  277.  
  278.   if cp > length(instr) then {pad with spaces}
  279.     begin
  280.       while length(instr) < pred(cp) do
  281.         instr := instr + ' ';
  282.       instr[cp] := letter;
  283.       instr[0] := chr(cp); {set length}
  284.     end
  285.   else
  286.     begin
  287.       if overwrite then
  288.         instr[cp] := letter
  289.       else {insert}
  290.         begin
  291.           if length(instr) = maxstrlen then
  292.             instr[0] := chr(pred(maxstrlen));
  293.           insert(letter,instr,cp);
  294.         end;
  295.     end;
  296.  
  297.   if cp < maxstrlen then
  298.     inc(cp)
  299.   else if (length(instr) = maxstrlen) and
  300.          (fixed_length or StringFieldWrap) then
  301.            begin
  302.              validate_field; {sets finished true or false}
  303.              if finished then
  304.                cp := 1;
  305.            end;
  306.  
  307.   show_string;
  308. end;
  309.  
  310.  
  311. procedure setup_picture_attributes;
  312. var LastLineStart,
  313.     last_picture_index,
  314.     repeat_count,
  315.     I,J,K,L:          integer;
  316.  
  317.     AttributeSet,
  318.     Duplicate,
  319.     Shift,
  320.     CopyLiteral:        boolean;
  321.  
  322. function transfer: boolean;
  323. { just used to make inline code a little more readable }
  324. begin
  325.   transfer := (picture[I] in CharacterSet[FieldMarkers].CharSet) or
  326.               (CopyLiteral and (picture[I] <> DefaultAltSwitch));
  327. end;
  328.  
  329. function PicType (picchar: char): CharacterSetType;
  330. begin
  331.   case upcase(picchar) of
  332.     'A': PicType := Alphabetic;
  333.     'C': PicType := Alphanumeric;
  334.     'P': PicType := Printable;
  335.     '9': PicType := Numeric;
  336.   else
  337.     PicType := AnyCharacter;
  338.   end; {case}
  339. end;
  340.  
  341. procedure enter_a_field_marker_or_literal;
  342. begin
  343.   if picture[I] = 'B' then
  344.     picsel := ' '
  345.   else picsel := chr(ord(picture[I])); {TP v4.0 enforced conversion}
  346.  
  347.   fmarray[K].markerchar := picsel; {field marker}
  348.   fmarray[K].location := L;        {screen location}
  349.   inc(K);
  350.   inc(L);
  351. end;
  352.  
  353. procedure set_attribute (picture_index: integer);
  354. begin
  355.   chartype[J] := PicType(picture[picture_index]);
  356.   PictureAllX := PictureAllX and (chartype[J] = AnyCharacter);
  357.  
  358.   if J > 1 then {set Insert lock on if character type changes}
  359.     LocalInsLock := LocalInsLock or (chartype[J] <> chartype[pred(J)]);
  360.  
  361.   charpos[J] := L;
  362.   charcase[J] := picture[picture_index] in ['A'..'Z'];
  363.   inc(J);
  364.   inc(L);
  365.  
  366.   last_picture_index  := picture_index;
  367.   AttributeSet := true;
  368. end;
  369.  
  370. begin
  371.   if length(picture) = 0 then
  372.     picture := 'x';
  373.  
  374.   fillchar(fmarray,sizeof(fmarray),0);
  375.   StringIsContiguous := true;
  376.   SizeOfSubstring1 := 0;
  377.   Duplicate := false;
  378.   Shift := false;
  379.   AttributeSet := false;
  380.   PictureAllX := true;
  381.   CopyLiteral := false;
  382.   LocalInsLock := InsLock or PasswordField;
  383. {
  384.   Local Insert not locked unless > 1 type in string or InsLock already set
  385.   or PasswordField is true.
  386. }
  387.  
  388.   L := 0; {screen location: offset for now, convert to absolute location later}
  389.   J := 1; {character index}
  390.   K := 1; {marker index}
  391.   LastLineStart := L;
  392.  
  393.   I := 1;
  394.   repeat
  395.     begin
  396.  
  397.       if picture[I] = DefaultAltSwitch then
  398.         CopyLiteral := not CopyLiteral;
  399.  
  400.  
  401.       if Duplicate then
  402.         begin
  403.           repeat_count := ord(picture[I]);
  404.           while (repeat_count > 0) and (J > 0) do {J will wrap to 0 after 255}
  405.             begin
  406.               set_attribute(last_picture_index);
  407.               dec(repeat_count);
  408.             end;
  409.           Duplicate := false;
  410.         end
  411.  
  412.       else if Shift then
  413.         begin
  414.           if picture[I] = 'N' then
  415.             L := LastLineStart + CRTcols
  416.           else inc(L,ord(picture[I]));
  417.           LastLineStart := L;
  418.           Shift := false;
  419.         end
  420.  
  421.       else if transfer then
  422.              enter_a_field_marker_or_literal
  423.  
  424.       else if picture[I] = ShiftCharacter then
  425.         begin
  426.           Shift := true;
  427.           StringIsContiguous :=  false;
  428.           if SizeOfSubstring1 = 0 then
  429.             SizeOfSubstring1 := pred(I);
  430.         end
  431.  
  432.       else if (picture[I] = RepeatCharacter) and AttributeSet then
  433.              Duplicate := true
  434.  
  435.       else if picture[I] <> DefaultAltSwitch then
  436.              set_attribute(I);
  437.  
  438.       inc(I);
  439.     end;
  440.   until (I > length(picture)) or (J = 0) {wrap: 255 + 1 = 0};
  441.  
  442.  
  443.   while J <= maxstrlen do
  444.     begin
  445.       if J = 1 then { picture had only field markers... assume PIC X}
  446.         begin
  447.           chartype[1] := AnyCharacter;
  448.           charcase[1] := false;
  449.         end
  450.       else
  451.         begin
  452.           chartype[J] := chartype[pred(J)]; {copy the last character type}
  453.           charcase[J] := charcase[pred(J)]; { and case}
  454.         end;
  455.  
  456.       charpos[J] := L;
  457.       inc(J);
  458.       inc(L);
  459.     end;
  460.  
  461.   NumberOfMarkers    := pred(K);
  462.   NumberOfCharacters := pred(J);
  463.  
  464. end;
  465.  
  466.  
  467. function EditingString: boolean;
  468. {
  469.   This function is used to prevent editing of a field full of markers
  470. }
  471. begin
  472.   EditingString := EditingField and (NumberOfCharacters > 0);
  473. end;
  474.  
  475.  
  476. procedure restore_and_validate;
  477. begin
  478.   restore_string;
  479.   validate_field;
  480. end;
  481.  
  482.  
  483. procedure get_input;
  484. var I: byte;
  485. begin
  486.   command := extendkey;
  487.   action := get_edit(command);
  488.  
  489.   clearerror2;
  490.  
  491.   case action of
  492.  
  493.     goto_start:
  494.  
  495.                  cp := 1;
  496.  
  497.     goto_end:
  498.  
  499.                  if length(instr) > 0 then
  500.                    if length(instr) = maxstrlen then
  501.                      cp := maxstrlen
  502.                    else cp := succ(length(instr))
  503.                  else cp := 1;
  504.  
  505.     leftchar:    if cp > 1 then
  506.                    dec(cp)
  507.                  else if StringFieldWrap then
  508.                    begin
  509.                      validate_field;           {sets finished true or false}
  510.                      if finished then
  511.                        cp := 255;      {force to end of any previous string}
  512.                    end;
  513.  
  514.     rightchar:   if cp < maxstrlen then
  515.                    inc(cp)
  516.                  else if StringFieldWrap then
  517.                    begin
  518.                      validate_field;           {sets finished true or false}
  519.                      if finished then
  520.                        cp := 1;     {force to start of any following string}
  521.                    end;
  522.  
  523.     toggle_mode: if not LocalInsLock then
  524.                    begin
  525.                      overwrite := not overwrite;
  526.                      show_cursor;
  527.                    end;
  528.  
  529.     del_to_end:  {delete to end of line}
  530.                  begin
  531.                    instr := copy(instr,1,pred(cp));
  532.                    show_string;
  533.                  end;
  534.  
  535.     del_to_start: {delete to start of line}
  536.                  begin
  537.                    delete(instr,1,pred(cp));
  538.                    show_string;
  539.                    cp := 1;
  540.                  end;
  541.  
  542.     del_line:   {delete line}
  543.                  begin
  544.                    instr := '';
  545.                    show_string;
  546.                    cp := 1;
  547.                  end;
  548.  
  549.     oops:        {restore original string and cursor position}
  550.                  begin
  551.                    restore_string;
  552.                    cp := firstcp;
  553.                    show_cursor;
  554.                  end;
  555.  
  556.     tabover:     {enter spaces to the next tab stop -- defined by tabsize}
  557.                  if tabsize > 0 then
  558.                    for I := 1 to tabsize - (cp mod tabsize) do
  559.                      enter_a_letter(' ')
  560.                  else validate_field;
  561.  
  562.     leftword:    {word left}
  563.                  if (cp > 1) and (length(instr) > 1) then
  564.                    begin
  565.                      dec(cp);
  566.                      while (cp >= 1) and (instr[cp] = ' ') do
  567.                        dec(cp); {skip over whitespace}
  568.                      while (cp >= 1) and (instr[cp] <> ' ') do
  569.                        dec(cp); {skip over text}
  570.                      inc(cp);
  571.                    end;
  572.  
  573.     rightword:   {word right}
  574.                  if cp <= length(instr) then
  575.                    begin
  576.                      while (cp < length(instr)) and (instr[cp] <> ' ') do
  577.                        inc(cp); {skip over text}
  578.                      if cp < maxstrlen then
  579.                        inc(cp); {skip over space}
  580.                      while (cp < length(instr)) and (instr[cp] = ' ') do
  581.                        inc(cp); {skip over whitespace}
  582.                    end;
  583.  
  584.     del_word:    {delete next word}
  585.                  begin
  586.                    fromcp := cp;
  587.                      while (cp <= length(instr)) and (instr[cp] <> ' ') do
  588.                        inc(cp); {skip over text}
  589.                      while (cp <= length(instr)) and (instr[cp] = ' ') do
  590.                        inc(cp); {skip over whitespace}
  591.                    delete(instr,fromcp,cp - fromcp);
  592.                    cp := fromcp;
  593.                    show_string;
  594.                  end;
  595.  
  596.     backspace:   {delete the previous character}
  597.                  if cp > 1 then
  598.                    begin
  599.                      dec(cp);
  600.                      delete(instr,cp,1);
  601.                      show_string;
  602.                    end;
  603.  
  604.     del_char:    {delete character}
  605.                  begin
  606.                    delete(instr,cp,1);
  607.                    show_string;
  608.                  end;
  609.  
  610.     escapefrom:  begin
  611.                    escaped := true;
  612.                    restore_string;
  613.                    cp := firstcp;
  614.                    show_cursor;
  615.                  end;
  616.  
  617.     carriage_return: begin
  618.                        validate_field;
  619.                        if finished then
  620.                          cp := 1;
  621.                      end;
  622.  
  623.     reset:       If ValidationOverride then
  624.                    begin
  625.                      for I := 1 to maxstrlen do
  626.                        chartype[I] := AnyCharacter;
  627.                      mandatory := false;
  628.                      fixed_length := false;
  629.                      {or.. ValidateOff := true}
  630.                      info2(Validation_suspended)
  631.                    end
  632.                  else error2(No_privilege);
  633.  
  634.     post_letter: begin
  635.                    letter := chr(asciicode);
  636.  
  637.                    if charcase[cp] then
  638.                      letter := upcase(letter);
  639.  
  640.                    if (letter in CharacterSet[chartype[cp]].CharSet) or
  641.                      (chartype[cp] = AnyCharacter) or PasswordField then
  642.                      enter_a_letter(letter)
  643.                    else error2(CharacterSet[chartype[cp]].CharacterSetName
  644.                                + CharacterWord + RequiredWord);
  645.                  end;
  646.  
  647.     enter_default: validate_field;
  648.  
  649. {
  650.   Customise the following list as required
  651. }
  652.     help,
  653.     abort:       begin
  654.                    restore_string;
  655.                    finished := true;
  656.                  end;
  657.  
  658.     upchar:      if not StringIsContiguous and (cp > 1) then
  659.                    begin
  660.                      breaks := 0;
  661.                      line_offset := 0;
  662.  
  663.                      while (cp > 1) and (breaks < 2) do
  664.                        begin
  665.                          if charpos[cp] - charpos[pred(cp)] > 1 then
  666.                             inc(breaks)
  667.                          else if breaks = 0 then
  668.                            inc(line_offset);
  669.                          if breaks < 2 then
  670.                            dec(cp);
  671.                        end;
  672.  
  673.                      if breaks > 0 then
  674.                        while line_offset > 0 do
  675.                          begin
  676.                            inc(cp);
  677.                            dec(line_offset);
  678.                          end;
  679.  
  680.                    end
  681.  
  682.                  else restore_and_validate;
  683.  
  684.  
  685.     downchar:    if not StringIsContiguous and (cp < maxstrlen) then
  686.                    begin
  687.                      breaks := 0;
  688.                      line_offset := 0;
  689.  
  690.                      while (cp < maxstrlen) and (breaks < 2) do
  691.                        begin
  692.                          if charpos[succ(cp)] - charpos[cp] > 1 then
  693.                             inc(breaks)
  694.                          else if breaks = 0 then
  695.                            inc(line_offset);
  696.                          if breaks < 2 then
  697.                            inc(cp);
  698.                        end;
  699.  
  700.                      if breaks > 0 then
  701.                        while line_offset > 0 do
  702.                          begin
  703.                            dec(cp);
  704.                            dec(line_offset);
  705.                          end;
  706.  
  707.                    end
  708.  
  709.                  else restore_and_validate;
  710.  
  711.  
  712.     pageup,
  713.     scrollup,
  714.     goto_top:      restore_and_validate;
  715.  
  716.     pagedown,
  717.     scrolldown,
  718.     goto_bottom:   restore_and_validate;
  719.  
  720.     tabback,
  721.     del_block,
  722.     restore_block,
  723.     exit_screen,
  724.     quit:
  725.                    restore_and_validate; {cp unchanged}
  726.   end; {case}
  727.  
  728.   if (cp <> oldcp) or (attr <> cursor_attr) then
  729.     gotocp(cp); {move cursor}
  730.   oldcp := cp;
  731. end;
  732.  
  733.  
  734. begin {getstring}
  735.  
  736.   instr := copy(instr,1,maxstrlen); {discard anything beyond max string length}
  737.   setup_picture_attributes;  {locks insert if validation is position dependent}
  738.  
  739.   display_prompt(str_prompt,atr,atc,pattr,minW(SizeOfSubstring1,maxstrlen));
  740.  
  741. {
  742.   turn locations from offsets to absolute values for speed
  743. }
  744.  
  745.   for I := 1 to maxstrlen do
  746.     inc(charpos[I],atc);
  747.  
  748.   for I := 1 to NumberOfMarkers do
  749.     inc(fmarray[I].location,atc);
  750.  
  751.   finished := false; { used in show_string must be initialized }
  752.   escaped  := false; { ditto }
  753.  
  754.   if EditingString then {prevents resetting cp when just painting fields}
  755.      begin
  756.        original_string := '';
  757.        show_string; {oldcp set to 0 here forces cursor position update}
  758.  
  759.        mandatory    := (status and $01) > 0;
  760.        fixed_length := (status and $02) > 0;
  761.        ValidateOff  := (not mandatory) and (not fixed_length) and PictureAllX;
  762.  
  763.        original_string := instr;  {backup, NB must follow show_string above}
  764.        OldOverwrite := overwrite; { " }
  765.        overwrite := overwrite or LocalInsLock;
  766.  
  767.        if (cp > length(instr)) or (cp > maxstrlen) then
  768.          {set cp to 1 if instr is blank, else set cp to length + 1 if possible}
  769.          cp := minW( maxW(succ(length(instr)),1), maxstrlen);
  770.        {else cp unchanged}
  771.        show_cursor;
  772.        firstcp := cp; {this should follow preceding if}
  773.  
  774.        repeat
  775.          get_input
  776.        until finished or escaped;
  777.  
  778.       if (not escaped) and top_n_tail then
  779.         instr := trim(instr);
  780.  
  781.       overwrite := OldOverwrite;
  782.     end;
  783.  
  784.   show_string; {needed even if string unchanged, to change attribute}
  785.  
  786.   clearerror2;
  787.   SetCursor(CursorOff);
  788. end;
  789.