Subversion Repositories Kolibri OS

Rev

Rev 9708 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8728 leency 1
(*
9902 akron1 2
    Copyright 2021-2023 Anton Krotov
8728 leency 3
 
4
    This file is part of CEdit.
5
 
6
    CEdit is free software: you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation, either version 3 of the License, or
9
    (at your option) any later version.
10
 
11
    CEdit is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with CEdit. If not, see .
18
*)
19
 
20
MODULE RW;
21
 
22
IMPORT
23
    File, SYSTEM, KOSAPI, E := Encodings,
24
    CB := Clipboard, Lines;
25
 
26
 
27
CONST
28
 
29
    CR = 0DX; LF = 0AX; TAB = 9X; SPACE = 20X;
30
    BOM = 0FEFFX;
31
 
32
    BUF_SIZE = 65536;
33
 
34
    NAME_LEN = 1024;
35
 
36
 
37
TYPE
38
 
39
    tFileName* = ARRAY NAME_LEN OF CHAR;
40
 
41
    tInput* = POINTER TO RECORD
42
        buffer:   INTEGER;
9522 akron1 43
        strBuf:   Lines.tLine;
8728 leency 44
        pos, cnt: INTEGER;
45
        CR:       BOOLEAN;
46
        clipbrd:  BOOLEAN;
47
        getChar:  PROCEDURE (file: tInput): INTEGER
48
    END;
49
 
50
    tOutput* = POINTER TO RECORD
51
        handle:   File.FS;
52
        buffer:   ARRAY BUF_SIZE OF BYTE;
53
        pos:      INTEGER;
9659 akron1 54
        eol:      E.tEOL;
9522 akron1 55
        putChar:  PROCEDURE (file: tOutput; code: INTEGER);
56
        error:    BOOLEAN
8728 leency 57
    END;
58
 
59
 
60
PROCEDURE getByte (file: tInput): BYTE;
61
VAR
62
    res: BYTE;
63
BEGIN
64
    IF file.cnt > 0 THEN
65
        SYSTEM.GET8(file.buffer + file.pos, res);
66
        INC(file.pos);
67
        DEC(file.cnt)
68
    ELSE
69
        res := 0
70
    END
71
    RETURN res
72
END getByte;
73
 
74
 
75
PROCEDURE peakByte (file: tInput): BYTE;
76
VAR
77
    res: BYTE;
78
BEGIN
79
    IF file.cnt > 0 THEN
80
        SYSTEM.GET8(file.buffer + file.pos, res)
81
    ELSE
82
        res := 0
83
    END
84
    RETURN res
85
END peakByte;
86
 
87
 
88
PROCEDURE getCharUTF8 (file: tInput): INTEGER;
89
VAR
90
    code, n: INTEGER;
91
    b: BYTE;
92
BEGIN
93
    b := getByte(file);
94
    IF b <= 07FH THEN
95
        n := 0
96
    ELSIF (0C0H <= b) & (b <= 0DFH) THEN
97
        DEC(b, 0C0H);
98
        n := 1
99
    ELSIF (0E0H <= b) & (b <= 0EFH) THEN
100
        DEC(b, 0E0H);
101
        n := 2
9659 akron1 102
    ELSE
103
    	n := -1
104
(*    ELSIF (0F0H <= b) & (b <= 0F7H) THEN
8728 leency 105
        DEC(b, 0F0H);
106
        n := 3
107
    ELSIF (0F8H <= b) & (b <= 0FBH) THEN
108
        DEC(b, 0F8H);
109
        n := 4
110
    ELSIF (0FCH <= b) & (b <= 0FDH) THEN
111
        DEC(b, 0FCH);
112
        n := 5
113
    ELSIF b = 0FEH THEN
114
        b := 0;
115
        n := 6
116
    ELSIF b = 0FFH THEN
117
        n := -1
118
    ELSIF (080H <= b) & (b <= 0BFH) THEN
9659 akron1 119
        n := -1*)
8728 leency 120
    END;
121
 
122
    code := b;
9659 akron1 123
(*
8728 leency 124
    IF n > 2 THEN
125
        n := -1
126
    END;
9659 akron1 127
*)
8728 leency 128
    WHILE n > 0 DO
129
        DEC(n);
130
        b := peakByte(file);
131
        IF (080H <= b) & (b <= 0BFH) THEN
132
            code := code*64 + getByte(file) - 080H
133
        ELSE
134
            n := -1
135
        END
136
    END;
137
 
138
    IF n = -1 THEN
9902 akron1 139
        code := -1
8728 leency 140
    END
141
 
142
    RETURN code
143
END getCharUTF8;
144
 
145
 
9708 akron1 146
PROCEDURE getCharCP1251 (file: tInput): INTEGER;
9674 akron1 147
    RETURN E.cp1251[getByte(file)]
9708 akron1 148
END getCharCP1251;
8728 leency 149
 
150
 
151
PROCEDURE getCharCP866 (file: tInput): INTEGER;
152
    RETURN E.cp866[getByte(file)]
153
END getCharCP866;
154
 
9659 akron1 155
(*
8728 leency 156
PROCEDURE getCharUTF16LE (file: tInput): INTEGER;
157
    RETURN getByte(file) + getByte(file) * 256
158
END getCharUTF16LE;
9659 akron1 159
*)
8728 leency 160
 
9174 akron1 161
PROCEDURE getString* (file: tInput; line: Lines.tLine; tabs: BOOLEAN; VAR eol: BOOLEAN): INTEGER;
8728 leency 162
VAR
163
    c: WCHAR;
9522 akron1 164
    i, k, n: INTEGER;
8728 leency 165
BEGIN
166
    eol := FALSE;
167
    n := 0;
168
    i := ORD(file.cnt > 0) - 1;
169
    WHILE (file.cnt > 0) & ~eol DO
170
        c := WCHR(file.getChar(file) MOD 65536);
9174 akron1 171
        IF c = Lines.TAB1 THEN
172
        	c := SPACE
9560 akron1 173
        ELSIF c = 0X THEN
174
        	c := Lines.NUL
9174 akron1 175
        END;
9560 akron1 176
 
8728 leency 177
        IF c = CR THEN
178
            eol := TRUE;
179
            file.CR := TRUE
9560 akron1 180
        ELSIF c = LF THEN
8728 leency 181
            IF ~file.CR THEN
182
                eol := TRUE
183
            END;
184
            file.CR := FALSE
185
        ELSIF c = TAB THEN
9174 akron1 186
            k := Lines.tab - i MOD Lines.tab;
187
            IF tabs THEN
9522 akron1 188
                Lines.setChar(file.strBuf, i, TAB)
9174 akron1 189
            ELSE
9522 akron1 190
            	Lines.setChar(file.strBuf, i, SPACE)
9174 akron1 191
            END;
192
            INC(i);
193
            DEC(k);
8728 leency 194
            WHILE k > 0 DO
9174 akron1 195
                IF tabs THEN
9522 akron1 196
                    Lines.setChar(file.strBuf, i, Lines.TAB1)
9174 akron1 197
                ELSE
9522 akron1 198
                    Lines.setChar(file.strBuf, i, SPACE)
9174 akron1 199
                END;
8728 leency 200
                INC(i);
201
                DEC(k)
202
            END;
203
            file.CR := FALSE
204
        ELSIF c = BOM THEN
205
            file.CR := FALSE
206
        ELSE
9522 akron1 207
        	Lines.setChar(file.strBuf, i, c);
8728 leency 208
            INC(i);
209
            file.CR := FALSE
210
        END
211
    END;
212
    IF i >= 0 THEN
9522 akron1 213
    	Lines.setChar(file.strBuf, i, 0X);
214
    	file.strBuf.length := i;
215
    	Lines._insert2(line, 0, file.strBuf)
8728 leency 216
    END;
217
    INC(n, i)
218
    RETURN n
219
END getString;
220
 
221
 
222
PROCEDURE detectEncoding (text: tInput): INTEGER;
223
VAR
224
    pos, cnt, res: INTEGER;
225
    continue, bom: BOOLEAN;
226
    b: BYTE;
9708 akron1 227
    cp866, cp1251: INTEGER;
8728 leency 228
BEGIN
229
    pos := text.pos;
230
    cnt := text.cnt;
231
    continue := TRUE;
232
    WHILE (text.cnt > 0) & continue DO
233
        IF getByte(text) > 127 THEN
234
            continue := FALSE
235
        END
236
    END;
237
    text.cnt := cnt;
238
    text.pos := pos;
239
    IF continue THEN
240
        res := E.CP866
241
    ELSE
242
        bom := getCharUTF8(text) = ORD(BOM);
243
        continue := TRUE;
244
        text.cnt := cnt;
245
        text.pos := pos;
246
        WHILE (text.cnt > 0) & continue DO
9902 akron1 247
            IF getCharUTF8(text) = -1 THEN
8728 leency 248
                continue := FALSE
249
            END
250
        END;
251
        IF continue THEN
252
            IF bom THEN
253
                res := E.UTF8BOM
254
            ELSE
255
                res := E.UTF8
256
            END
257
        ELSE
258
            text.cnt := cnt;
259
            text.pos := pos;
9708 akron1 260
            cp866  := 0;
261
            cp1251 := 0;
8728 leency 262
            WHILE text.cnt > 0 DO
263
                b := getByte(text);
264
                IF b > 127 THEN
265
                    IF b >= 192 THEN
9708 akron1 266
                        INC(cp1251)
8728 leency 267
                    ELSE
268
                        INC(cp866)
269
                    END
270
                END
271
            END;
9708 akron1 272
            IF cp1251 > cp866 THEN
273
                res := E.CP1251
8728 leency 274
            ELSE
275
                res := E.CP866
276
            END
277
        END;
278
        text.cnt := cnt;
279
        text.pos := pos
280
    END
281
    RETURN res
282
END detectEncoding;
283
 
284
 
9180 akron1 285
PROCEDURE detectEOL (text: tInput): INTEGER;
8728 leency 286
VAR
9180 akron1 287
	pos, cnt, c, res: INTEGER;
288
BEGIN
289
	res := -1;
290
	pos := text.pos;
291
	cnt := text.cnt;
292
	WHILE (text.cnt > 0) & (res = -1) DO
293
		c := text.getChar(text);
9671 akron1 294
		IF c = ORD(LF) THEN
9659 akron1 295
			res := E.EOL_LF
9671 akron1 296
		ELSIF c = ORD(CR) THEN
297
			IF text.getChar(text) = ORD(LF) THEN
9659 akron1 298
				res := E.EOL_CRLF
9180 akron1 299
			ELSE
9659 akron1 300
				res := E.EOL_CR
9180 akron1 301
			END
302
		END
303
	END;
304
	text.cnt := cnt;
305
	text.pos := pos;
306
	IF res = -1 THEN
9659 akron1 307
		res := E.EOL_CRLF
9180 akron1 308
	END
309
	RETURN res
310
END detectEOL;
311
 
312
 
9522 akron1 313
PROCEDURE getMaxLength (file: tInput): INTEGER;
314
VAR
315
	res, cur, cnt: INTEGER;
316
	c: WCHAR;
317
BEGIN
318
	res := 0;
319
	cur := 0;
320
	cnt := file.cnt;
321
	WHILE file.cnt > 0 DO
322
		c := WCHR(file.getChar(file) MOD 65536);
323
		IF (c = CR) OR (c = LF) THEN
324
			cur := 0
325
		ELSIF c = TAB THEN
326
			INC(cur, Lines.tab - cur MOD Lines.tab)
327
		ELSE
328
			INC(cur)
329
		END;
330
		IF cur > res THEN
331
			res := cur
332
		END
333
	END;
334
	file.cnt := cnt;
335
	file.pos := 0
336
	RETURN res
337
END getMaxLength;
338
 
339
 
340
PROCEDURE createStrBuf (file: tInput);
341
BEGIN
342
	file.strBuf := Lines.create(TRUE);
343
	Lines.resize(file.strBuf, MAX(2048, getMaxLength(file) + 1))
344
END createStrBuf;
345
 
346
 
9674 akron1 347
PROCEDURE _loadFromMem (ptr, size: INTEGER; cp866: BOOLEAN; VAR enc, eol: INTEGER): tInput;
9180 akron1 348
VAR
8728 leency 349
    res: tInput;
350
BEGIN
351
    NEW(res);
352
    res.pos := 0;
353
    res.CR := FALSE;
354
    res.getChar := NIL;
355
    res.clipbrd := FALSE;
9674 akron1 356
    res.buffer := ptr;
357
    res.cnt := size;
8728 leency 358
    IF res.buffer = 0 THEN
359
        DISPOSE(res)
360
    ELSE
361
        enc := detectEncoding(res);
9659 akron1 362
        IF enc IN {E.UTF8BOM, E.UTF8} THEN
8728 leency 363
            res.getChar := getCharUTF8
364
        ELSIF enc = E.CP866 THEN
365
            res.getChar := getCharCP866
9708 akron1 366
        ELSIF enc = E.CP1251 THEN
9674 akron1 367
        	IF cp866 THEN
368
        		enc := E.CP866;
369
        		res.getChar := getCharCP866
370
        	ELSE
9708 akron1 371
            	res.getChar := getCharCP1251
9674 akron1 372
            END
8728 leency 373
        END;
9522 akron1 374
        eol := detectEOL(res);
375
        createStrBuf(res)
8728 leency 376
    END
377
    RETURN res
9674 akron1 378
END _loadFromMem;
8728 leency 379
 
380
 
9674 akron1 381
PROCEDURE loadFromMem* (ptr, size: INTEGER; VAR enc, eol: INTEGER): tInput;
382
    RETURN _loadFromMem(ptr, size, TRUE, enc, eol)
383
END loadFromMem;
384
 
385
 
386
PROCEDURE loadFromFile* (name: tFileName; VAR enc, eol: INTEGER): tInput;
387
VAR
388
    ptr, size: INTEGER;
389
BEGIN
390
	size := File.FileSize(name);
391
    IF size = 0 THEN
392
    	ptr := KOSAPI.malloc(4096)
393
    ELSE
394
    	ptr := File.Load(name, size)
395
    END
396
	RETURN _loadFromMem(ptr, size, FALSE, enc, eol)
397
END loadFromFile;
398
 
399
 
8728 leency 400
PROCEDURE clipboard* (): tInput;
401
VAR
402
    res: tInput;
403
BEGIN
404
    NEW(res);
405
    res.pos := 0;
406
    res.CR := FALSE;
407
    res.clipbrd := TRUE;
408
    res.getChar := NIL;
409
    res.getChar := getCharCP866;
410
    res.buffer := CB.get(res.cnt);
411
    IF res.buffer = 0 THEN
412
        DISPOSE(res)
9522 akron1 413
    ELSE
414
    	createStrBuf(res)
8728 leency 415
    END
416
    RETURN res
417
END clipboard;
418
 
419
 
420
PROCEDURE putByte (file: tOutput; b: BYTE);
421
BEGIN
422
    IF file.pos = BUF_SIZE THEN
9522 akron1 423
        IF File.Write(file.handle, SYSTEM.ADR(file.buffer[0]), BUF_SIZE) # BUF_SIZE THEN
424
        	file.error := TRUE
425
        END;
8728 leency 426
        file.pos := 0
427
    END;
428
    file.buffer[file.pos] := b;
429
    INC(file.pos)
430
END putByte;
431
 
432
 
9522 akron1 433
PROCEDURE putString* (file: tOutput; line: Lines.tLine; n: INTEGER);
8728 leency 434
VAR
435
    i: INTEGER;
9174 akron1 436
    c: WCHAR;
8728 leency 437
BEGIN
9522 akron1 438
    FOR i := 0 TO n - 1 DO
9174 akron1 439
        c := Lines.getChar(line, i);
9659 akron1 440
        IF c = Lines.NUL THEN
9560 akron1 441
        	file.putChar(file, 0)
9659 akron1 442
        ELSIF c # Lines.TAB1 THEN
9560 akron1 443
        	file.putChar(file, ORD(c))
9522 akron1 444
        END
8728 leency 445
    END
446
END putString;
447
 
448
 
9522 akron1 449
PROCEDURE newLine* (file: tOutput);
8728 leency 450
VAR
451
    i: INTEGER;
452
BEGIN
453
    i := 0;
9522 akron1 454
    WHILE file.eol[i] # 0X DO
455
    	file.putChar(file, ORD(file.eol[i]));
8728 leency 456
        INC(i)
457
    END
458
END newLine;
459
 
460
 
9522 akron1 461
PROCEDURE putCharUTF8 (file: tOutput; code: INTEGER);
8728 leency 462
BEGIN
463
    IF code <= 7FH THEN
464
        putByte(file, code)
465
    ELSIF (80H <= code) & (code <= 7FFH) THEN
466
        putByte(file, code DIV 64 + 0C0H);
467
        putByte(file, code MOD 64 + 080H)
468
    ELSIF (800H <= code) & (code <= 0FFFFH) THEN
469
        putByte(file, code DIV 4096 + 0E0H);
470
        putByte(file, (code DIV 64) MOD 64 + 080H);
471
        putByte(file, code MOD 64 + 080H)
472
    ELSE
9902 akron1 473
    	putByte(file, E.UNDEF)
8728 leency 474
    END
475
END putCharUTF8;
476
 
477
 
9708 akron1 478
PROCEDURE putCharCP1251 (file: tOutput; code: INTEGER);
9659 akron1 479
BEGIN
9902 akron1 480
	putByte(file, E.UNI[code, E.CP1251])
9708 akron1 481
END putCharCP1251;
8728 leency 482
 
483
 
9522 akron1 484
PROCEDURE putCharCP866 (file: tOutput; code: INTEGER);
8728 leency 485
BEGIN
9902 akron1 486
	putByte(file, E.UNI[code, E.CP866])
8728 leency 487
END putCharCP866;
488
 
9659 akron1 489
(*
9522 akron1 490
PROCEDURE putCharUTF16LE (file: tOutput; code: INTEGER);
8728 leency 491
BEGIN
9522 akron1 492
    IF ~((0 <= code) & (code <= 65535)) THEN
9902 akron1 493
    	code := E.UNDEF
9522 akron1 494
    END;
495
    putByte(file, code MOD 256);
496
    putByte(file, code DIV 256)
9659 akron1 497
END putCharUTF16LE;*)
8728 leency 498
 
499
 
500
PROCEDURE close* (VAR file: tOutput): BOOLEAN;
501
VAR
502
    res: BOOLEAN;
503
BEGIN
504
    res := TRUE;
505
    IF file # NIL THEN
506
        IF file.handle # NIL THEN
507
            IF file.pos > 0 THEN
508
                res := File.Write(file.handle, SYSTEM.ADR(file.buffer[0]), file.pos) = file.pos
509
            END;
9522 akron1 510
            res := res & ~file.error;
8728 leency 511
            File.Close(file.handle)
512
        END;
513
        DISPOSE(file)
514
    END
515
    RETURN res
516
END close;
517
 
518
 
519
PROCEDURE create* (name: tFileName; enc, nl: INTEGER): tOutput;
520
VAR
521
    res: tOutput;
522
BEGIN
523
    NEW(res);
524
    res.pos := 0;
9659 akron1 525
    res.eol := E.eol[nl];
8728 leency 526
    res.putChar := NIL;
9659 akron1 527
    IF enc IN {E.UTF8BOM, E.UTF8} THEN
8728 leency 528
        IF enc = E.UTF8BOM THEN
9659 akron1 529
            putCharUTF8(res, ORD(BOM))
530
        END;
531
        res.putChar := putCharUTF8
532
    (*ELSIF enc = E.UTF16LE THEN
533
        res.putChar := putCharUTF16LE*)
9708 akron1 534
    ELSIF enc = E.CP1251 THEN
535
        res.putChar := putCharCP1251
8728 leency 536
    ELSIF enc = E.CP866 THEN
537
        res.putChar := putCharCP866
538
    END;
539
    ASSERT(res.putChar # NIL);
540
    res.handle := File.Create(name);
9522 akron1 541
    res.error := FALSE;
8728 leency 542
    IF res.handle = NIL THEN
543
        DISPOSE(res)
544
    END
545
    RETURN res
546
END create;
547
 
548
 
549
PROCEDURE destroy* (VAR file: tInput);
9522 akron1 550
VAR
551
	null: INTEGER;
8728 leency 552
BEGIN
553
    IF file # NIL THEN
554
        IF file.buffer # 0 THEN
9522 akron1 555
            null := KOSAPI.free(file.buffer - 12*ORD(file.clipbrd))
8728 leency 556
        END;
9522 akron1 557
        IF file.strBuf # NIL THEN
558
        	Lines.resize(file.strBuf, 0)
559
        END;
8728 leency 560
        DISPOSE(file)
561
    END
562
END destroy;
563
 
564
 
565
END RW.