Subversion Repositories Kolibri OS

Rev

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