Subversion Repositories Kolibri OS

Rev

Rev 8728 | Rev 9200 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8728 leency 1
(*
2
    Copyright 2021 Anton Krotov
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
    EOL_LF* = 0; EOL_CRLF* = 1; EOL_CR* = 2;
37
 
38
 
39
TYPE
40
 
41
    tFileName* = ARRAY NAME_LEN OF CHAR;
42
 
43
    tEOL = ARRAY 3 OF WCHAR;
44
 
45
    tInput* = POINTER TO RECORD
46
        buffer:   INTEGER;
47
        pos, cnt: INTEGER;
48
        enc:      INTEGER;
49
        CR:       BOOLEAN;
50
        clipbrd:  BOOLEAN;
51
        getChar:  PROCEDURE (file: tInput): INTEGER
52
    END;
53
 
54
    tOutput* = POINTER TO RECORD
55
        handle:   File.FS;
56
        buffer:   ARRAY BUF_SIZE OF BYTE;
57
        pos:      INTEGER;
58
        eol:      tEOL;
59
        putChar:  PROCEDURE (file: tOutput; code: INTEGER): BOOLEAN
60
    END;
61
 
62
 
63
VAR
64
 
65
    eol*: ARRAY 3 OF tEOL;
66
 
67
 
68
PROCEDURE getByte (file: tInput): BYTE;
69
VAR
70
    res: BYTE;
71
BEGIN
72
    IF file.cnt > 0 THEN
73
        SYSTEM.GET8(file.buffer + file.pos, res);
74
        INC(file.pos);
75
        DEC(file.cnt)
76
    ELSE
77
        res := 0
78
    END
79
    RETURN res
80
END getByte;
81
 
82
 
83
PROCEDURE peakByte (file: tInput): BYTE;
84
VAR
85
    res: BYTE;
86
BEGIN
87
    IF file.cnt > 0 THEN
88
        SYSTEM.GET8(file.buffer + file.pos, res)
89
    ELSE
90
        res := 0
91
    END
92
    RETURN res
93
END peakByte;
94
 
95
 
96
PROCEDURE getCharUTF8 (file: tInput): INTEGER;
97
VAR
98
    code, n: INTEGER;
99
    b: BYTE;
100
BEGIN
101
    b := getByte(file);
102
    IF b <= 07FH THEN
103
        n := 0
104
    ELSIF (0C0H <= b) & (b <= 0DFH) THEN
105
        DEC(b, 0C0H);
106
        n := 1
107
    ELSIF (0E0H <= b) & (b <= 0EFH) THEN
108
        DEC(b, 0E0H);
109
        n := 2
110
    ELSIF (0F0H <= b) & (b <= 0F7H) THEN
111
        DEC(b, 0F0H);
112
        n := 3
113
    ELSIF (0F8H <= b) & (b <= 0FBH) THEN
114
        DEC(b, 0F8H);
115
        n := 4
116
    ELSIF (0FCH <= b) & (b <= 0FDH) THEN
117
        DEC(b, 0FCH);
118
        n := 5
119
    ELSIF b = 0FEH THEN
120
        b := 0;
121
        n := 6
122
    ELSIF b = 0FFH THEN
123
        n := -1
124
    ELSIF (080H <= b) & (b <= 0BFH) THEN
125
        n := -1
126
    END;
127
 
128
    code := b;
129
 
130
    IF n > 2 THEN
131
        n := -1
132
    END;
133
 
134
    WHILE n > 0 DO
135
        DEC(n);
136
        b := peakByte(file);
137
        IF (080H <= b) & (b <= 0BFH) THEN
138
            code := code*64 + getByte(file) - 080H
139
        ELSE
140
            n := -1
141
        END
142
    END;
143
 
144
    IF n = -1 THEN
145
        code := E.UNDEF
146
    END
147
 
148
    RETURN code
149
END getCharUTF8;
150
 
151
 
152
PROCEDURE getCharW1251 (file: tInput): INTEGER;
153
    RETURN E.cpW1251[getByte(file)]
154
END getCharW1251;
155
 
156
 
157
PROCEDURE getCharCP866 (file: tInput): INTEGER;
158
    RETURN E.cp866[getByte(file)]
159
END getCharCP866;
160
 
161
 
162
PROCEDURE getCharUTF16LE (file: tInput): INTEGER;
163
    RETURN getByte(file) + getByte(file) * 256
164
END getCharUTF16LE;
165
 
166
 
9174 akron1 167
PROCEDURE getString* (file: tInput; line: Lines.tLine; tabs: BOOLEAN; VAR eol: BOOLEAN): INTEGER;
8728 leency 168
VAR
169
    c: WCHAR;
170
    i, L, k, n: INTEGER;
171
    s: ARRAY 1000 OF WCHAR;
172
BEGIN
173
    L := LEN(s);
174
    eol := FALSE;
175
    n := 0;
176
    i := ORD(file.cnt > 0) - 1;
177
    WHILE (file.cnt > 0) & ~eol DO
178
        c := WCHR(file.getChar(file) MOD 65536);
9174 akron1 179
        IF c = Lines.TAB1 THEN
180
        	c := SPACE
181
        END;
8728 leency 182
        IF c = CR THEN
183
            eol := TRUE;
184
            file.CR := TRUE
185
        ELSIF (c = LF) OR (c = 0X) THEN
186
            IF ~file.CR THEN
187
                eol := TRUE
188
            END;
189
            file.CR := FALSE
190
        ELSIF c = TAB THEN
9174 akron1 191
            k := Lines.tab - i MOD Lines.tab;
192
            IF tabs THEN
193
                s[i] := TAB
194
            ELSE
195
                s[i] := SPACE
196
            END;
197
            INC(i);
198
            DEC(k);
8728 leency 199
            WHILE k > 0 DO
9174 akron1 200
                IF tabs THEN
201
                    s[i] := Lines.TAB1
202
                ELSE
203
                    s[i] := SPACE
204
                END;
8728 leency 205
                INC(i);
206
                IF i = L THEN
207
                    Lines.concat(line, s);
208
                    INC(n, i);
209
                    i := 0
210
                END;
211
                DEC(k)
212
            END;
213
            file.CR := FALSE
214
        ELSIF c = BOM THEN
215
            file.CR := FALSE
216
        ELSE
217
            s[i] := c;
218
            INC(i);
219
            IF i = L THEN
220
                Lines.concat(line, s);
221
                INC(n, i);
222
                i := 0
223
            END;
224
            file.CR := FALSE
225
        END
226
    END;
227
    IF i >= 0 THEN
228
        s[i] := 0X;
229
        Lines.concat(line, s);
230
    END;
231
    INC(n, i)
232
    RETURN n
233
END getString;
234
 
235
 
236
PROCEDURE detectEncoding (text: tInput): INTEGER;
237
VAR
238
    pos, cnt, res: INTEGER;
239
    continue, bom: BOOLEAN;
240
    b: BYTE;
241
    cp866, w1251: INTEGER;
242
BEGIN
243
    pos := text.pos;
244
    cnt := text.cnt;
245
    continue := TRUE;
246
    WHILE (text.cnt > 0) & continue DO
247
        IF getByte(text) > 127 THEN
248
            continue := FALSE
249
        END
250
    END;
251
    text.cnt := cnt;
252
    text.pos := pos;
253
    IF continue THEN
254
        res := E.CP866
255
    ELSE
256
        bom := getCharUTF8(text) = ORD(BOM);
257
        continue := TRUE;
258
        text.cnt := cnt;
259
        text.pos := pos;
260
        WHILE (text.cnt > 0) & continue DO
261
            IF getCharUTF8(text) = E.UNDEF THEN
262
                continue := FALSE
263
            END
264
        END;
265
        IF continue THEN
266
            IF bom THEN
267
                res := E.UTF8BOM
268
            ELSE
269
                res := E.UTF8
270
            END
271
        ELSE
272
            text.cnt := cnt;
273
            text.pos := pos;
274
            cp866 := 0;
275
            w1251 := 0;
276
            WHILE text.cnt > 0 DO
277
                b := getByte(text);
278
                IF b > 127 THEN
279
                    IF b >= 192 THEN
280
                        INC(w1251)
281
                    ELSE
282
                        INC(cp866)
283
                    END
284
                END
285
            END;
286
            IF w1251 > cp866 THEN
287
                res := E.W1251
288
            ELSE
289
                res := E.CP866
290
            END
291
        END;
292
        text.cnt := cnt;
293
        text.pos := pos
294
    END
295
    RETURN res
296
END detectEncoding;
297
 
298
 
299
PROCEDURE load* (name: tFileName; VAR enc: INTEGER): tInput;
300
VAR
301
    res: tInput;
302
    fsize: INTEGER;
303
BEGIN
304
    NEW(res);
305
    res.pos := 0;
306
    res.CR := FALSE;
307
    res.getChar := NIL;
308
    res.clipbrd := FALSE;
309
    fsize := File.FileSize(name);
310
    IF fsize = 0 THEN
311
        res.buffer := KOSAPI.malloc(4096);
312
        ASSERT(res.buffer # 0);
313
        res.cnt := 0
314
    ELSE
315
        res.buffer := File.Load(name, res.cnt)
316
    END;
317
    IF res.buffer = 0 THEN
318
        DISPOSE(res)
319
    ELSE
320
        enc := detectEncoding(res);
321
        IF (enc = E.UTF8BOM) OR (enc = E.UTF8) THEN
322
            res.getChar := getCharUTF8
323
        ELSIF enc = E.CP866 THEN
324
            res.getChar := getCharCP866
325
        ELSIF enc = E.W1251 THEN
326
            res.getChar := getCharW1251
327
        END;
328
        res.enc := enc
329
    END
330
    RETURN res
331
END load;
332
 
333
 
334
PROCEDURE clipboard* (): tInput;
335
VAR
336
    res: tInput;
337
BEGIN
338
    NEW(res);
339
    res.pos := 0;
340
    res.CR := FALSE;
341
    res.clipbrd := TRUE;
342
    res.getChar := NIL;
343
    res.enc := E.CP866;
344
    res.getChar := getCharCP866;
345
    res.buffer := CB.get(res.cnt);
346
    IF res.buffer = 0 THEN
347
        DISPOSE(res)
348
    END
349
    RETURN res
350
END clipboard;
351
 
352
 
353
PROCEDURE putByte (file: tOutput; b: BYTE);
354
VAR
355
    c: INTEGER;
356
BEGIN
357
    IF file.pos = BUF_SIZE THEN
358
        c := File.Write(file.handle, SYSTEM.ADR(file.buffer[0]), BUF_SIZE);
359
        file.pos := 0
360
    END;
361
    file.buffer[file.pos] := b;
362
    INC(file.pos)
363
END putByte;
364
 
365
 
366
PROCEDURE putString* (file: tOutput; line: Lines.tLine; n: INTEGER): INTEGER;
367
VAR
368
    i: INTEGER;
9174 akron1 369
    c: WCHAR;
370
    err: BOOLEAN;
8728 leency 371
BEGIN
372
    i := 0;
9174 akron1 373
    err := FALSE;
374
    WHILE (i < n) & ~err DO
375
        c := Lines.getChar(line, i);
376
        IF c # Lines.TAB1 THEN
377
            IF ~file.putChar(file, ORD(c)) THEN
378
                err := TRUE;
379
                DEC(i)
380
            END
381
        END;
8728 leency 382
        INC(i)
383
    END
384
    RETURN i
385
END putString;
386
 
387
 
388
PROCEDURE newLine* (file: tOutput): BOOLEAN;
389
VAR
390
    i: INTEGER;
391
BEGIN
392
    i := 0;
393
    WHILE (file.eol[i] # 0X) & file.putChar(file, ORD(file.eol[i])) DO
394
        INC(i)
395
    END
396
    RETURN i = LENGTH(file.eol)
397
END newLine;
398
 
399
 
400
PROCEDURE putCharUTF8 (file: tOutput; code: INTEGER): BOOLEAN;
401
VAR
402
    res: BOOLEAN;
403
BEGIN
404
    res := TRUE;
405
    IF code <= 7FH THEN
406
        putByte(file, code)
407
    ELSIF (80H <= code) & (code <= 7FFH) THEN
408
        putByte(file, code DIV 64 + 0C0H);
409
        putByte(file, code MOD 64 + 080H)
410
    ELSIF (800H <= code) & (code <= 0FFFFH) THEN
411
        putByte(file, code DIV 4096 + 0E0H);
412
        putByte(file, (code DIV 64) MOD 64 + 080H);
413
        putByte(file, code MOD 64 + 080H)
414
    ELSE
415
        res := FALSE
416
    END
417
    RETURN res
418
END putCharUTF8;
419
 
420
 
421
PROCEDURE putCharW1251 (file: tOutput; code: INTEGER): BOOLEAN;
422
VAR
423
    n: INTEGER;
424
    res: BOOLEAN;
425
BEGIN
426
    res := TRUE;
427
    n := E.UNI[code, E.W1251];
428
    IF n # E.UNDEF THEN
429
        putByte(file, n)
430
    ELSE
431
        res := FALSE
432
    END
433
    RETURN res
434
END putCharW1251;
435
 
436
 
437
PROCEDURE putCharCP866 (file: tOutput; code: INTEGER): BOOLEAN;
438
VAR
439
    n: INTEGER;
440
    res: BOOLEAN;
441
BEGIN
442
    res := TRUE;
443
    n := E.UNI[code, E.CP866];
444
    IF n # E.UNDEF THEN
445
        putByte(file, n)
446
    ELSE
447
        res := FALSE
448
    END
449
    RETURN res
450
END putCharCP866;
451
 
452
 
453
PROCEDURE putCharUTF16LE (file: tOutput; code: INTEGER): BOOLEAN;
454
VAR
455
    res: BOOLEAN;
456
BEGIN
457
    IF (0 <= code) & (code <= 65535) THEN
458
        res := TRUE;
459
        putByte(file, code MOD 256);
460
        putByte(file, code DIV 256)
461
    ELSE
462
        res := FALSE
463
    END
464
    RETURN res
465
END putCharUTF16LE;
466
 
467
 
468
PROCEDURE close* (VAR file: tOutput): BOOLEAN;
469
VAR
470
    res: BOOLEAN;
471
BEGIN
472
    res := TRUE;
473
    IF file # NIL THEN
474
        IF file.handle # NIL THEN
475
            IF file.pos > 0 THEN
476
                res := File.Write(file.handle, SYSTEM.ADR(file.buffer[0]), file.pos) = file.pos
477
            END;
478
            File.Close(file.handle)
479
        END;
480
        DISPOSE(file)
481
    END
482
    RETURN res
483
END close;
484
 
485
 
486
PROCEDURE create* (name: tFileName; enc, nl: INTEGER): tOutput;
487
VAR
488
    res: tOutput;
489
BEGIN
490
    NEW(res);
491
    res.pos := 0;
492
    res.eol := eol[nl];
493
    res.putChar := NIL;
494
    IF (enc = E.UTF8) OR (enc = E.UTF8BOM) THEN
495
        res.putChar := putCharUTF8;
496
        IF enc = E.UTF8BOM THEN
497
            ASSERT(res.putChar(res, ORD(BOM)))
498
        END
499
    ELSIF enc = E.UTF16LE THEN
500
        res.putChar := putCharUTF16LE;
501
    ELSIF enc = E.W1251 THEN
502
        res.putChar := putCharW1251
503
    ELSIF enc = E.CP866 THEN
504
        res.putChar := putCharCP866
505
    END;
506
    ASSERT(res.putChar # NIL);
507
    res.handle := File.Create(name);
508
    IF res.handle = NIL THEN
509
        DISPOSE(res)
510
    END
511
    RETURN res
512
END create;
513
 
514
 
515
PROCEDURE destroy* (VAR file: tInput);
516
BEGIN
517
    IF file # NIL THEN
518
        IF file.buffer # 0 THEN
519
            file.buffer := KOSAPI.free(file.buffer - 12*ORD(file.clipbrd))
520
        END;
521
        DISPOSE(file)
522
    END
523
END destroy;
524
 
525
 
526
BEGIN
527
    eol[EOL_LF] := LF;
528
    eol[EOL_CRLF] := CR + LF;
529
    eol[EOL_CR] := CR
530
END RW.