~ubuntu-branches/ubuntu/wily/luatex/wily

« back to all changes in this revision

Viewing changes to source/texk/web2c/luatexdir/tex/stringpool.w

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2010-04-29 00:47:19 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20100429004719-o42etkqe90n97b9e
Tags: 0.60.1-1
* new upstream release, adapt build-script patch
* disable patch: upstream-epstopdf_cc_no_xpdf_patching, included upstream
* disable patch: libpoppler-0.12, not needed anymore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
% stringpool.w
 
2
 
3
% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
 
4
 
 
5
% This file is part of LuaTeX.
 
6
 
 
7
% LuaTeX is free software; you can redistribute it and/or modify it under
 
8
% the terms of the GNU General Public License as published by the Free
 
9
% Software Foundation; either version 2 of the License, or (at your
 
10
% option) any later version.
 
11
 
 
12
% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
 
13
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
15
% License for more details.
 
16
 
 
17
% You should have received a copy of the GNU General Public License along
 
18
% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
 
19
 
 
20
@ @c
 
21
#include "ptexlib.h"
 
22
 
 
23
static const char _svn_version[] =
 
24
    "$Id: stringpool.w 3587 2010-04-03 14:32:25Z taco $ "
 
25
    "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.1/source/texk/web2c/luatexdir/tex/stringpool.w $";
 
26
 
 
27
@ Control sequence names and diagnostic messages are variable-length strings
 
28
of eight-bit characters. Since PASCAL did not have a well-developed string
 
29
mechanism, \TeX\ did all of its string processing by homegrown methods.
 
30
 
 
31
Elaborate facilities for dynamic strings are not needed, so all of the
 
32
necessary operations can be handled with a simple data structure.
 
33
The array |str_pool| contains all of the (eight-bit) bytes off all
 
34
of the strings, and the array |str_start| contains indices of the starting
 
35
points of each string. Strings are referred to by integer numbers, so that
 
36
string number |s| comprises the characters |str_pool[j]| for
 
37
|str_start_macro(s)<=j<str_start_macro(s+1)|. Additional integer variables
 
38
|pool_ptr| and |str_ptr| indicate the number of entries used so far
 
39
in |str_pool| and |str_start|, respectively; locations
 
40
|str_pool[pool_ptr]| and |str_start_macro(str_ptr)| are
 
41
ready for the next string to be allocated.
 
42
 
 
43
String numbers 0 to |biggest_char| are reserved for strings that correspond to 
 
44
single UNICODE characters. This is in accordance with the conventions of \.{WEB}
 
45
which converts single-character strings into the ASCII code number of the
 
46
single character involved.
 
47
 
 
48
@c
 
49
lstring *string_pool;           /* the array of strings */
 
50
lstring *_string_pool;          /* this variable lives |STRING_OFFSET| below |string_pool| 
 
51
                                   (handy for debugging: 
 
52
                                   |_string_pool[str_ptr] == str_string(str_ptr)| */
 
53
 
 
54
str_number str_ptr = (STRING_OFFSET + 1);       /* number of the current string being created */
 
55
str_number init_str_ptr;        /* the starting value of |str_ptr| */
 
56
 
 
57
unsigned char *cur_string;      /*  current string buffer */
 
58
unsigned cur_length;            /* current index in that buffer */
 
59
unsigned cur_string_size;       /*  malloced size of |cur_string| */
 
60
unsigned pool_size;             /* occupied byte count */
 
61
 
 
62
 
 
63
@ Once a sequence of characters has been appended to |cur_string|, it
 
64
officially becomes a string when the function |make_string| is called.
 
65
This function returns the identification number of the new string as its
 
66
value.
 
67
 
 
68
@c
 
69
void reset_cur_string(void)
 
70
{
 
71
    cur_length = 0;
 
72
    cur_string_size = 255;
 
73
    cur_string = (unsigned char *) xmalloc(256);
 
74
    memset(cur_string, 0, 256);
 
75
}
 
76
 
 
77
@  current string enters the pool 
 
78
@c
 
79
str_number make_string(void)
 
80
{
 
81
    if (str_ptr == (max_strings + STRING_OFFSET))
 
82
        overflow("number of strings",
 
83
                 (unsigned) (max_strings - init_str_ptr + STRING_OFFSET));
 
84
    str_room(1);
 
85
    cur_string[cur_length] = '\0';      /* now |lstring.s| is always a valid C string */
 
86
    str_string(str_ptr) = (unsigned char *) cur_string;
 
87
    str_length(str_ptr) = cur_length;
 
88
    pool_size += cur_length;
 
89
    reset_cur_string();
 
90
#if 0
 
91
    printf("Made a string: %s (s=%d)\n", (char *)str_string(str_ptr), (int)str_ptr);
 
92
#endif
 
93
    str_ptr++;
 
94
    return (str_ptr - 1);
 
95
}
 
96
 
 
97
@ @c
 
98
static void utf_error(void)
 
99
{
 
100
    const char *hlp[] =
 
101
        { "A funny symbol that I can't read has just been (re)read.",
 
102
        "Just continue, I'll change it to 0xFFFD.",
 
103
        NULL
 
104
    };
 
105
    deletions_allowed = false;
 
106
    tex_error("String contains an invalid utf-8 sequence", hlp);
 
107
    deletions_allowed = true;
 
108
}
 
109
 
 
110
@ @c
 
111
unsigned str2uni(const unsigned char *k)
 
112
{
 
113
    register int ch;
 
114
    unsigned val = 0xFFFD;
 
115
    const unsigned char *text = k;
 
116
    if ((ch = *text++) < 0x80) {
 
117
        val = (unsigned) ch;
 
118
    } else if (ch <= 0xbf) {    /* error */
 
119
    } else if (ch <= 0xdf) {
 
120
        if (*text >= 0x80 && *text < 0xc0)
 
121
            val = (unsigned) (((ch & 0x1f) << 6) | (*text++ & 0x3f));
 
122
    } else if (ch <= 0xef) {
 
123
        if (*text >= 0x80 && *text < 0xc0 && text[1] >= 0x80 && text[1] < 0xc0) {
 
124
            val = (unsigned)
 
125
                (((ch & 0xf) << 12) | ((text[0] & 0x3f) << 6) |
 
126
                 (text[1] & 0x3f));
 
127
        }
 
128
    } else {
 
129
        int w = (((ch & 0x7) << 2) | ((text[0] & 0x30) >> 4)) - 1, w2;
 
130
        w = (w << 6) | ((text[0] & 0xf) << 2) | ((text[1] & 0x30) >> 4);
 
131
        w2 = ((text[1] & 0xf) << 6) | (text[2] & 0x3f);
 
132
        val = (unsigned) (w * 0x400 + w2 + 0x10000);
 
133
        if (*text < 0x80 || text[1] < 0x80 || text[2] < 0x80 ||
 
134
            *text >= 0xc0 || text[1] >= 0xc0 || text[2] >= 0xc0)
 
135
            val = 0xFFFD;
 
136
    }
 
137
    if (val == 0xFFFD)
 
138
        utf_error();
 
139
    return (val);
 
140
}
 
141
 
 
142
@ This is a very basic helper 
 
143
@c
 
144
unsigned char *uni2str(unsigned unic)
 
145
{
 
146
    unsigned char *buf = xmalloc(5);
 
147
    unsigned char *pt = buf;
 
148
    if (unic < 0x80)
 
149
        *pt++ = (unsigned char) unic;
 
150
    else if (unic < 0x800) {
 
151
        *pt++ = (unsigned char) (0xc0 | (unic >> 6));
 
152
        *pt++ = (unsigned char) (0x80 | (unic & 0x3f));
 
153
    } else if (unic >= 0x110000) {
 
154
        *pt++ = (unsigned char) (unic - 0x110000);
 
155
    } else if (unic < 0x10000) {
 
156
        *pt++ = (unsigned char) (0xe0 | (unic >> 12));
 
157
        *pt++ = (unsigned char) (0x80 | ((unic >> 6) & 0x3f));
 
158
        *pt++ = (unsigned char) (0x80 | (unic & 0x3f));
 
159
    } else {
 
160
        int u, z, y, x;
 
161
        unsigned val = unic - 0x10000;
 
162
        u = (int) (((val & 0xf0000) >> 16) + 1);
 
163
        z = (int) ((val & 0x0f000) >> 12);
 
164
        y = (int) ((val & 0x00fc0) >> 6);
 
165
        x = (int) (val & 0x0003f);
 
166
        *pt++ = (unsigned char) (0xf0 | (u >> 2));
 
167
        *pt++ = (unsigned char) (0x80 | ((u & 3) << 4) | z);
 
168
        *pt++ = (unsigned char) (0x80 | y);
 
169
        *pt++ = (unsigned char) (0x80 | x);
 
170
    }
 
171
    *pt = '\0';
 
172
    return buf;
 
173
}
 
174
 
 
175
 
 
176
@ |buffer_to_unichar| converts a sequence of bytes in the |buffer|
 
177
into a unicode character value. It does not check for overflow
 
178
of the |buffer|, but it is careful to check the validity of the 
 
179
UTF-8 encoding.
 
180
 
 
181
@c
 
182
#define test_sequence_byte(A) do {                      \
 
183
        if (((A)<0x80) || ((A)>=0xC0)) {                \
 
184
            utf_error();                                \
 
185
            return 0xFFFD;                              \
 
186
        }                                               \
 
187
  } while (0)
 
188
 
 
189
 
 
190
static int buffer_to_unichar(int k)
 
191
{
 
192
    int a;                      /* a utf char */
 
193
    int b;                      /* a utf nibble */
 
194
    b = buffer[k];
 
195
    if (b < 0x80) {
 
196
        a = b;
 
197
    } else if (b >= 0xF8) {
 
198
        /* the 5- and 6-byte UTF-8 sequences generate integers 
 
199
           that are outside of the valid UCS range, and therefore
 
200
           unsupported 
 
201
         */
 
202
        test_sequence_byte(-1);
 
203
    } else if (b >= 0xF0) {
 
204
        a = (b - 0xF0) * 64;
 
205
        b = buffer[k + 1];
 
206
        test_sequence_byte(b);
 
207
        a = (a + (b - 128)) * 64;
 
208
        b = buffer[k + 2];
 
209
        test_sequence_byte(b);
 
210
        a = (a + (b - 128)) * 64;
 
211
        b = buffer[k + 3];
 
212
        test_sequence_byte(b);
 
213
        a = a + (b - 128);
 
214
    } else if (b >= 0xE0) {
 
215
        a = (b - 0xE0) * 64;
 
216
        b = buffer[k + 1];
 
217
        test_sequence_byte(b);
 
218
        a = (a + (b - 128)) * 64;
 
219
        b = buffer[k + 2];
 
220
        test_sequence_byte(b);
 
221
        a = a + (b - 128);
 
222
    } else if (b >= 0xC0) {
 
223
        a = (b - 0xC0) * 64;
 
224
        b = buffer[k + 1];
 
225
        test_sequence_byte(b);
 
226
        a = a + (b - 128);
 
227
    } else {
 
228
        /* This is an encoding error */
 
229
        test_sequence_byte(-1);
 
230
    }
 
231
    return a;
 
232
}
 
233
 
 
234
@ @c
 
235
int pool_to_unichar(unsigned char *t)
 
236
{
 
237
    return (int) str2uni(t);
 
238
}
 
239
 
 
240
 
 
241
 
 
242
@ The following subroutine compares string |s| with another string of the
 
243
same length that appears in |buffer| starting at position |k|;
 
244
the result is |true| if and only if the strings are equal.
 
245
Empirical tests indicate that |str_eq_buf| is used in such a way that
 
246
it tends to return |true| about 80 percent of the time.
 
247
 
 
248
@c
 
249
boolean str_eq_buf(str_number s, int k)
 
250
{                               /* test equality of strings */
 
251
    int a;                      /* a unicode character */
 
252
    if (s < STRING_OFFSET) {
 
253
        a = buffer_to_unichar(k);
 
254
        if (a != s)
 
255
            return false;
 
256
    } else {
 
257
        unsigned char *j = str_string(s);
 
258
        unsigned char *l = j + str_length(s);
 
259
        while (j < l) {
 
260
            if (*j++ != buffer[k++])
 
261
                return false;
 
262
        }
 
263
    }
 
264
    return true;
 
265
}
 
266
 
 
267
 
 
268
@ Here is a similar routine, but it compares two strings in the string pool,
 
269
and it does not assume that they have the same length.
 
270
 
 
271
@c
 
272
boolean str_eq_str(str_number s, str_number t)
 
273
{                               /* test equality of strings */
 
274
    int a = 0;                  /* a utf char */
 
275
    unsigned char *j, *k, *l;   /* running indices */
 
276
    if (s < STRING_OFFSET) {
 
277
        if (t >= STRING_OFFSET) {
 
278
            k = str_string(t);
 
279
            if (s <= 0x7F && (str_length(t) == 1) && *k == s)
 
280
                return true;
 
281
            a = pool_to_unichar(k);
 
282
            if (a != s)
 
283
                return false;
 
284
        } else {
 
285
            if (t != s)
 
286
                return false;
 
287
        }
 
288
    } else if (t < STRING_OFFSET) {
 
289
        j = str_string(s);
 
290
        if (t <= 0x7F && (str_length(s) == 1) && *j == t)
 
291
            return true;
 
292
        a = pool_to_unichar(j);
 
293
        if (a != t)
 
294
            return false;
 
295
    } else {
 
296
        if (str_length(s) != str_length(t))
 
297
            return false;
 
298
        k = str_string(t);
 
299
        j = str_string(s);
 
300
        l = j + str_length(s);
 
301
        while (j < l) {
 
302
            if (*j++ != *k++)
 
303
                return false;
 
304
        }
 
305
    }
 
306
    return true;
 
307
}
 
308
 
 
309
@ string compare 
 
310
@c
 
311
boolean str_eq_cstr(str_number r, const char *s, size_t l)
 
312
{
 
313
    if (l != (size_t) str_length(r))
 
314
        return false;
 
315
    return (strncmp((const char *) (str_string(r)), s, l) == 0);
 
316
}
 
317
 
 
318
 
 
319
@ The initial values of |str_pool|, |str_start|, |pool_ptr|,
 
320
and |str_ptr| are computed by the \.{INITEX} program, based in part
 
321
on the information that \.{WEB} has output while processing \TeX.
 
322
 
 
323
The first |string_offset| strings are single-characters strings matching
 
324
Unicode. There is no point in generating all of these. But |str_ptr| has
 
325
initialized properly, otherwise |print_char| cannot see the difference
 
326
between characters and strings.
 
327
 
 
328
 
 
329
@ initializes the string pool, but returns |false| if something goes wrong 
 
330
@c
 
331
boolean get_strings_started(void)
 
332
{
 
333
    reset_cur_string();
 
334
    return true;
 
335
}
 
336
 
 
337
@ The string recycling routines.  \TeX{} uses 2
 
338
   upto 4 {\it new\/} strings when scanning a filename in an \.{\\input},
 
339
   \.{\\openin}, or \.{\\openout} operation.  These strings are normally
 
340
   lost because the reference to them are not saved after finishing the
 
341
   operation.  |search_string| searches through the string pool for the
 
342
   given string and returns either 0 or the found string number.
 
343
 
 
344
@c
 
345
str_number search_string(str_number search)
 
346
{
 
347
    str_number s;               /* running index */
 
348
    size_t len;                 /* length of searched string */
 
349
    len = str_length(search);
 
350
    if (len == 0) {
 
351
        return get_nullstr();
 
352
    } else {
 
353
        s = search - 1;         /* start search with newest string below |s|; |search>1|! */
 
354
        while (s >= STRING_OFFSET) {
 
355
            /* first |string_offset| strings depend on implementation!! */
 
356
            if (str_length(s) == len)
 
357
                if (str_eq_str(s, search))
 
358
                    return s;
 
359
            s--;
 
360
        }
 
361
    }
 
362
    return 0;
 
363
}
 
364
 
 
365
@ @c
 
366
str_number maketexstring(const char *s)
 
367
{
 
368
    if (s == NULL || *s == 0)
 
369
        return get_nullstr();
 
370
    return maketexlstring(s, strlen(s));
 
371
}
 
372
 
 
373
@ @c
 
374
str_number maketexlstring(const char *s, size_t l)
 
375
{
 
376
    if (s == NULL || l == 0)
 
377
        return get_nullstr();
 
378
    str_string(str_ptr) = xmalloc((unsigned) (l + 1));
 
379
    memcpy(str_string(str_ptr), s, (l + 1));
 
380
    str_length(str_ptr) = (unsigned) l;
 
381
    str_ptr++;
 
382
    return (str_ptr - 1);
 
383
}
 
384
 
 
385
@ append a C string to a TeX string
 
386
@c
 
387
void append_string(const unsigned char *s, unsigned l)
 
388
{
 
389
    if (s == NULL || *s == 0)
 
390
        return;
 
391
    l = (unsigned) strlen((const char *) s);
 
392
    str_room(l);
 
393
    memcpy(cur_string + cur_length, s, l);
 
394
    cur_length += l;
 
395
    return;
 
396
}
 
397
 
 
398
@ @c
 
399
char *makecstring(int s)
 
400
{
 
401
    size_t l;
 
402
    return makeclstring(s, &l);
 
403
}
 
404
 
 
405
@ @c
 
406
char *makeclstring(int s, size_t * len)
 
407
{
 
408
    if (s < STRING_OFFSET) {
 
409
        *len = (size_t) utf8_size(s);
 
410
        return (char *) uni2str((unsigned) s);
 
411
    } else {
 
412
        unsigned l = (unsigned) str_length(s);
 
413
        char *cstrbuf = xmalloc(l + 1);
 
414
        memcpy(cstrbuf, str_string(s), l);
 
415
        cstrbuf[l] = '\0';
 
416
        *len = (size_t) l;
 
417
        return cstrbuf;
 
418
    }
 
419
}
 
420
 
 
421
@ @c
 
422
int dump_string_pool(void)
 
423
{
 
424
    int j;
 
425
    int l;
 
426
    int k = str_ptr;
 
427
    dump_int(k - STRING_OFFSET);
 
428
    for (j = STRING_OFFSET + 1; j < k; j++) {
 
429
        l = (int) str_length(j);
 
430
        if (str_string(j) == NULL)
 
431
            l = -1;
 
432
        dump_int(l);
 
433
        if (l > 0)
 
434
            dump_things(*str_string(j), str_length(j));
 
435
    }
 
436
    return (k - STRING_OFFSET);
 
437
}
 
438
 
 
439
@ @c
 
440
int undump_string_pool(void)
 
441
{
 
442
    int j;
 
443
    int x;
 
444
    undump_int(str_ptr);
 
445
    if (max_strings < str_ptr + strings_free)
 
446
        max_strings = str_ptr + strings_free;
 
447
    str_ptr += STRING_OFFSET;
 
448
    if (ini_version)
 
449
        libcfree(string_pool);
 
450
    init_string_pool_array((unsigned) max_strings);
 
451
    for (j = STRING_OFFSET + 1; j < str_ptr; j++) {
 
452
        undump_int(x);
 
453
        if (x >= 0) {
 
454
            str_length(j) = (unsigned) x;
 
455
            pool_size += (unsigned) x;
 
456
            str_string(j) = xmallocarray(unsigned char, (unsigned) (x + 1));
 
457
            undump_things(*str_string(j), (unsigned) x);
 
458
            *(str_string(j) + str_length(j)) = '\0';
 
459
        } else {
 
460
            str_length(j) = 0;
 
461
        }
 
462
    }
 
463
    init_str_ptr = str_ptr;
 
464
    return str_ptr;
 
465
}
 
466
 
 
467
@ @c
 
468
void init_string_pool_array(unsigned s)
 
469
{
 
470
    string_pool = xmallocarray(lstring, s);
 
471
    _string_pool = string_pool - STRING_OFFSET;
 
472
    memset(string_pool, 0, s * sizeof(lstring));
 
473
    /* seed the null string */
 
474
    string_pool[0].s = xmalloc(1);
 
475
    string_pool[0].s[0] = '\0';
 
476
}
 
477
 
 
478
@ To destroy an already made string, we say |flush_str|. 
 
479
@c
 
480
void flush_str(str_number s)
 
481
{
 
482
#if 0   
 
483
    printf("Flushing a string: %s (s=%d,str_ptr=%d)\n", (char *)str_string(s), (int)s, (int)str_ptr); 
 
484
#endif
 
485
    if (s > STRING_OFFSET) {    /* don't ever delete the null string */
 
486
        pool_size -= (unsigned) str_length(s);
 
487
        str_length(s) = 0;
 
488
        xfree(str_string(s));
 
489
    }
 
490
    while (str_string((str_ptr - 1)) == NULL)
 
491
        str_ptr--;
 
492
}