home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1990 / 12 / tricks / coninput.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-09-11  |  17.5 KB  |  539 lines

  1. (* ------------------------------------------------------ *)
  2. (*                     CONINPUT.PAS                       *)
  3. (*   Komfortable Eingabe für alle Turbo-Pascal-Basistypen *)
  4. (*                   über die Konsole                     *)
  5. (*       (c) 1988 by Karsten Gieselmann  &  TOOLBOX       *)
  6. (*                                                        *)
  7. (* Die UNIT implementiert einen  vollständigen Satz von   *)
  8. (* Routinen zur Eingabe von Variablen des Typs BYTE,      *)
  9. (* SHORTINT, CHAR, INTEGER, WORD, LONGINT, REAL und       *)
  10. (* STRING über die Konsole.  Zum Einlesen der Zeichen-    *)
  11. (* ketten dient ein komfortabler Zeileneditor, der bei    *)
  12. (* frei wählbarer Breite des Eingabefensters auch hori-   *)
  13. (* zontales Scrolling erlaubt;  Fenstertechnik            *)
  14. (* (Window-Befehl aus CRT) wird unterstützt. Leereingaben *)
  15. (* und Abbruch einer Eingabe mittels <Esc> lassen den     *)
  16. (* Inhalt einer einzulesenden Variablen (außer bei        *)
  17. (* STRINGs) unverändert. Editierbefehle:                  *)
  18. (*                                                        *)
  19. (*  <Pfeil links> . Cursor ein Zeichen nach links         *)
  20. (*  <Pfeil rechts>  Cursor ein Zeichen nach rechts        *)
  21. (*  <Ctrl><links> . Cursor ein Wort nach links            *)
  22. (*  <Ctrl><rechts>  Cursor ein Wort nach rechts           *)
  23. (*  <Home> ........ Cursor an den Anfang der Eingabezeile *)
  24. (*  <End> ......... Cursor an das Ende der Eingabezeile   *)
  25. (*  <Del> ......... Zeichen unter Cursor löschen          *)
  26. (*  <Backspace> ... Zeichen links vom Cursor löschen      *)
  27. (*  <Ctrl><Home> .. löschen von Zeilenanfang bis Cursor   *)
  28. (*  <Ctrl><End> ... löschen vom Cursor bis Zeilenende     *)
  29. (*  <PgDn> ........ letzte Eingabe wiederholen            *)
  30. (*  <Ins> ......... Einfügemodus an/aus                   *)
  31. (*  <Esc> ......... Eingabe abbrechen (nicht übernehmen)  *)
  32. (*  <Ctrl><Break> . laufendes Programm abbrechen          *)
  33. (*  <Return> ...... Eingabe beenden (übernehmen)          *)
  34. (*                                                        *)
  35. (*  Änderung 12'90  (H.Kaese / wr) :                      *)
  36. (*  Die Eingabe läßt sich nun auch durch mit Cursor Up/Dn *)
  37. (*  wie bei <Return> Beenden.                             *)
  38. (*  Die Tasten werden durch 'Zeilensprung := TRUE'        *)
  39. (*  aktiviert und 'CursorZeile' liefert 'up' oder 'dn'    *)
  40. (*  zur Identifikation der Cursortasten-Aktivität.        *)
  41. (*                                                        *)
  42. (* ------------------------------------------------------ *)
  43. UNIT ConInput;
  44.  
  45. INTERFACE
  46.  
  47. USES Crt, Dos;
  48.  
  49. (* ----------------  Kontrollvariablen  ----------------- *)
  50.  
  51. VAR EditOld : BOOLEAN; (* bestimmt, ob der alte           *)
  52.                        (* Variablenwert bei der Eingabe   *)
  53.                        (* vorgegeben wird                 *)
  54. VAR InsMode : BOOLEAN; (* bestimmt, ob bei Eingabebeginn  *)
  55.                        (* Insert- oder Overwrite-Modus    *)
  56.                        (* aktiv ist                       *)
  57. VAR BufLen  : BYTE;    (* bestimmt die Maximallänge       *)
  58.                        (* einer Eingabe                   *)
  59. VAR EditSize: BYTE;    (* bestimmt die Breite des         *)
  60.                        (* Editierfeldes                   *)
  61. VAR Aborted : BOOLEAN; (* gibt an, ob die letzte Eingabe  *)
  62.                        (* mit <Esc> oder <Break>          *)
  63.                        (* abgebrochen wurde               *)
  64. VAR Width   : BYTE;    (* bestimmt die Breite, mit der    *)
  65.                        (* eine  REAL-Variable im  Gleit-  *)
  66.                        (* kommaformat vorgegeben wird;    *)
  67.                        (* beim Festkommadarstellung hat   *)
  68.                        (* diese Größe keinen Einfluß auf  *)
  69.                        (* das Anzeigeformat eines         *)
  70.                        (* REAL-Wertes!                    *)
  71.  
  72. VAR Decimals: SHORTINT;
  73.                        (* legt die Anzahl der Nachkomma-  *)
  74.                        (* stellen bei der Eingabevorgabe  *)
  75.                        (* für REAL-Variablen fest; Angabe *)
  76.                        (* eines Wertes < 0 bewirkt        *)
  77.                        (* Gleitkommadarstellung!          *)
  78.  
  79. VAR Zeilensprung: BOOLEAN;
  80.                        (* Cursor Up/Dn  Ein/Aus           *)
  81.  
  82. VAR CursorZeile : STRING [2];
  83.                        (* Cursor Up oder Down             *)
  84.  
  85. (* ---------  Eingaberoutinen für die Basistypen  ------- *)
  86.  
  87. PROCEDURE ReadByte (VAR B : BYTE);
  88.                          (* Einlesen einer BYTE-Variablen *)
  89.  
  90. PROCEDURE ReadShortInt (VAR S : SHORTINT);
  91.                  (* Einlesen einer ShortInteger-Variablen *)
  92.  
  93. PROCEDURE ReadChar (VAR C :CHAR);
  94.                     (* Einlesen einer Character-Variablen *)
  95.  
  96. PROCEDURE ReadInt (VAR I :INTEGER);
  97.                       (* Einlesen einer INTEGER-Variablen *)
  98.  
  99. PROCEDURE ReadLongInt (VAR L :LONGINT);
  100.                   (* Einlesen einer LongInteger-Variablen *)
  101.  
  102. PROCEDURE ReadWord (VAR W :WORD);
  103.                          (* Einlesen einer WORD-Variablen *)
  104.  
  105. PROCEDURE ReadReal (VAR R :REAL);
  106.                    (* Einlesen einer Gleitkomma-Variablen *)
  107.  
  108. PROCEDURE ReadString (VAR S : STRING);
  109.                        (* Einlesen einer STRING-Variablen *)
  110.  
  111.  
  112.  
  113. IMPLEMENTATION
  114.  
  115.  
  116. (* ------- Akustische Fehlermeldung durch Piepton ------- *)
  117.  
  118. PROCEDURE Beep (Frequency, Hold : WORD);
  119. BEGIN
  120.   Sound (Frequency); Delay (Hold); NoSound
  121. END;
  122.  
  123. (* ---------------  der Zeileneditor -------------------- *)
  124.  
  125. PROCEDURE EditString (VAR EditStr : STRING; MaxLen : BYTE);
  126.  
  127. TYPE
  128.   ShapeType = ARRAY [FALSE..TRUE] OF WORD;
  129.  
  130. CONST
  131.   Monochrome = 7;
  132.   MonoShape  : ShapeType = ($0C0D, $060D);
  133.   ColorShape : ShapeType = ($0607, $0407);
  134.   Letters    : SET OF CHAR = ['A'..'Z','a'..'z','0'..'9',
  135.                               'ß','Ä','Ö','Ü','ä','ö','ü'];
  136.  
  137. VAR
  138.   xpos,ypos,Deleted         : INTEGER;
  139.   p,f,w,SaveShape,Command   : WORD;
  140.   c                         : CHAR absolute Command;
  141.   CursorShape               : WORD absolute $0040:$0060;
  142.   VideoMode                 : BYTE absolute $0040:$0049;
  143.   First,Quit,Display,Insert : BOOLEAN;
  144.   s                         : STRING;
  145.   Len                       : BYTE absolute s;
  146.   Shape                     : ShapeType;
  147.  
  148. PROCEDURE SetCursorShape (Shape :WORD);
  149.                                      (* Setzt Cursorgröße *)
  150.   INLINE ($59/$B4/$01/$CD/$10);
  151.  
  152. FUNCTION GetKey :WORD;
  153.                    (* wartet auf Taste und holt Scan-Code *)
  154.   INLINE ($31/$C0/$CD/$16);
  155.  
  156. FUNCTION MinI (a,b :INTEGER) :INTEGER;
  157.                            (* liefert Minimum von a und b *)
  158.   INLINE ($58/$5B/$39/$D8/$7E/$02/$89/$D8);
  159.  
  160. PROCEDURE Cursor (Switch : BOOLEAN);
  161.                                 (* schaltet Cursor an/aus *)
  162. BEGIN
  163.   CASE Switch OF
  164.     TRUE:  SetCursorShape (CursorShape AND $EFFF);
  165.     FALSE: SetCursorShape (CursorShape  OR $1000);
  166.   END;
  167. END;
  168.  
  169. FUNCTION StringOf (Ch : CHAR; Num : INTEGER) : STRING;
  170.                                        (* String aus "Ch" *)
  171. VAR s : STRING;
  172. BEGIN
  173.   IF Num < 0 THEN Num:=0;
  174.   s[0] := Chr (Num);
  175.   FillChar (s[1], Num, Ch);
  176.   StringOf := s;
  177. END;
  178.  
  179. PROCEDURE PosCursor (p : WORD);
  180.                    (* setzt Cursor auf Stringposition "p" *)
  181. BEGIN
  182.   GotoXY(Succ(Pred(xpos+p-f) MOD w), ypos
  183.                                   + (Pred(xpos+p-f) DIV w));
  184. END;
  185.  
  186. PROCEDURE Advance (StepForward : BOOLEAN);
  187.                      (* bewegt den Cursor im STRING um    *)
  188.                      (* eine Position nach links / rechts *)
  189.                      (* und berechnet gegebenfalls die    *)
  190.                      (* neue Lage des Strings im          *)
  191.                      (* Editierfenster                    *)
  192. BEGIN
  193.   IF StepForward THEN BEGIN
  194.     IF (p > f+EditSize-2) THEN Inc(f) ELSE Display:=FALSE;
  195.     Inc(p);
  196.   END ELSE BEGIN
  197.     IF p = f THEN Dec(f) ELSE Display:=FALSE;
  198.     Dec (p);
  199.   END;
  200. END;
  201.  
  202. BEGIN                                       (* EditString *)
  203.   xpos       := WhereX;           (* Home-Position merken *)
  204.   ypos       := WhereY;
  205.   w          := Lo(WindMax) - Lo(WindMin) + 1;
  206.                                  (* nutzbare Schirmbreite *)
  207.   s          := EditStr;
  208.   p          := 1;           (* Cursor-Position im STRING *)
  209.   f          := 1;           (* STRING-Index des ersten   *)
  210.                              (* angezeigten Zeichens      *)
  211.   Deleted    := 0;
  212.   First      := TRUE;
  213.   Quit       := FALSE;       (* Flagbyte für Eingabe      *)
  214.                              (* abgeschlossen             *)
  215.   Aborted    := FALSE;
  216.   Insert     := InsMode;     (* Flagbyte für Einfügemodus *)
  217.                              (* an/aus                    *)
  218.   Display    := TRUE;
  219.   SaveShape  := CursorShape;
  220.   If VideoMode = Monochrome THEN
  221.     Shape := MonoShape
  222.   ELSE
  223.     Shape := ColorShape;
  224.   SetCursorShape (Shape[Insert]);
  225.   REPEAT
  226.     IF p > Len THEN IF Deleted=0 THEN Deleted:=1;
  227.     IF Display THEN BEGIN
  228.       Cursor (FALSE);
  229.       GotoXY (xpos,ypos);
  230.       Write (Copy(s,f,EditSize) + StringOf(' ',Deleted));
  231.       Cursor (TRUE);
  232.     END;
  233.     CursorZeile := '';
  234.     Display := TRUE;
  235.     Deleted := 0;
  236.     PosCursor (p);
  237.     Command := GetKey;
  238.     CASE Command OF
  239.  
  240.       $4B00:                                   (* <Left>  *)
  241.         IF p>1 THEN Advance (FALSE);
  242.  
  243.       $4D00:                                   (* <Right> *)
  244.         IF p<=Len THEN Advance (TRUE);
  245.  
  246.       $7300:                              (* <Ctrl><Left> *)
  247.         BEGIN
  248.           WHILE (p>1) AND NOT (s[p-1] IN Letters) DO
  249.             Advance (FALSE);
  250.           WHILE (p>1) AND     (s[p-1] IN Letters) DO
  251.             Advance (FALSE);
  252.           Display := TRUE;
  253.         END;
  254.  
  255.       $7400:                             (* <Ctrl><Right> *)
  256.         BEGIN
  257.           WHILE (p <= Len) AND     (s[p] IN Letters) DO
  258.             Advance (TRUE);
  259.           WHILE (p <= Len) AND NOT (s[p] IN Letters) DO
  260.             Advance (TRUE);
  261.           Display := TRUE;
  262.         END;
  263.  
  264.       $4700:                                    (* <Home> *)
  265.         BEGIN
  266.           p:=1; f:=1;
  267.         END;
  268.  
  269.       $4F00:                                     (* <End> *)
  270.         BEGIN
  271.           p := Len+1;
  272.           IF p > EditSize THEN
  273.              f := Succ (p-EditSize)
  274.           ELSE
  275.              f := 1;
  276.         END;
  277.  
  278.       $5300:                                     (* <Del> *)
  279.         IF p <= Len THEN BEGIN
  280.           IF Len > EditSize THEN
  281.             IF (f <> 1) AND (p-f <> EditSize) THEN
  282.               Dec (f)
  283.             ELSE
  284.           ELSE
  285.             Deleted := 1;
  286.           Delete (s, p, 1);
  287.         END;
  288.  
  289.       $0E08:                                   (* <BkSpc> *)
  290.         IF p > 1 THEN BEGIN
  291.           IF Len >= EditSize THEN
  292.             IF f <> 1 THEN
  293.               Dec (f)
  294.             ELSE IF Len = EditSize THEN
  295.               Deleted := 1
  296.             ELSE
  297.           ELSE
  298.             Deleted := 1;
  299.           Dec (p);
  300.           Delete (s, p, 1);
  301.         END;
  302.  
  303.       $7700:                              (* <Ctrl><Home> *)
  304.         BEGIN
  305.           Deleted := Pred(MinI(EditSize,Len))
  306.                      - INTEGER(Len-p);
  307.           IF p = Len+1 THEN
  308.             s := ''
  309.           ELSE
  310.             s := Copy (s, p, Len-p+1);
  311.           p:=1; f:=1;
  312.         END;
  313.  
  314.       $7500:                               (* <Ctrl><End> *)
  315.         BEGIN
  316.           IF p > EditSize THEN
  317.             f := Succ (p-EditSize)
  318.           ELSE
  319.             BEGIN
  320.               Deleted := MinI(EditSize,Len) - Pred(p);
  321.               f := 1;
  322.             END;
  323.           Len := p-1;
  324.         END;
  325.  
  326.       $5200:                                     (* <Ins> *)
  327.         BEGIN
  328.           Display := FALSE;
  329.           Insert := NOT Insert;
  330.           SetCursorShape (Shape[Insert]);
  331.         END;
  332.  
  333.       $5100, $011B, $0000:
  334.                           (* <PgDn>, <Esc>, <Ctrl><Break> *)
  335.         BEGIN
  336.           Deleted := Len;
  337.           s := EditStr;
  338.           Deleted := MinI (EditSize-Len, Deleted-Len);
  339.           p:=1; f:=1;
  340.           First := TRUE;
  341.           Aborted := (Command=$0000) OR (Command=$011B);
  342.         END;
  343.  
  344.       $4800:
  345.                              (* Cursor up, Unit verlassen *)
  346.         BEGIN
  347.           IF Zeilensprung THEN BEGIN
  348.             CursorZeile := 'up';
  349.             Quit        := TRUE;
  350.           END;
  351.         END;
  352.  
  353.       $5000:
  354.                              (* Cursor dn, Unit verlassen *)
  355.         BEGIN
  356.           IF Zeilensprung THEN BEGIN
  357.             CursorZeile := 'dn';
  358.             Quit        := TRUE;
  359.           END;
  360.         END;
  361.  
  362.       $1C0D:                 (* <Return>, Eingabe beenden *)
  363.         Quit := TRUE;
  364.  
  365.       ELSE
  366.         IF Ord(c) >= 32 THEN    (* Eingabe eines Zeichens *)
  367.           IF First THEN BEGIN
  368.             Deleted := Pred (MinI (EditSize,Len));
  369.             s := c;
  370.             p := 2
  371.           END ELSE BEGIN
  372.             IF p = Len+1 THEN          (* hinten anfügen? *)
  373.               IF Len < MaxLen THEN BEGIN
  374.                 s := s + c;
  375.                 Advance (TRUE);
  376.               END ELSE           (* Maximallänge erreicht *)
  377.                 Beep (3200,50)
  378.               ELSE
  379.                 IF NOT Insert THEN BEGIN
  380.                   s[p] := c;
  381.                           (* Cursor-Zeichen überschreiben *)
  382.                   Advance (TRUE);
  383.                 END ELSE
  384.                   IF Len < MaxLen THEN BEGIN
  385.                                               (* einfügen *)
  386.                     s := Copy (s,1,p-1) + c
  387.                          + Copy (s,p,Len);
  388.                     Advance (TRUE);
  389.                   END ELSE       (* Maximallänge erreicht *)
  390.                     Beep (3200,50);
  391.                   Display := TRUE;
  392.                   END
  393.           END;
  394.     IF Command <> $5100 THEN First:=FALSE
  395.   UNTIL Quit OR Aborted;
  396.   EditStr := s;
  397.   f := 1;
  398.   GotoXY (xpos,ypos);
  399.   Write (Copy(s,f,EditSize) + StringOf(' ',Deleted));
  400.   PosCursor (MinI (EditSize,Len+1));
  401.   SetCursorShape (SaveShape);
  402. END;
  403.  
  404.  
  405. (* --------  Eingaberoutinen für die Basistypen  -------- *)
  406.  
  407. TYPE
  408.   Type_ = (BYTE_, SHORTINT_, INTEGER_, WORD_,
  409.            LONGINT_, REAL_);
  410.  
  411. PROCEDURE Read (p :POINTER; t :Type_);
  412.                           (* liest die bei "p^" stehenden *)
  413.                           (* Variablen vom Typ "t" ein    *)
  414. VAR
  415.   St,Old   : STRING;
  416.   ErrorPos : INTEGER;
  417.   x,y      : BYTE;
  418.   New      : RECORD CASE Type_ OF
  419.                0: (B : BYTE);
  420.                1: (S : SHORTINT);
  421.                2: (I : INTEGER);
  422.                3: (W : WORD);
  423.                4: (L : LONGINT);
  424.                5: (R : REAL);
  425.              END;
  426.  
  427. BEGIN
  428.   x := WhereX;
  429.   y := WhereY;
  430.   WITH New DO BEGIN
  431.     CASE t OF
  432.       BYTE_     : BEGIN  B := BYTE(p^);      Str(B,Old) END;
  433.       SHORTINT_ : BEGIN  S := SHORTINT(p^);  Str(S,Old) END;
  434.       INTEGER_  : BEGIN  I := INTEGER(p^);   Str(I,Old) END;
  435.       WORD_     : BEGIN  W := WORD(p^);      Str(W,Old) END;
  436.       LONGINT_  : BEGIN  L := LONGINT(p^);   Str(L,Old) END;
  437.       ELSE BEGIN
  438.         R := REAL (p^);
  439.         IF Decimals > 0 THEN          (* Fixkomma-Format? *)
  440.           Str (R:0:Decimals, Old)
  441.         ELSE BEGIN                   (* Gleitkomma-Format *)
  442.           Str (R,Old);
  443.           IF Length(Old) < Width THEN
  444.             Width := Length (Old);
  445.           Str (R:Width+1, Old);
  446.         END;
  447.         WHILE Old[1]=' ' DO Delete (Old,1,1);
  448.                                 (* Leerzeichen abstreifen *)
  449.       END
  450.     END;
  451.     IF EditOld THEN St:=Old ELSE St:='';
  452.     REPEAT
  453.       GotoXY (x,y);
  454.       EditString (St, BufLen);
  455.       IF St='' THEN St:=Old;
  456.       IF t = REAL_ THEN
  457.         Val (St, R, ErrorPos)
  458.       ELSE BEGIN
  459.         Val (St, L, ErrorPos);
  460.         IF ErrorPos = 0 THEN
  461.           CASE t OF
  462.             BYTE_    : IF (L <     0) OR (L >   255) THEN
  463.                          ErrorPos:=1;
  464.             SHORTINT_: IF (L <  -128) OR (L >   127) THEN
  465.                          ErrorPos:=1;
  466.             INTEGER_ : IF (L <-32768) OR (L > 32767) THEN
  467.                          ErrorPos:=1;
  468.             WORD_    : IF (L <     0) OR (L > 65535) THEN
  469.                          ErrorPos:=1;
  470.           END;
  471.       END;
  472.       IF ErrorPos > 0 THEN Beep(500,100);
  473.     UNTIL ErrorPos = 0;
  474.     CASE t OF
  475.       BYTE_    : BYTE(p^)     := B;
  476.       SHORTINT_: SHORTINT(p^) := S;
  477.       INTEGER_ : INTEGER(p^)  := I;
  478.       WORD_    : WORD(p^)     := W;
  479.       LONGINT_ : LONGINT(p^)  := L;
  480.       REAL_    : REAL(p^)     := R
  481.       END
  482.     END;
  483. END;
  484.  
  485. PROCEDURE ReadByte (VAR B : BYTE);
  486. BEGIN
  487.   Read (@B, BYTE_)
  488. END;
  489.  
  490. PROCEDURE ReadShortInt (VAR S : SHORTINT);
  491. BEGIN
  492.   Read (@S, SHORTINT_)
  493. END;
  494.  
  495. PROCEDURE ReadChar (VAR C : CHAR);
  496. VAR
  497.   S : STRING;
  498. BEGIN
  499.   EditString (S, 1);
  500.   C := S[1];
  501. END;
  502.  
  503. PROCEDURE ReadInt (VAR I : INTEGER);
  504. BEGIN
  505.   Read (@I, INTEGER_)
  506. END;
  507.  
  508. PROCEDURE ReadLongInt (VAR L :LONGINT);
  509. BEGIN
  510.   Read (@L, LONGINT_)
  511. END;
  512.  
  513. PROCEDURE ReadWord (VAR W : WORD);
  514. BEGIN
  515.   Read (@W, WORD_)
  516. END;
  517.  
  518. PROCEDURE ReadReal (VAR R : REAL);
  519. BEGIN
  520.   Read (@R, REAL_)
  521. END;
  522.  
  523. PROCEDURE ReadString (VAR S : STRING);
  524. BEGIN
  525.   EditString (S, BufLen);
  526. END;
  527.  
  528. BEGIN
  529.   EditOld  := TRUE;          (* Vorgaben standardmäßig an *)
  530.   InsMode  := TRUE;      (* Einfügemodus standardmäßig an *)
  531.   Width    := 255;
  532.   Decimals :=  20;  (* Fließkomma-Format bei REAL-Eingabe *)
  533.   BufLen   := 255;  (* Voreinstellung: maximale Länge     *)
  534.   EditSize := 255;
  535.   Aborted  := FALSE;
  536.   Zeilensprung := FALSE;
  537. END.
  538. (* ------------------------------------------------------ *)
  539. (*                 Ende von CONINPUT.PAS                  *)