home *** CD-ROM | disk | FTP | other *** search
- 1: (* ------------------------------------------------------ *)
- 2: (* MAKECKBD.PAS *)
- 3: (* (c) 1989 Olaf Stoyke & TOOLBOX *)
- 4: (* ------------------------------------------------------ *)
- 5: PROGRAM MakeCKBD;
- 6:
- 7: USES Dos;
- 8:
- 9: Const
- 10: CRLF = #13#10;
- 11: NUL = #0;
- 12: QUOTE1 = '''';
- 13: QUOTE2 = '"';
- 14: BACKSLASH = '\';
- 15: SEMICOLON = ';';
- 16: BUFSIZE = 2048; { Für bessere I/O-Performance }
- 17: CKBD1SIZE = 166; { Größe von CKBD1.BIN }
- 18: CKBD2SIZE = 378; { Größe von CKBD2.BIN }
- 19: INITOFSOFS = 10; { Offset von 'initofs' in CKBD1 }
- 20: { MAXOFS gibt die maximale Größe des Textspeichers an }
- 21: MAXOFS = 65535 - CKBD2SIZE;
- 22: { Für Dez/Hex-Umwandlungen: }
- 23: Digits : Array[0..15] Of Char = '0123456789ABCDEF';
- 24:
- 25: Type
- 26: KeyList = ^KeyString;
- 27: KeyString = RECORD
- 28: { Scancode und Offset werden in die
- 29: Scancodetabelle geschrieben }
- 30: ScanCode,
- 31: Offset : WORD;
- 32: { Wird gesetzt, wenn ein Scancode
- 33: zum zweiten Mal gelesen wird }
- 34: DefTwice : BOOLEAN;
- 35: { Der Text für die Taste: }
- 36: KeyText : STRING[81];
- 37: Next : KeyList;
- 38: END;
- 39:
- 40: VAR
- 41: Root : KeyList; { Liste aller Definitionen }
- 42: KeyDefs : WORD; { Anzahl gültiger Definitionen }
- 43: SourceName, { Dateinamen ... }
- 44: CKBDName : DirStr; { 'DirStr' kommt aus 'Dos' }
- 45: IOBuffer : ARRAY[0..BUFSIZE - 1] OF BYTE;
- 46:
- 47: PROCEDURE CKBD1; { Binärcode von CKBD1 }
- 48: {$L CKBD1.OBJ }
- 49: EXTERNAL;
- 50:
- 51: PROCEDURE CKBD2; { Binärcode von CKBD2 }
- 52: {$L CKBD2.OBJ }
- 53: EXTERNAL;
- 54:
- 55: PROCEDURE GetNames;
- 56: { Es werden die Dateinamen erfragt, wobei gleichzeitig
- 57: getestet wird, ob die Quelldatei existiert und ob der
- 58: Anwender damit einverstanden ist, daß wenn die Datei
- 59: schon existiert, CKBD.COM überschrieben wird. }
- 60: VAR
- 61: Flag : BOOLEAN;
- 62: F : SearchRec;
- 63:
- 64: FUNCTION Yes : BOOLEAN;
- 65: { Ja/Nein-Abfrage, Version in Neudeutsch. }
- 66: VAR
- 67: R : Registers;
- 68: BEGIN
- 69: WITH R DO BEGIN
- 70: ah := 0;
- 71: Intr($16, R);
- 72: Yes := (al = 89) Or (al = 121);
- 73: END; { With }
- 74: END; { Yes }
- 75:
- 76: BEGIN
- 77: REPEAT
- 78: WriteLn('Enter source filename:');
- 79: ReadLn(SourceName);
- 80: FindFirst(SourceName, Archive, F);
- 81: UNTIL DosError = 0;
- 82: REPEAT
- 83: WriteLn('Enter CKBD.COM path: ');
- 84: ReadLn(CKBDName);
- 85: If CKBDName[Length(CKBDName)] <> '\' THEN
- 86: CKBDName := CKBDName + '\';
- 87: CKBDName := CKBDName + 'CKBD.COM';
- 88: FindFirst(CKBDName, Archive, F);
- 89: If DosError = 0 THEN BEGIN
- 90: WriteLn('Overwrite ', CKBDName, ' ? (Y/N)');
- 91: Flag := Yes;
- 92: END { If } ELSE
- 93: Flag := True;
- 94: UNTIL Flag;
- 95: WriteLn;
- 96: END; { GetNames }
- 97:
- 98: FUNCTION HexStr(W : WORD) : STRING;
- 99: VAR
- 100: I : WORD;
- 101: HS : STRING[4];
- 102: BEGIN
- 103: I := 1;
- 104: HS[0] := #4;
- 105: WHILE I < 5 DO BEGIN
- 106: HS[5 - I] := Digits[W MOD 16];
- 107: W := W SHR 4;
- 108: Inc(I);
- 109: END; { While }
- 110: HexStr := HS;
- 111: END; { HexStr }
- 112:
- 113: PROCEDURE ReadSource;
- 114: { Hyper-Prozedur mit Lesen der Quelldatei und Compi-
- 115: lieren derselben. Weil Strings unter Turbo Pascal
- 116: auf maximal 255 Zeichen Länge begrenzt sind, wird
- 117: mittels 'WHILE NOT EoLn(Source) DO ...' die gesamte
- 118: Zeile ein- bzw. überlesen ohne irgendwelche internen
- 119: Grenzen zu überschreiten ... }
- 120: CONST
- 121: STRSIZE = 255; { Maximale Stringlänge }
- 122: VAR
- 123: Source : TEXT; { Quelldatei }
- 124: Buffer : STRING; { Übertragungspuffer }
- 125: LC, { Zeilenzähler }
- 126: Index : WORD; { Index für den 'Buffer' }
- 127: C : CHAR; { Für Datei-I/O }
- 128:
- 129: PROCEDURE Compile(VAR Line : STRING);
- 130: { Die übergebene Zeile wird compiliert, das heißt
- 131: es wird versucht, sie zu "verstehen". }
- 132: VAR
- 133: Buffer : STRING; { Der String kommt hier hin }
- 134: I, J, { Quell- / Pufferindex }
- 135: V, SC : WORD; { V: Dummy, SC: Scancode }
- 136: S, Ch : CHAR;
- 137:
- 138: PROCEDURE ListInsert(SCode : WORD; TData : STRING);
- 139: { Einfügen einer neuen Tastendefinition, bestehend
- 140: aus Scancode 'SCode' und Text 'TData', in die
- 141: Liste. Wenn 'SCode' schon in der Liste anzutref-
- 142: fen ist, wird der alte Eintrag als Doppeldefini-
- 143: tion vermerkt und die neue Definition ignoriert. }
- 144: VAR
- 145: HelpPtr : KeyList;
- 146: BEGIN
- 147: HelpPtr := Root;
- 148: WHILE (HelpPtr <> Nil) AND
- 149: (HelpPtr^.Scancode <> SCode) DO
- 150: HelpPtr := HelpPtr^.Next;
- 151: IF HelpPtr = Nil THEN BEGIN
- 152: New(HelpPtr);
- 153: WITH HelpPtr^ DO BEGIN
- 154: Next := Root;
- 155: Scancode := SCode;
- 156: KeyText := TData;
- 157: DefTwice := FALSE;
- 158: { Mit der nächsten Zuweisung wird das Offset
- 159: auf einen Wert gesetzt der sich aus der
- 160: Länge des PSP und der Größe von CKBD1.BIN
- 161: ergibt und sich auf die ausführbare Datei
- 162: CKBD.COM bezieht: }
- 163: Offset := 256 + CKBD1SIZE;
- 164: END; { With }
- 165: Root := HelpPtr;
- 166: Inc(KeyDefs);
- 167: END { If } ELSE
- 168: HelpPtr^.DefTwice := TRUE;
- 169: END; { ListInsert }
- 170:
- 171: FUNCTION CharsLeft : BOOLEAN;
- 172: { Sucht von der aktuellen Position innerhalb
- 173: der Zeile an ein Zeichen, daß kein Blank oder
- 174: Steuerzeichen ist und gibt 'True' aus, wenn
- 175: ein solches Zeichen existiert. }
- 176: BEGIN
- 177: WHILE (I <= Length(Line)) AND (Line[I] < '!') DO
- 178: Inc(I);
- 179: CharsLeft := I <= Length(Line);
- 180: END; { CharsLeft }
- 181:
- 182: PROCEDURE Message(LC, PC : WORD; Msg : STRING);
- 183: BEGIN
- 184: WriteLn('Error at line ',
- 185: LC, ', pos ', PC, ': ', Msg);
- 186: END; { Message }
- 187:
- 188: BEGIN
- 189: I := 1;
- 190: IF NOT CharsLeft THEN Exit;
- 191: IF Line[I] <> SEMICOLON THEN BEGIN
- 192: SC := 0;
- 193: FOR J := 0 TO 3 DO BEGIN
- 194: V := Pos(UpCase(Line[I + J]), Digits);
- 195: IF V = 0 THEN BEGIN
- 196: Message(LC, I + J, 'Error in base 16 const.');
- 197: Exit;
- 198: END; { If }
- 199: SC := V - 1 + SC SHL 4;
- 200: END; { For }
- 201: I := I + J + 1;
- 202: IF NOT CharsLeft THEN
- 203: Message(LC, I, 'Unexpected end of line.')
- 204: ELSE BEGIN
- 205: S := Line[I];
- 206: IF (S = QUOTE1) OR (S = QUOTE2) THEN BEGIN
- 207: J := 1; { Für 1. Zeichen im Puffer }
- 208: Inc(I);
- 209: WHILE (I <= Length(Line)) AND
- 210: (Line[I] <> S) DO BEGIN
- 211: Ch := Line[I];
- 212: { Falls \, Rest analysieren. Zahlen-
- 213: konstante als ASCII-Wert interpretie-
- 214: ren, sonst normales Zeichen ... }
- 215: IF Ch = BACKSLASH THEN BEGIN
- 216: Inc(I);
- 217: IF ('/' < Line[I]) AND
- 218: (Line[I] < ':') THEN BEGIN
- 219: V := 0; { Puffer für ASCII-Code }
- 220: REPEAT
- 221: V := V * 10 + Ord(Line[I]) - 48;
- 222: Inc(I);
- 223: UNTIL (Line[I] < '0') Or ('9' < Line[I]);
- 224: { Da unten steht ein Inc(I), also kommt
- 225: hier ein Dec(I) hin ... }
- 226: Dec(I);
- 227: If V > 255 THEN BEGIN
- 228: Message(LC, I, 'Invalid ascii const.');
- 229: Exit;
- 230: END { If } ELSE
- 231: Ch := Chr(V);
- 232: END { If } ELSE
- 233: Ch := Line[I];
- 234: END; { If }
- 235: IF Ch = NUL THEN BEGIN
- 236: Message(LC, I, 'Invalid NUL in string.');
- 237: Exit;
- 238: END ELSE
- 239: Buffer[J] := Ch;
- 240: Inc(I); { Nächstes Zeichen Quellzeile }
- 241: Inc(J); { Nächstes Zeichen Zielpuffer }
- 242: END; { While }
- 243: { J ist Anzahl gelesener Zeichen plus 1 }
- 244: Buffer[J] := NUL;
- 245: Buffer[0] := Chr(J);
- 246: IF I > Length(Line) THEN BEGIN
- 247: Message(LC, I, 'Unexpected end of line.');
- 248: Exit;
- 249: END; { If }
- 250: IF J = 1 THEN BEGIN
- 251: Message(LC, J, 'Invalid string.');
- 252: Exit;
- 253: END; { If }
- 254: Inc(I);
- 255: IF CharsLeft THEN
- 256: Message(LC, I, 'Extra chars on line.')
- 257: ELSE
- 258: ListInsert(SC, Buffer);
- 259: END { If } ELSE
- 260: Message(LC, I, '" or '' expected.');
- 261: END; { Else }
- 262: END; { If }
- 263: END; { Compile }
- 264:
- 265: PROCEDURE TestDefTwice;
- 266: { Durchsucht die Liste der Tastendfinitionen und
- 267: meldet sich, wenn eine Definition mit dem ge-
- 268: setzten Flag für eine Doppeldefinition gefunden
- 269: wurde. }
- 270: VAR
- 271: Walker : KeyList;
- 272: BEGIN
- 273: Walker := Root;
- 274: IF Walker = Nil THEN
- 275: WriteLn('No lines compiled.')
- 276: ELSE
- 277: REPEAT
- 278: WITH Walker^ DO BEGIN
- 279: IF DefTwice THEN
- 280: WriteLn(HexStr(Scancode), ' read twice.');
- 281: Walker := Next;
- 282: END; { With }
- 283: UNTIL Walker = Nil;
- 284: END; { TestDefTwice }
- 285:
- 286: BEGIN
- 287: {$I-}
- 288: Assign(Source, SourceName);
- 289: Reset(Source);
- 290: {$I+}
- 291: IF IOResult <> 0 THEN BEGIN
- 292: WriteLn(CRLF, 'Cannot open ', SourceName, '.');
- 293: Halt(1);
- 294: END { If } ELSE
- 295: SetTextBuf(Source, IOBuffer, BUFSIZE);
- 296: LC := 1;
- 297: WriteLn('Reading . . .');
- 298: WHILE NOT EoF(Source) DO BEGIN
- 299: Index := 1;
- 300: WHILE NOT EoLn(Source) DO BEGIN { Bis zum Zeilen- }
- 301: Read(Source, C); { ende Zeichen }
- 302: IF Index <= STRSIZE THEN { einlesen ... }
- 303: Buffer[Index] := C;
- 304: Inc(Index);
- 305: END; { While }
- 306: { 'Read(Source, C, C)' überliest das EoLn-Merkmal,
- 307: in der Regel ein CR und ein LF. (oder LF/CR ?) }
- 308: Read(Source, C, C);
- 309: IF Index > 1 THEN BEGIN
- 310: Buffer[0] := Chr(Index - 1); { Länge setzen }
- 311: Compile(Buffer);
- 312: END; { If }
- 313: Inc(LC);
- 314: END; { While }
- 315: Close(Source);
- 316: TestDefTwice;
- 317: END; { ReadSource }
- 318:
- 319: PROCEDURE MakeCode;
- 320: { 'MakeCode' generiert das ready-to-run CKBD.COM
- 321: mittels der Tastendefinitionen in der Liste. }
- 322: CONST
- 323: { 'TabEnd' wird ans Ende der Scancodetabelle ange-
- 324: hängt, um CKBD mitzuteilen, wo die Tabelle endet. }
- 325: TabEnd : LongInt = $FFFFFFFF;
- 326: VAR
- 327: Walker : KeyList;
- 328: CKBD : File; { Zieldatei }
- 329: TDLength : Word; { Offset der Textdaten }
- 330:
- 331: PROCEDURE GenOffsets;
- 332: BEGIN
- 333: WriteLn(KeyDefs, ' line(s) compiled.');
- 334: TDLength := 4 + KeyDefs * 4;
- 335: Walker := Root;
- 336: WHILE Walker <> Nil DO
- 337: WITH Walker^ DO BEGIN
- 338: { siehe auch 'ListInsert' ... }
- 339: Inc(Offset, TDLength);
- 340: Inc(TDLength, Length(KeyText));
- 341: IF TDLength > MAXOFS THEN BEGIN
- 342: { Kein Platz mehr für CKBD2 }
- 343: WriteLn('Not enough memory for text data.');
- 344: Halt(1);
- 345: END; { If }
- 346: Walker := Next;
- 347: END; { With }
- 348: WriteLn(HexStr(TDLength), ' bytes text data.');
- 349: WriteLn;
- 350: END; { GenOffsets }
- 351:
- 352: PROCEDURE GenCode(VAR C; CodeL : WORD);
- 353: { Generelle Ausgabeprozedur mit zentraler Fehler-
- 354: behandlung. }
- 355: VAR
- 356: Result : WORD;
- 357: BEGIN
- 358: BlockWrite(CKBD, C, CodeL, Result);
- 359: IF Result < CodeL THEN BEGIN
- 360: WriteLn(CRLF, CKBDName, ': Write error.');
- 361: Halt(1);
- 362: END; { If }
- 363: END; { GenCode }
- 364:
- 365: BEGIN
- 366: {$I-}
- 367: Assign(CKBD, CKBDName);
- 368: Rewrite(CKBD, 1);
- 369: {$I+}
- 370: IF IOResult > 0 THEN BEGIN
- 371: WriteLn(CRLF, 'Cannot open ', CKBDName, '.');
- 372: Halt(1);
- 373: END; { If }
- 374: GenOffsets;
- 375: WriteLn('Writing . . .');
- 376: { Die folgende, kryptische Zuweisung setzt die Varia-
- 377: ble 'initofs' in CKBD1.BIN auf das Startoffset der
- 378: Initialisierungsroutine in CKBD2.BIN. Dieser be-
- 379: rechnet sich aus Länge des PSP (256) plus Länge von
- 380: CKBD1.BIN plus Länge der Textdaten ... }
- 381: MemW[Seg(CKBD1):Ofs(CKBD1) + INITOFSOFS] :=
- 382: 256 + CKBD1SIZE + TDLength;
- 383: GenCode(Addr(CKBD1)^, CKBD1SIZE);
- 384: Walker := Root;
- 385: WHILE Walker <> Nil DO
- 386: WITH Walker^ DO BEGIN { Schreibe Scancodetabelle }
- 387: GenCode(ScanCode, 2); { 1) Den Scancode selbst }
- 388: GenCode(Offset, 2); { 2) Das Offset dazu }
- 389: Walker := Next;
- 390: END; { With }
- 391: GenCode(TabEnd, 4); { Anhängen des Ende-Merkmals }
- 392: Walker := Root;
- 393: WHILE Walker <> Nil DO
- 394: WITH Walker^ DO BEGIN { Ausgabe des Texts: }
- 395: GenCode(KeyText[1], Length(KeyText));
- 396: Walker := Next;
- 397: END; { With }
- 398: GenCode(Addr(CKBD2)^, CKBD2SIZE);
- 399: Close(CKBD);
- 400: WriteLn(HexStr(CKBD1SIZE + CKBD2SIZE + TDLength),
- 401: ' bytes written.');
- 402: WriteLn;
- 403: END; { MakeCode }
- 404:
- 405: BEGIN
- 406: WriteLn(CRLF, 'MAKECKBD Version 1.30', CRLF,
- 407: 'Copyright (c) 1989 by Olaf Stoyke & TOOLBOX',
- 408: CRLF);
- 409: KeyDefs := 0; { Noch keine gültigen Zeilen gelesen }
- 410: Root := Nil; { ... deshalb auch eine leere Liste }
- 411: GetNames; { Dateinamen einlesen und testen }
- 412: ReadSource; { Quelle lesen und compilieren }
- 413: IF Root <> Nil THEN { Wenn gültige Zeilen existieren }
- 414: MakeCode { Zieldatei ausgeben: CKBD.COM }
- 415: ELSE
- 416: WriteLn;
- 417: WriteLn('Done.'); { Stimmt ! }
- 418: END.
- 419: (* ------------------------------------------------------ *)
- 420: (* Ende von MAKECKBD.PAS *)
-