2 Copyright 2021 Anton Krotov
\r
4 This file is part of CEdit.
\r
6 CEdit is free software: you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation, either version 3 of the License, or
\r
9 (at your option) any later version.
\r
11 CEdit is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with CEdit. If not, see <http://www.gnu.org/licenses/>.
\r
23 File, SYSTEM, KOSAPI, E := Encodings,
\r
24 CB := Clipboard, Lines;
\r
29 CR = 0DX; LF = 0AX; TAB = 9X; SPACE = 20X;
\r
36 EOL_CRLF* = 0; EOL_LF* = 1; EOL_CR* = 2;
\r
41 tFileName* = ARRAY NAME_LEN OF CHAR;
\r
43 tEOL = ARRAY 3 OF WCHAR;
\r
45 tInput* = POINTER TO RECORD
\r
50 getChar: PROCEDURE (file: tInput): INTEGER
\r
53 tOutput* = POINTER TO RECORD
\r
55 buffer: ARRAY BUF_SIZE OF BYTE;
\r
58 putChar: PROCEDURE (file: tOutput; code: INTEGER): BOOLEAN
\r
64 eol*: ARRAY 3 OF tEOL;
\r
65 eolNames*: ARRAY 3, 16 OF WCHAR;
\r
66 strBuf: ARRAY 1000000 OF WCHAR;
\r
69 PROCEDURE getByte (file: tInput): BYTE;
\r
73 IF file.cnt > 0 THEN
\r
74 SYSTEM.GET8(file.buffer + file.pos, res);
\r
84 PROCEDURE peakByte (file: tInput): BYTE;
\r
88 IF file.cnt > 0 THEN
\r
89 SYSTEM.GET8(file.buffer + file.pos, res)
\r
97 PROCEDURE getCharUTF8 (file: tInput): INTEGER;
\r
102 b := getByte(file);
\r
105 ELSIF (0C0H <= b) & (b <= 0DFH) THEN
\r
108 ELSIF (0E0H <= b) & (b <= 0EFH) THEN
\r
111 ELSIF (0F0H <= b) & (b <= 0F7H) THEN
\r
114 ELSIF (0F8H <= b) & (b <= 0FBH) THEN
\r
117 ELSIF (0FCH <= b) & (b <= 0FDH) THEN
\r
120 ELSIF b = 0FEH THEN
\r
123 ELSIF b = 0FFH THEN
\r
125 ELSIF (080H <= b) & (b <= 0BFH) THEN
\r
137 b := peakByte(file);
\r
138 IF (080H <= b) & (b <= 0BFH) THEN
\r
139 code := code*64 + getByte(file) - 080H
\r
153 PROCEDURE getCharW1251 (file: tInput): INTEGER;
\r
154 RETURN E.cpW1251[getByte(file)]
\r
158 PROCEDURE getCharCP866 (file: tInput): INTEGER;
\r
159 RETURN E.cp866[getByte(file)]
\r
163 PROCEDURE getCharUTF16LE (file: tInput): INTEGER;
\r
164 RETURN getByte(file) + getByte(file) * 256
\r
165 END getCharUTF16LE;
\r
168 PROCEDURE getString* (file: tInput; line: Lines.tLine; tabs: BOOLEAN; VAR eol: BOOLEAN): INTEGER;
\r
171 i, L, k, n: INTEGER;
\r
176 i := ORD(file.cnt > 0) - 1;
\r
177 WHILE (file.cnt > 0) & ~eol DO
\r
178 c := WCHR(file.getChar(file) MOD 65536);
\r
179 IF c = Lines.TAB1 THEN
\r
185 ELSIF (c = LF) OR (c = 0X) THEN
\r
191 k := Lines.tab - i MOD Lines.tab;
\r
201 strBuf[i] := Lines.TAB1
\r
207 Lines.concat(line, strBuf);
\r
220 Lines.concat(line, strBuf);
\r
229 Lines.concat(line, strBuf);
\r
236 PROCEDURE detectEncoding (text: tInput): INTEGER;
\r
238 pos, cnt, res: INTEGER;
\r
239 continue, bom: BOOLEAN;
\r
241 cp866, w1251: INTEGER;
\r
246 WHILE (text.cnt > 0) & continue DO
\r
247 IF getByte(text) > 127 THEN
\r
256 bom := getCharUTF8(text) = ORD(BOM);
\r
260 WHILE (text.cnt > 0) & continue DO
\r
261 IF getCharUTF8(text) = E.UNDEF THEN
\r
276 WHILE text.cnt > 0 DO
\r
277 b := getByte(text);
\r
286 IF w1251 > cp866 THEN
\r
296 END detectEncoding;
\r
299 PROCEDURE detectEOL (text: tInput): INTEGER;
\r
301 pos, cnt, c, res: INTEGER;
\r
306 WHILE (text.cnt > 0) & (res = -1) DO
\r
307 c := text.getChar(text);
\r
311 IF text.getChar(text) = 10 THEN
\r
327 PROCEDURE load* (name: tFileName; VAR enc, eol: INTEGER): tInput;
\r
335 res.getChar := NIL;
\r
336 res.clipbrd := FALSE;
\r
337 fsize := File.FileSize(name);
\r
339 res.buffer := KOSAPI.malloc(4096);
\r
340 ASSERT(res.buffer # 0);
\r
343 res.buffer := File.Load(name, res.cnt)
\r
345 IF res.buffer = 0 THEN
\r
348 enc := detectEncoding(res);
\r
349 IF (enc = E.UTF8BOM) OR (enc = E.UTF8) THEN
\r
350 res.getChar := getCharUTF8
\r
351 ELSIF enc = E.CP866 THEN
\r
352 res.getChar := getCharCP866
\r
353 ELSIF enc = E.W1251 THEN
\r
354 res.getChar := getCharW1251
\r
356 eol := detectEOL(res)
\r
362 PROCEDURE clipboard* (): tInput;
\r
369 res.clipbrd := TRUE;
\r
370 res.getChar := NIL;
\r
371 res.getChar := getCharCP866;
\r
372 res.buffer := CB.get(res.cnt);
\r
373 IF res.buffer = 0 THEN
\r
380 PROCEDURE putByte (file: tOutput; b: BYTE);
\r
384 IF file.pos = BUF_SIZE THEN
\r
385 c := File.Write(file.handle, SYSTEM.ADR(file.buffer[0]), BUF_SIZE);
\r
388 file.buffer[file.pos] := b;
\r
393 PROCEDURE putString* (file: tOutput; line: Lines.tLine; n: INTEGER): INTEGER;
\r
401 WHILE (i < n) & ~err DO
\r
402 c := Lines.getChar(line, i);
\r
403 IF c # Lines.TAB1 THEN
\r
404 IF ~file.putChar(file, ORD(c)) THEN
\r
415 PROCEDURE newLine* (file: tOutput): BOOLEAN;
\r
420 WHILE (file.eol[i] # 0X) & file.putChar(file, ORD(file.eol[i])) DO
\r
423 RETURN i = LENGTH(file.eol)
\r
427 PROCEDURE putCharUTF8 (file: tOutput; code: INTEGER): BOOLEAN;
\r
432 IF code <= 7FH THEN
\r
433 putByte(file, code)
\r
434 ELSIF (80H <= code) & (code <= 7FFH) THEN
\r
435 putByte(file, code DIV 64 + 0C0H);
\r
436 putByte(file, code MOD 64 + 080H)
\r
437 ELSIF (800H <= code) & (code <= 0FFFFH) THEN
\r
438 putByte(file, code DIV 4096 + 0E0H);
\r
439 putByte(file, (code DIV 64) MOD 64 + 080H);
\r
440 putByte(file, code MOD 64 + 080H)
\r
448 PROCEDURE putCharW1251 (file: tOutput; code: INTEGER): BOOLEAN;
\r
454 n := E.UNI[code, E.W1251];
\r
455 IF n # E.UNDEF THEN
\r
464 PROCEDURE putCharCP866 (file: tOutput; code: INTEGER): BOOLEAN;
\r
470 n := E.UNI[code, E.CP866];
\r
471 IF n # E.UNDEF THEN
\r
480 PROCEDURE putCharUTF16LE (file: tOutput; code: INTEGER): BOOLEAN;
\r
484 IF (0 <= code) & (code <= 65535) THEN
\r
486 putByte(file, code MOD 256);
\r
487 putByte(file, code DIV 256)
\r
492 END putCharUTF16LE;
\r
495 PROCEDURE close* (VAR file: tOutput): BOOLEAN;
\r
501 IF file.handle # NIL THEN
\r
502 IF file.pos > 0 THEN
\r
503 res := File.Write(file.handle, SYSTEM.ADR(file.buffer[0]), file.pos) = file.pos
\r
505 File.Close(file.handle)
\r
513 PROCEDURE create* (name: tFileName; enc, nl: INTEGER): tOutput;
\r
519 res.eol := eol[nl];
\r
520 res.putChar := NIL;
\r
521 IF (enc = E.UTF8) OR (enc = E.UTF8BOM) THEN
\r
522 res.putChar := putCharUTF8;
\r
523 IF enc = E.UTF8BOM THEN
\r
524 ASSERT(res.putChar(res, ORD(BOM)))
\r
526 ELSIF enc = E.UTF16LE THEN
\r
527 res.putChar := putCharUTF16LE;
\r
528 ELSIF enc = E.W1251 THEN
\r
529 res.putChar := putCharW1251
\r
530 ELSIF enc = E.CP866 THEN
\r
531 res.putChar := putCharCP866
\r
533 ASSERT(res.putChar # NIL);
\r
534 res.handle := File.Create(name);
\r
535 IF res.handle = NIL THEN
\r
542 PROCEDURE destroy* (VAR file: tInput);
\r
545 IF file.buffer # 0 THEN
\r
546 file.buffer := KOSAPI.free(file.buffer - 12*ORD(file.clipbrd))
\r
554 eol[EOL_CRLF] := CR + LF;
\r
557 eolNames[EOL_CRLF] := "CRLF";
\r
558 eolNames[EOL_LF] := "LF";
\r
559 eolNames[EOL_CR] := "CR"
\r