~ubuntu-branches/ubuntu/karmic/edbrowse/karmic-security

« back to all changes in this revision

Viewing changes to stringfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Kapil Hari Paranjape
  • Date: 2006-10-20 10:47:30 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061020104730-o7vxbrypwaz932dt
Tags: 3.1.2-1
* New upstream version (3.1.2). Closes: #306486.
  - programs now written in C
  - support for javascript.
* debian/control:
  - added Kapil Hari Paranjape to Uploaders.
  - Build-depends on "libssl-dev", "libmozjs-dev", "libpcre3-dev".
  - Standards-Version to 3.7.2. No changes required.
* debian/rules:
  - add "noopt" feature.
  - set CFLAGS and LIBS.
  - Put $(MAKE) into the build rules.
* debian/copyright: Edited to add the current copyright which
  is GPL with the exception for linking with OpenSSL.
* debian/docs: added "README".
* debian/examples: added "jsrt".

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* stringfile.c: manage strings, files, and directories for edbrowse.
 
2
* Copyright (c) Karl Dahlke, 2006
 
3
* This file is part of the edbrowse project, released under GPL.
 
4
 */
 
5
 
 
6
#include "eb.h"
 
7
 
 
8
#include <sys/stat.h>
 
9
#ifdef DOSLIKE
 
10
#include <dos.h>
 
11
#else
 
12
#include <dirent.h>
 
13
#ifdef SYSBSD
 
14
#include <termios.h>
 
15
typedef struct termios termstruct;
 
16
#define TTY_GET_COMMAND TIOCGETA
 
17
#define TTY_SET_COMMAND TIOCSETA
 
18
#else
 
19
#include <termio.h>
 
20
typedef struct termio termstruct;
 
21
#define TTY_GET_COMMAND TCGETA
 
22
#define TTY_SET_COMMAND TCSETA
 
23
#endif
 
24
#include <sys/utsname.h>
 
25
#endif
 
26
#include <pcre.h>
 
27
 
 
28
 
 
29
/*********************************************************************
 
30
Allocate and manage memory.
 
31
Allocate and copy strings.
 
32
If we're out of memory, the program aborts.  No error legs.
 
33
*********************************************************************/
 
34
 
 
35
void *
 
36
allocMem(unsigned n)
 
37
{
 
38
    void *s;
 
39
    if(!n)
 
40
        return EMPTYSTRING;
 
41
    if(!(s = malloc(n)))
 
42
        errorPrint("@error allocating %u bytes", n);
 
43
    return s;
 
44
}                               /* allocMem */
 
45
 
 
46
void *
 
47
allocZeroMem(unsigned n)
 
48
{
 
49
    void *s;
 
50
    if(!n)
 
51
        return EMPTYSTRING;
 
52
    if(!(s = calloc(n, 1)))
 
53
        errorPrint("@error callocating %u bytes", n);
 
54
    return s;
 
55
}                               /* allocZeroMem */
 
56
 
 
57
void *
 
58
reallocMem(void *p, unsigned n)
 
59
{
 
60
    void *s;
 
61
    if(!n)
 
62
        errorPrint("@reallocMem(p,0)");
 
63
    if(!p)
 
64
        errorPrint("@reallocMem(0,%d)", n);
 
65
    if(p == EMPTYSTRING)
 
66
        return allocMem(n);
 
67
    if(!(s = realloc(p, n)))
 
68
        errorPrint("@error re-allocating %u bytes", n);
 
69
    return s;
 
70
}                               /* reallocMem */
 
71
 
 
72
void
 
73
nzFree(void *s)
 
74
{
 
75
    if(s && s != EMPTYSTRING)
 
76
        free(s);
 
77
}                               /* nzFree */
 
78
 
 
79
uchar
 
80
fromHex(char d, char e)
 
81
{
 
82
    d |= 0x20, e |= 0x20;
 
83
    if(d >= 'a')
 
84
        d -= ('a' - '9' - 1);
 
85
    if(e >= 'a')
 
86
        e -= ('a' - '9' - 1);
 
87
    d -= '0', e -= '0';
 
88
    return ((((uchar) d) << 4) | (uchar) e);
 
89
}                               /* fromHex */
 
90
 
 
91
char *
 
92
appendString(char *s, const char *p)
 
93
{
 
94
    int slen = strlen(s);
 
95
    int plen = strlen(p);
 
96
    s = reallocMem(s, slen + plen + 1);
 
97
    strcpy(s + slen, p);
 
98
    return s;
 
99
}                               /* appendstring */
 
100
 
 
101
char *
 
102
prependString(char *s, const char *p)
 
103
{
 
104
    int slen = strlen(s);
 
105
    int plen = strlen(p);
 
106
    char *t = allocMem(slen + plen + 1);
 
107
    strcpy(t, p);
 
108
    strcpy(t + plen, s);
 
109
    nzFree(s);
 
110
    return t;
 
111
}                               /* prependstring */
 
112
 
 
113
void
 
114
skipWhite(const char **s)
 
115
{
 
116
    const char *t = *s;
 
117
    while(isspaceByte(*t))
 
118
        ++t;
 
119
    *s = t;
 
120
}                               /* skipWhite */
 
121
 
 
122
void
 
123
stripWhite(char *s)
 
124
{
 
125
    const char *t = s;
 
126
    char *u;
 
127
    skipWhite(&t);
 
128
    if(t > s)
 
129
        strcpy(s, t);
 
130
    u = s + strlen(s);
 
131
    while(u > s && isspaceByte(u[-1]))
 
132
        --u;
 
133
    *u = 0;
 
134
}                               /* stripWhite */
 
135
 
 
136
/* compress white space */
 
137
void
 
138
spaceCrunch(char *s, bool onespace, bool unprint)
 
139
{
 
140
    int i, j;
 
141
    char c;
 
142
    bool space = true;
 
143
    for(i = j = 0; c = s[i]; ++i) {
 
144
        if(isspaceByte(c)) {
 
145
            if(!onespace)
 
146
                continue;
 
147
            if(!space)
 
148
                s[j++] = ' ', space = true;
 
149
            continue;
 
150
        }
 
151
        if(unprint && !isprintByte(c))
 
152
            continue;
 
153
        s[j++] = c, space = false;
 
154
    }
 
155
    if(space && j)
 
156
        --j;                    /* drop trailing space */
 
157
    s[j] = 0;
 
158
}                               /* spaceCrunch */
 
159
 
 
160
/* OO has a lot of unnecessary overhead, and a few inconveniences,
 
161
 * but I really miss it right now.  The following
 
162
 * routines make up for the lack of simple string concatenation in C.
 
163
 * The string space allocated is always a power of 2 - 1, starting with 1.
 
164
 * Each of these routines puts an extra 0 on the end of the "string". */
 
165
 
 
166
char *
 
167
initString(int *l)
 
168
{
 
169
    *l = 0;
 
170
    return EMPTYSTRING;
 
171
}
 
172
 
 
173
void
 
174
stringAndString(char **s, int *l, const char *t)
 
175
{
 
176
    char *p = *s;
 
177
    int oldlen, newlen, x;
 
178
    oldlen = *l;
 
179
    newlen = oldlen + strlen(t);
 
180
    *l = newlen;
 
181
    ++newlen;                   /* room for the 0 */
 
182
    x = oldlen ^ newlen;
 
183
    if(x > oldlen) {            /* must realloc */
 
184
        newlen |= (newlen >> 1);
 
185
        newlen |= (newlen >> 2);
 
186
        newlen |= (newlen >> 4);
 
187
        newlen |= (newlen >> 8);
 
188
        newlen |= (newlen >> 16);
 
189
        p = reallocMem(p, newlen);
 
190
        *s = p;
 
191
    }
 
192
    strcpy(p + oldlen, t);
 
193
}                               /* stringAndString */
 
194
 
 
195
void
 
196
stringAndBytes(char **s, int *l, const char *t, int cnt)
 
197
{
 
198
    char *p = *s;
 
199
    int oldlen, newlen, x;
 
200
    oldlen = *l;
 
201
    newlen = oldlen + cnt;
 
202
    *l = newlen;
 
203
    ++newlen;
 
204
    x = oldlen ^ newlen;
 
205
    if(x > oldlen) {            /* must realloc */
 
206
        newlen |= (newlen >> 1);
 
207
        newlen |= (newlen >> 2);
 
208
        newlen |= (newlen >> 4);
 
209
        newlen |= (newlen >> 8);
 
210
        newlen |= (newlen >> 16);
 
211
        p = reallocMem(p, newlen);
 
212
        *s = p;
 
213
    }
 
214
    memcpy(p + oldlen, t, cnt);
 
215
    p[oldlen + cnt] = 0;
 
216
}                               /* stringAndBytes */
 
217
 
 
218
void
 
219
stringAndChar(char **s, int *l, char c)
 
220
{
 
221
    char *p = *s;
 
222
    int oldlen, newlen, x;
 
223
    oldlen = *l;
 
224
    newlen = oldlen + 1;
 
225
    *l = newlen;
 
226
    ++newlen;
 
227
    x = oldlen ^ newlen;
 
228
    if(x > oldlen) {            /* must realloc */
 
229
        newlen |= (newlen >> 1);
 
230
        newlen |= (newlen >> 2);
 
231
        newlen |= (newlen >> 4);
 
232
        newlen |= (newlen >> 8);
 
233
        newlen |= (newlen >> 16);
 
234
        p = reallocMem(p, newlen);
 
235
        *s = p;
 
236
    }
 
237
    p[oldlen] = c;
 
238
    p[oldlen + 1] = 0;
 
239
}                               /* stringAndChar */
 
240
 
 
241
void
 
242
stringAndNum(char **s, int *l, int n)
 
243
{
 
244
    char a[16];
 
245
    sprintf(a, "%d", n);
 
246
    stringAndString(s, l, a);
 
247
}                               /* stringAndNum */
 
248
 
 
249
/* 64M 16K etc */
 
250
void
 
251
stringAndKnum(char **s, int *l, int n)
 
252
{
 
253
    char a[16];
 
254
    if(n && n / (1024 * 1024) * (1024 * 1024) == n)
 
255
        sprintf(a, "%dM", n / (1024 * 1024));
 
256
    else if(n && n / 1024 * 1024 == n)
 
257
        sprintf(a, "%dK", n / 1024);
 
258
    else
 
259
        sprintf(a, "%d", n);
 
260
    stringAndString(s, l, a);
 
261
}                               /* stringAndKnum */
 
262
 
 
263
char *
 
264
cloneString(const char *s)
 
265
{
 
266
    char *t;
 
267
    unsigned len;
 
268
 
 
269
    if(!s)
 
270
        return 0;
 
271
    if(!*s)
 
272
        return EMPTYSTRING;
 
273
    len = strlen(s) + 1;
 
274
    t = allocMem(len);
 
275
    strcpy(t, s);
 
276
    return t;
 
277
}                               /* cloneString */
 
278
 
 
279
char *
 
280
cloneMemory(const char *s, int n)
 
281
{
 
282
    char *t = allocMem(n);
 
283
    if(n)
 
284
        memcpy(t, s, n);
 
285
    return t;
 
286
}                               /* cloneMemory */
 
287
 
 
288
char *
 
289
Cify(const char *s, int n)
 
290
{
 
291
    char *u;
 
292
    char *t = allocMem(n + 1);
 
293
    if(n)
 
294
        memcpy(t, s, n);
 
295
    for(u = t; u < t + n; ++u)
 
296
        if(*u == 0)
 
297
            *u = ' ';
 
298
    *u = 0;
 
299
    return t;
 
300
}                               /* Cify */
 
301
 
 
302
/* pull a substring out of a larger string,
 
303
 * and make it its own allocated string */
 
304
char *
 
305
pullString(const char *s, int l)
 
306
{
 
307
    char *t;
 
308
    if(!l)
 
309
        return EMPTYSTRING;
 
310
    t = allocMem(l + 1);
 
311
    memcpy(t, s, l);
 
312
    t[l] = 0;
 
313
    return t;
 
314
}                               /* pullString */
 
315
 
 
316
char *
 
317
pullString1(const char *s, const char *t)
 
318
{
 
319
    return pullString(s, t - s);
 
320
}
 
321
 
 
322
int
 
323
stringIsNum(const char *s)
 
324
{
 
325
    int n;
 
326
    if(!isdigitByte(s[0]))
 
327
        return -1;
 
328
    n = strtol(s, (char **)&s, 10);
 
329
    if(*s)
 
330
        return -1;
 
331
    return n;
 
332
}                               /* stringIsNum */
 
333
 
 
334
bool
 
335
stringIsFloat(const char *s, double *dp)
 
336
{
 
337
    const char *t;
 
338
    *dp = strtod(s, (char **)&t);
 
339
    if(*t)
 
340
        return false;           /* extra stuff at the end */
 
341
    return true;
 
342
}                               /* stringIsFloat */
 
343
 
 
344
bool
 
345
memEqualCI(const char *s, const char *t, int len)
 
346
{
 
347
    char c, d;
 
348
    while(len--) {
 
349
        c = *s, d = *t;
 
350
        if(islowerByte(c))
 
351
            c = toupper(c);
 
352
        if(islowerByte(d))
 
353
            d = toupper(d);
 
354
        if(c != d)
 
355
            return false;
 
356
        ++s, ++t;
 
357
    }
 
358
    return true;
 
359
}                               /* memEqualCI */
 
360
 
 
361
char *
 
362
strstrCI(const char *base, const char *search)
 
363
{
 
364
    int l = strlen(search);
 
365
    while(*base) {
 
366
        if(memEqualCI(base, search, l))
 
367
            return (char *)base;
 
368
        ++base;
 
369
    }
 
370
    return 0;
 
371
}                               /* strstrCI */
 
372
 
 
373
bool
 
374
stringEqualCI(const char *s, const char *t)
 
375
{
 
376
    char c, d;
 
377
    while((c = *s) && (d = *t)) {
 
378
        if(islowerByte(c))
 
379
            c = toupper(c);
 
380
        if(islowerByte(d))
 
381
            d = toupper(d);
 
382
        if(c != d)
 
383
            return false;
 
384
        ++s, ++t;
 
385
    }
 
386
    if(*s)
 
387
        return false;
 
388
    if(*t)
 
389
        return false;
 
390
    return true;
 
391
}                               /* stringEqualCI */
 
392
 
 
393
int
 
394
stringInList(const char *const *list, const char *s)
 
395
{
 
396
    int i = 0;
 
397
    if(!list)
 
398
        errorPrint("@stringInList(null,...)");
 
399
    if(s)
 
400
        while(*list) {
 
401
            if(stringEqual(s, *list))
 
402
                return i;
 
403
            ++i;
 
404
            ++list;
 
405
        }
 
406
    return -1;
 
407
}                               /* stringInList */
 
408
 
 
409
int
 
410
stringInListCI(const char *const *list, const char *s)
 
411
{
 
412
    int i = 0;
 
413
    if(!list)
 
414
        errorPrint("@stringInListCI(null,...)");
 
415
    if(s)
 
416
        while(*list) {
 
417
            if(stringEqualCI(s, *list))
 
418
                return i;
 
419
            ++i;
 
420
            ++list;
 
421
        }
 
422
    return -1;
 
423
}                               /* stringInListCI */
 
424
 
 
425
/* In an empty list, next and prev point back to the list, not to 0. */
 
426
/* We also allow zero. */
 
427
bool
 
428
listIsEmpty(const struct listHead * l)
 
429
{
 
430
    return l->next == l || l->next == 0;
 
431
}                               /* listIsEmpty */
 
432
 
 
433
void
 
434
initList(struct listHead *l)
 
435
{
 
436
    l->prev = l->next = l;
 
437
}                               /* initList */
 
438
 
 
439
void
 
440
delFromList(void *x)
 
441
{
 
442
    struct listHead *xh = x;
 
443
    ((struct listHead *)xh->next)->prev = xh->prev;
 
444
    ((struct listHead *)xh->prev)->next = xh->next;
 
445
}                               /* delFromList */
 
446
 
 
447
void
 
448
addToListFront(struct listHead *l, void *x)
 
449
{
 
450
    struct listHead *xh = x;
 
451
    xh->next = l->next;
 
452
    xh->prev = l;
 
453
    l->next = x;
 
454
    ((struct listHead *)xh->next)->prev = x;
 
455
}                               /* addToListFront */
 
456
 
 
457
void
 
458
addToListBack(struct listHead *l, void *x)
 
459
{
 
460
    struct listHead *xh = x;
 
461
    xh->prev = l->prev;
 
462
    xh->next = l;
 
463
    l->prev = x;
 
464
    ((struct listHead *)xh->prev)->next = x;
 
465
}                               /* addToListBack */
 
466
 
 
467
void
 
468
addAtPosition(void *p, void *x)
 
469
{
 
470
    struct listHead *xh = x;
 
471
    struct listHead *ph = p;
 
472
    xh->prev = p;
 
473
    xh->next = ph->next;
 
474
    ph->next = x;
 
475
    ((struct listHead *)xh->next)->prev = x;
 
476
}                               /* addAtPosition */
 
477
 
 
478
void
 
479
freeList(struct listHead *l)
 
480
{
 
481
    while(!listIsEmpty(l)) {
 
482
        void *p = l->next;
 
483
        delFromList(p);
 
484
        nzFree(p);
 
485
    }
 
486
}                               /* freeList */
 
487
 
 
488
/* like isalnumByte, but allows _ and - */
 
489
bool
 
490
isA(char c)
 
491
{
 
492
    if(isalnumByte(c))
 
493
        return true;
 
494
    return (c == '_' || c == '-');
 
495
}                               /* isA */
 
496
 
 
497
bool
 
498
isquote(char c)
 
499
{
 
500
    return c == '"' || c == '\'';
 
501
}                               /* isquote */
 
502
 
 
503
/* Gather at most 5 parameters from a vararg list
 
504
 * and place them in local variables.
 
505
 * Only take as many as indicated by the percents in a sprintf string.
 
506
 * If we blindly take more, we risk core dumps, at least on the Sun. */
 
507
 
 
508
void
 
509
varargLocals(va_list p, const char *msg, long *locals)
 
510
{
 
511
    const char *s = msg;
 
512
    int cnt;
 
513
 
 
514
    for(cnt = 0; cnt < 5; msg = s) {
 
515
        s = strchr(msg, '%');
 
516
        if(!s)
 
517
            break;
 
518
        ++s;
 
519
        if(*s == '%') {
 
520
            ++s;
 
521
            continue;
 
522
        }
 
523
        if(strchr("-.0123456789lhusdfxco", *s)) {
 
524
            long n = va_arg(p, long);
 
525
            locals[cnt++] = n;
 
526
        }
 
527
    }                           /* while finding percents in msg */
 
528
 
 
529
/* a little protection, in case they pass too few arguments */
 
530
    while(cnt < 5)
 
531
        locals[cnt++] = (long)"argmissing";
 
532
}                               /* varargLocals */
 
533
 
 
534
/* print an error message */
 
535
void
 
536
errorPrint(const char *msg, ...)
 
537
{
 
538
    char bailflag = 0;
 
539
    va_list p;
 
540
    long a[5];
 
541
    va_start(p, msg);
 
542
    varargLocals(p, msg, a);
 
543
    va_end(p);
 
544
 
 
545
    if(*msg == '@') {
 
546
        ++msg;
 
547
        bailflag = 1;
 
548
        fprintf(stderr, "disaster, ");
 
549
    } else if(isdigitByte(*msg)) {
 
550
        ++msg;
 
551
        bailflag = *msg - '0';
 
552
    }
 
553
 
 
554
    fprintf(stderr, msg, a[0], a[1], a[2], a[3], a[4]);
 
555
    fprintf(stderr, "\n");
 
556
 
 
557
    if(bailflag)
 
558
        exit(bailflag);
 
559
}                               /* errorPrint */
 
560
 
 
561
void
 
562
debugPrint(int lev, const char *msg, ...)
 
563
{
 
564
    va_list p;
 
565
    long a[5];
 
566
    if(lev > debugLevel)
 
567
        return;
 
568
    va_start(p, msg);
 
569
    varargLocals(p, msg, a);
 
570
    va_end(p);
 
571
    printf(msg, a[0], a[1], a[2], a[3], a[4]);
 
572
    printf("\n");
 
573
    if(lev == 0 && !memcmp(msg, "warning", 7))
 
574
        eeCheck();
 
575
}                               /* debugPrint */
 
576
 
 
577
char errorMsg[4000];
 
578
/* Show the error message, not just the question mark, after these commands. */
 
579
static const char showerror_cmd[] = "AbefMqrw^";
 
580
 
 
581
/* Set the error message.  Type h to see the message. */
 
582
void
 
583
setError(const char *msg, ...)
 
584
{
 
585
    va_list p;
 
586
    long a[5];
 
587
 
 
588
    if(!msg) {
 
589
        errorMsg[0] = 0;
 
590
        return;
 
591
    }
 
592
 
 
593
    va_start(p, msg);
 
594
    varargLocals(p, msg, a);
 
595
    va_end(p);
 
596
/* Yeah I know, there's a va_list sprintf call; this is old code. */
 
597
    sprintf(errorMsg, msg, a[0], a[1], a[2], a[3], a[4]);
 
598
 
 
599
/* sanity check */
 
600
    if(strlen(errorMsg) >= sizeof (errorMsg)) {
 
601
        printf("disaster, error message, length %d is too long\n",
 
602
           strlen(errorMsg));
 
603
        puts(errorMsg);
 
604
        exit(1);
 
605
    }
 
606
}                               /* setError */
 
607
 
 
608
void
 
609
showError(void)
 
610
{
 
611
    printf("%s\n", errorMsg[0] ? errorMsg : "no errors");
 
612
}                               /* showError */
 
613
 
 
614
void
 
615
showErrorConditional(char cmd)
 
616
{
 
617
    if(helpMessagesOn || strchr(showerror_cmd, cmd))
 
618
        showError();
 
619
    else
 
620
        printf("?\n");
 
621
}                               /* showErrorConditional */
 
622
 
 
623
void
 
624
showErrorAbort(void)
 
625
{
 
626
    errorPrint("1%s", errorMsg);
 
627
}                               /* showErrorAbort */
 
628
 
 
629
void
 
630
browseError(const char *msg, ...)
 
631
{
 
632
    va_list p;
 
633
    long a[5];
 
634
    if(ismc)
 
635
        return;
 
636
    if(browseLocal != 1)
 
637
        return;
 
638
    va_start(p, msg);
 
639
    varargLocals(p, msg, a);
 
640
    va_end(p);
 
641
    if(browseLine) {
 
642
        printf("line %d: ", browseLine);
 
643
        cw->labels[4] = browseLine;
 
644
    } else
 
645
        printf("browse error: ");
 
646
    printf(msg, a[0], a[1], a[2], a[3], a[4]);
 
647
    printf("\n");
 
648
    browseLocal = 2;
 
649
}                               /* browseError */
 
650
 
 
651
/* Javascript errors, we need to see these no matter what. */
 
652
void
 
653
runningError(const char *msg, ...)
 
654
{
 
655
    va_list p;
 
656
    long a[5];
 
657
    if(ismc)
 
658
        return;
 
659
    va_start(p, msg);
 
660
    varargLocals(p, msg, a);
 
661
    va_end(p);
 
662
    if(browseLine) {
 
663
        printf("line %d: ", browseLine);
 
664
        cw->labels[4] = browseLine;
 
665
    }
 
666
    printf(msg, a[0], a[1], a[2], a[3], a[4]);
 
667
    printf("\n");
 
668
    browseLocal = 2;
 
669
}                               /* runningError */
 
670
 
 
671
/* Turn perl string into C string, and complain about nulls. */
 
672
int
 
673
perl2c(char *t)
 
674
{
 
675
    int n = 0;
 
676
    while(*t != '\n') {
 
677
        if(*t == 0)
 
678
            ++n;
 
679
        ++t;
 
680
    }
 
681
    *t = 0;                     /* now it's a C string */
 
682
    return n;                   /* number of nulls */
 
683
}                               /* perl2c */
 
684
 
 
685
/* The length of a perl string includes its terminating newline */
 
686
unsigned
 
687
pstLength(pst s)
 
688
{
 
689
    pst t;
 
690
    if(!s)
 
691
        errorPrint("@null pointer in pstLength");
 
692
    t = s;
 
693
    while(*t != '\n')
 
694
        ++t;
 
695
    return t + 1 - s;
 
696
}                               /* pstLength */
 
697
 
 
698
pst
 
699
clonePstring(pst s)
 
700
{
 
701
    pst t;
 
702
    unsigned len;
 
703
    if(!s)
 
704
        return s;
 
705
    len = pstLength(s);
 
706
    t = allocMem(len);
 
707
    memcpy(t, s, len);
 
708
    return t;
 
709
}                               /* clonePstring */
 
710
 
 
711
void
 
712
copyPstring(pst s, const pst t)
 
713
{
 
714
    int len = pstLength(t);
 
715
    memcpy(s, t, len);
 
716
}                               /* copyPstring */
 
717
 
 
718
bool
 
719
fileIntoMemory(const char *filename, char **data, int *len)
 
720
{
 
721
    int length, n, fh;
 
722
    char *buf;
 
723
    char ftype = fileTypeByName(filename, false);
 
724
    if(ftype && ftype != 'f') {
 
725
        setError("%s is not a regular file", filename);
 
726
        return false;
 
727
    }
 
728
    fh = open(filename, O_RDONLY | O_BINARY);
 
729
    if(fh < 0) {
 
730
        setError("cannot open %s", filename);
 
731
        return false;
 
732
    }
 
733
    length = fileSizeByName(filename);
 
734
    if(length < 0) {
 
735
        close(fh);
 
736
        return false;
 
737
    }                           /* should never hapen */
 
738
    if(length > maxFileSize) {
 
739
        setError("file is too large, limit 40MB");
 
740
        close(fh);
 
741
        return false;
 
742
    }
 
743
    buf = allocMem(length + 2);
 
744
    n = 0;
 
745
    if(length)
 
746
        n = read(fh, buf, length);
 
747
    close(fh);                  /* don't need that any more */
 
748
    if(n < length) {
 
749
        setError("cannot read the contents of %s", filename);
 
750
        free(buf);
 
751
        return false;
 
752
    }
 
753
    *data = buf;
 
754
    *len = length;
 
755
    return true;
 
756
}                               /* fileIntoMemory */
 
757
 
 
758
/* shift string to upper, lower, or mixed case */
 
759
/* action is u, l, or m. */
 
760
void
 
761
caseShift(char *s, char action)
 
762
{
 
763
    char c;
 
764
    int mc = 0;
 
765
    bool ws = true;
 
766
 
 
767
    for(; c = *s; ++s) {
 
768
        if(action == 'u') {
 
769
            if(isalphaByte(c))
 
770
                *s = toupper(c);
 
771
            continue;
 
772
        }
 
773
        if(action == 'l') {
 
774
            if(isalphaByte(c))
 
775
                *s = tolower(c);
 
776
            continue;
 
777
        }
 
778
/* mixed case left */
 
779
        if(isalphaByte(c)) {
 
780
            if(ws)
 
781
                c = toupper(c);
 
782
            else
 
783
                c = tolower(c);
 
784
            if(ws && c == 'M')
 
785
                mc = 1;
 
786
            else if(mc == 1 && c == 'c')
 
787
                mc = 2;
 
788
            else if(mc == 2) {
 
789
                c = toupper(c);
 
790
                mc = 0;
 
791
            } else
 
792
                mc = 0;
 
793
            *s = c;
 
794
            ws = false;
 
795
            continue;
 
796
        }
 
797
        ws = true, mc = 0;
 
798
    }                           /* loop */
 
799
}                               /* caseShift */
 
800
 
 
801
 
 
802
/*********************************************************************
 
803
Manage files, directories, and terminal IO.
 
804
You'll see some conditional compilation when this program
 
805
is ported to other operating systems.
 
806
*********************************************************************/
 
807
 
 
808
/* Return the type of a file.
 
809
 * Make it a capital letter if you are going through a link.
 
810
 * I think this will work on Windows, not sure.
 
811
 * But the link feature is Unix specific. */
 
812
 
 
813
char
 
814
fileTypeByName(const char *name, bool showlink)
 
815
{
 
816
    struct stat buf;
 
817
    bool islink = false;
 
818
    char c;
 
819
    int mode;
 
820
    if(lstat(name, &buf)) {
 
821
        setError("cannot access %s", name);
 
822
        return 0;
 
823
    }
 
824
    mode = buf.st_mode & S_IFMT;
 
825
    if(mode == S_IFLNK) {       /* symbolic link */
 
826
        islink = true;
 
827
/* If this fails, I'm guessing it's just a file. */
 
828
        if(stat(name, &buf))
 
829
            return (showlink ? 'F' : 0);
 
830
        mode = buf.st_mode & S_IFMT;
 
831
    }
 
832
    c = 'f';
 
833
    if(mode == S_IFDIR)
 
834
        c = 'd';
 
835
#ifndef DOSLIKE
 
836
/* I don't think these are Windows constructs. */
 
837
    if(mode == S_IFBLK)
 
838
        c = 'b';
 
839
    if(mode == S_IFCHR)
 
840
        c = 'c';
 
841
    if(mode == S_IFIFO)
 
842
        c = 'p';
 
843
    if(mode == S_IFSOCK)
 
844
        c = 's';
 
845
#endif
 
846
    if(islink & showlink)
 
847
        c = toupper(c);
 
848
    return c;
 
849
}                               /* fileTypeByName */
 
850
 
 
851
int
 
852
fileSizeByName(const char *name)
 
853
{
 
854
    struct stat buf;
 
855
    if(stat(name, &buf)) {
 
856
        setError("cannot access %s", name);
 
857
        return -1;
 
858
    }
 
859
    return buf.st_size;
 
860
}                               /* fileSizeByName */
 
861
 
 
862
time_t
 
863
fileTimeByName(const char *name)
 
864
{
 
865
    struct stat buf;
 
866
    if(stat(name, &buf)) {
 
867
        setError("cannot access %s", name);
 
868
        return -1;
 
869
    }
 
870
    return buf.st_mtime;
 
871
}                               /* fileSizeByName */
 
872
 
 
873
#ifndef DOSLIKE
 
874
 
 
875
static termstruct savettybuf;
 
876
void
 
877
ttySaveSettings(void)
 
878
{
 
879
    isInteractive = isatty(0);
 
880
    if(isInteractive) {
 
881
        if(ioctl(0, TTY_GET_COMMAND, &savettybuf))
 
882
            errorPrint("@canot use ioctl() to manage the tty");
 
883
    }
 
884
}                               /* ttySaveSettings */
 
885
 
 
886
static void
 
887
ttyRestoreSettings(void)
 
888
{
 
889
    if(isInteractive)
 
890
        ioctl(0, TTY_SET_COMMAND, &savettybuf);
 
891
}                               /* ttyRestoreSettings */
 
892
 
 
893
/* put the tty in raw mode.
 
894
 * Review your Unix manual on termio.
 
895
 * min>0 time>0:  return min chars, or as many as you have received
 
896
 *   when time/10 seconds have elapsed between characters.
 
897
 * min>0 time=0:  block until min chars are received.
 
898
 * min=0 time>0:  return 1 char, or 0 if the timer expires.
 
899
 * min=0 time=0:  nonblocking, return whatever chars have been received. */
 
900
static void
 
901
ttyRaw(int charcount, int timeout, bool isecho)
 
902
{
 
903
    termstruct buf = savettybuf;        /* structure copy */
 
904
    buf.c_cc[VMIN] = charcount;
 
905
    buf.c_cc[VTIME] = timeout;
 
906
    buf.c_lflag &= ~(ICANON | ECHO);
 
907
    if(isecho)
 
908
        buf.c_lflag |= ECHO;
 
909
    ioctl(0, TTY_SET_COMMAND, &buf);
 
910
}                               /* ttyRaw */
 
911
 
 
912
/* simulate MSDOS getche() system call */
 
913
int
 
914
getche(void)
 
915
{
 
916
    char c;
 
917
    fflush(stdout);
 
918
    ttyRaw(1, 0, true);
 
919
    read(0, &c, 1);
 
920
    ttyRestoreSettings();
 
921
    return c;
 
922
}                               /* getche */
 
923
 
 
924
int
 
925
getch(void)
 
926
{
 
927
    char c;
 
928
    fflush(stdout);
 
929
    ttyRaw(1, 0, false);
 
930
    read(0, &c, 1);
 
931
    ttyRestoreSettings();
 
932
    return c;
 
933
}                               /* getche */
 
934
 
 
935
#endif
 
936
 
 
937
char
 
938
getLetter(const char *s)
 
939
{
 
940
    char c;
 
941
    while(true) {
 
942
        c = getch();
 
943
        if(strchr(s, c))
 
944
            break;
 
945
        printf("\a\b");
 
946
        fflush(stdout);
 
947
    }
 
948
    printf("%c", c);
 
949
    return c;
 
950
}                               /* getLetter */
 
951
 
 
952
/* loop through the files in a directory */
 
953
/* Hides the differences between DOS, Unix, and NT. */
 
954
static bool dirstart = true;
 
955
 
 
956
char *
 
957
nextScanFile(const char *base)
 
958
{
 
959
    char *s;
 
960
#ifdef DOSLIKE
 
961
    static char global[] = "/*.*";
 
962
    bool rc;
 
963
    short len;
 
964
    char *p;
 
965
    bool allocate = false;
 
966
#ifdef MSDOS
 
967
    static struct _find_t dta;
 
968
#else
 
969
    static struct _finddata_t dta;
 
970
    static int handle;
 
971
#endif
 
972
#else
 
973
    struct dirent *de;
 
974
    static DIR *df;
 
975
#endif
 
976
 
 
977
#ifdef DOSLIKE
 
978
    if(dirstart) {
 
979
        if(base) {
 
980
            len = strlen(base) - 1;
 
981
            p = allocMem(len + 6);
 
982
            strcpy(p, base);
 
983
            allocate = true;
 
984
            if(p[len] == '/' || p[len] == '\\')
 
985
                p[len] = 0;
 
986
            strcat(p, global);
 
987
        } else
 
988
            p = global +1;
 
989
#ifdef MSDOS
 
990
        rc = _dos_findfirst(p, (showHiddenFiles ? 077 : 073), &dta);
 
991
#else
 
992
        rc = false;
 
993
        handle = _findfirst(p, &dta);
 
994
        if(handle < 0)
 
995
            rc = true;
 
996
#endif
 
997
        if(allocate)
 
998
            nzFree(p);
 
999
    }
 
1000
#else
 
1001
    if(!df) {
 
1002
        if(!base)
 
1003
            base = ".";
 
1004
        df = opendir(base);
 
1005
        if(!df) {
 
1006
            puts
 
1007
               ("warning, the directory is inaccessible - the listing will be empty");
 
1008
            return 0;
 
1009
        }
 
1010
    }
 
1011
#endif
 
1012
 
 
1013
#ifdef DOSLIKE
 
1014
    while(true) {
 
1015
/* read the next file */
 
1016
        if(!dirStart) {
 
1017
#ifdef MSDOS
 
1018
            rc = _dos_findnext(&dta);
 
1019
#else
 
1020
            rc = _findnext(handle, &dta);
 
1021
#endif
 
1022
            dirstart = false;
 
1023
        }
 
1024
        if(rc)
 
1025
            break;
 
1026
/* extract the base name */
 
1027
        s = strrchr(dta.name, '/');
 
1028
        s = s ? s + 1 : dta.name;
 
1029
/* weed out unwanted directories */
 
1030
        if(stringEqual(s, "."))
 
1031
            continue;
 
1032
        if(stringEqual(s, ".."))
 
1033
            continue;
 
1034
        return s;
 
1035
    }                           /* end loop over files in directory */
 
1036
#else
 
1037
    while(de = readdir(df)) {
 
1038
        if(de->d_ino == 0)
 
1039
            continue;
 
1040
        if(de->d_name[0] == '.') {
 
1041
            if(!showHiddenFiles)
 
1042
                continue;
 
1043
            if(de->d_name[1] == 0)
 
1044
                continue;
 
1045
            if(de->d_name[1] == '.' && de->d_name[2] == 0)
 
1046
                continue;
 
1047
        }
 
1048
        return de->d_name;
 
1049
    }                           /* end loop over files in directory */
 
1050
    closedir(df);
 
1051
    df = 0;
 
1052
#endif
 
1053
 
 
1054
    return 0;
 
1055
}                               /* nextScanFile */
 
1056
 
 
1057
/* Sorted directory list.  Uses textLines[]. */
 
1058
bool
 
1059
sortedDirList(const char *dir, int *start, int *end)
 
1060
{
 
1061
    char *f;
 
1062
    int j;
 
1063
    bool change;
 
1064
 
 
1065
    *start = *end = textLinesCount;
 
1066
 
 
1067
    while(f = nextScanFile(dir)) {
 
1068
        if(!linesComing(1))
 
1069
            return false;
 
1070
        textLines[textLinesCount] = allocMem(strlen(f) + 3);
 
1071
        strcpy((char *)textLines[textLinesCount], f);
 
1072
        textLinesCount++;
 
1073
    }
 
1074
 
 
1075
    *end = textLinesCount;
 
1076
    if(*end == *start)
 
1077
        return true;
 
1078
 
 
1079
/* Bubble sort, the list shouldn't be too long. */
 
1080
    change = true;
 
1081
    while(change) {
 
1082
        change = false;
 
1083
        for(j = *start; j < *end - 1; ++j) {
 
1084
            if(strcmp((char *)textLines[j], (char *)textLines[j + 1]) > 0) {
 
1085
                pst swap = textLines[j];
 
1086
                textLines[j] = textLines[j + 1];
 
1087
                textLines[j + 1] = swap;
 
1088
                change = true;
 
1089
            }
 
1090
        }
 
1091
    }
 
1092
 
 
1093
    return true;
 
1094
}                               /* sortedDirList */
 
1095
 
 
1096
/* Expand environment variables, then wild cards.
 
1097
 * But the result should be one and only one file.
 
1098
 * Return the new expanded line.
 
1099
 * Neither the original line nore the new line is allocated.
 
1100
 * They are static char buffers that are just plain long enough. */
 
1101
 
 
1102
bool
 
1103
envFile(const char *line, const char **expanded)
 
1104
{
 
1105
    static char line1[MAXTTYLINE];
 
1106
    static char line2[MAXTTYLINE];
 
1107
    const char *s, *value, *basedir;
 
1108
    char *t, *dollar, *cut, *file;
 
1109
    char c;
 
1110
    bool cc, badBrackets;
 
1111
    int filecount;
 
1112
    char re[MAXRE + 20];
 
1113
    const char *re_error;
 
1114
    int re_offset, re_count, re_vector[3];
 
1115
 
 
1116
    pcre *re_cc;
 
1117
 
 
1118
/* ` supresses this stuff */
 
1119
    if(*line == '`') {
 
1120
        *expanded = line + 1;
 
1121
        return true;
 
1122
    }
 
1123
 
 
1124
/* quick check, nothing to do */
 
1125
    if(!strpbrk(line, "$[*?") && line[0] != '~') {
 
1126
        *expanded = line;
 
1127
        return true;
 
1128
    }
 
1129
 
 
1130
/* first the env variables */
 
1131
    s = line;
 
1132
    t = line1;
 
1133
    dollar = 0;
 
1134
    while(true) {
 
1135
        if(t >= line1 + sizeof (line1))
 
1136
            goto longvar;
 
1137
        c = *s;
 
1138
        if(c == '~' && s == line && (s[1] == '/' || s[1] == 0)) {
 
1139
            if(strlen(home) >= sizeof (line1) - 1)
 
1140
                goto longvar;
 
1141
            strcpy(t, home);
 
1142
            t = t + strlen(t);
 
1143
            ++s;
 
1144
            continue;
 
1145
        }
 
1146
        if(dollar && !isalnumByte(c) && c != '_') {
 
1147
            *t = 0;
 
1148
            value = getenv(dollar + 1);
 
1149
            if(!value) {
 
1150
                setError("environement variable %s not set", dollar + 1);
 
1151
                return false;
 
1152
            }
 
1153
            if(dollar + strlen(value) >= line1 + sizeof (line1) - 1)
 
1154
                goto longvar;
 
1155
            strcpy(dollar, value);
 
1156
            t = dollar + strlen(dollar);
 
1157
            dollar = 0;
 
1158
        }
 
1159
        if(c == '$' && (s[1] == '_' || isalphaByte(s[1])))
 
1160
            dollar = t;
 
1161
        *t++ = c;
 
1162
        if(!c)
 
1163
            break;
 
1164
        ++s;
 
1165
    }
 
1166
 
 
1167
/* Wildcard expansion, but somewhat limited.
 
1168
 * The directory has to be hard coded;
 
1169
 * we only expand stars in the filename. */
 
1170
 
 
1171
    cut = dollar = 0;
 
1172
    for(t = line1; *t; ++t) {
 
1173
        c = *t;
 
1174
        if(c == '/')
 
1175
            cut = t;
 
1176
        if(c == '[' || c == '*' || c == '?')
 
1177
            dollar = t;
 
1178
    }
 
1179
    if(!dollar) {               /* nothing meta */
 
1180
        *expanded = line1;
 
1181
        return true;
 
1182
    }
 
1183
    if(cut && dollar < cut) {
 
1184
        setError("cannot expand * ? or [] prior to the last /");
 
1185
        return false;
 
1186
    }
 
1187
 
 
1188
/* Make sure its a directory, and build a perl regexp for the pattern. */
 
1189
    if(cut) {
 
1190
        *cut = 0;
 
1191
        if(cut > line1 && fileTypeByName(line1, false) != 'd') {
 
1192
            setError("%s is not an accessible directory", line1);
 
1193
            return false;
 
1194
        }
 
1195
    }
 
1196
 
 
1197
    s = cut ? cut + 1 : line1;
 
1198
    t = re;
 
1199
    *t++ = '^';
 
1200
    cc = badBrackets = false;
 
1201
    while(c = *s) {
 
1202
        if(t >= re + sizeof (re) - 3) {
 
1203
            setError("shell pattern is too long");
 
1204
            return false;
 
1205
        }
 
1206
        if(c == '\\') {
 
1207
            setError
 
1208
               ("sorry, I don't know how to expand filenames with \\ in them");
 
1209
            return false;
 
1210
        }
 
1211
/* things we need to escape */
 
1212
        if(strchr("().+|", c))
 
1213
            *t++ = '\\';
 
1214
        if(c == '?')
 
1215
            c = '.';
 
1216
        if(c == '*')
 
1217
            *t++ = '.';
 
1218
        *t++ = c;
 
1219
        if(c == '[') {
 
1220
            if(cc)
 
1221
                badBrackets = true;
 
1222
            cc = true;
 
1223
        }
 
1224
        if(c == ']') {
 
1225
            if(!cc)
 
1226
                badBrackets = true;
 
1227
            cc = false;
 
1228
        }
 
1229
        ++s;
 
1230
    }                           /* loop over shell pattern */
 
1231
    *t++ = '$';
 
1232
    *t = 0;
 
1233
    if(badBrackets | cc) {
 
1234
        setError("improperly formed [] pattern");
 
1235
        return false;
 
1236
    }
 
1237
 
 
1238
    debugPrint(7, "shell regexp %s", re);
 
1239
    re_cc = pcre_compile(re, 0, &re_error, &re_offset, 0);
 
1240
    if(!re_cc) {
 
1241
        setError("error compiling the shell pattern, %s", re_error);
 
1242
        return false;
 
1243
    }
 
1244
 
 
1245
    filecount = 0;
 
1246
    cc = false;                 /* long flag */
 
1247
    basedir = 0;
 
1248
    if(cut) {
 
1249
        if(cut == line1)
 
1250
            basedir = "/";
 
1251
        else
 
1252
            basedir = line1;
 
1253
    }
 
1254
    while(file = nextScanFile(basedir)) {
 
1255
        if(filecount > 1)
 
1256
            continue;
 
1257
        re_count = pcre_exec(re_cc, 0, file, strlen(file), 0, 0, re_vector, 3);
 
1258
        if(re_count < -1) {
 
1259
            pcre_free(re_cc);
 
1260
            setError("unexpected error while evaluating the shell pattern");
 
1261
            return false;
 
1262
        }
 
1263
        if(re_count < 0)
 
1264
            continue;
 
1265
        ++filecount;
 
1266
        if(filecount > 1)
 
1267
            continue;
 
1268
        if((cut ? strlen(line1) : 0) + strlen(file) >= sizeof (line2) - 2)
 
1269
            cc = true;
 
1270
        else if(cut)
 
1271
            sprintf(line2, "%s/%s", line1, file);
 
1272
        else
 
1273
            strcpy(line2, file);
 
1274
    }
 
1275
    pcre_free(re_cc);
 
1276
    if(filecount != 1) {
 
1277
        setError(filecount ? "shell pattern matches more than one file" :
 
1278
           "shell pattern does not match any files");
 
1279
        return false;
 
1280
    }
 
1281
    if(cc)
 
1282
        goto longvar;
 
1283
 
 
1284
    *expanded = line2;
 
1285
    return true;
 
1286
 
 
1287
  longvar:
 
1288
    setError("line becomes too long when shell variables are expanded");
 
1289
    return false;
 
1290
}                               /* envFile */
 
1291
 
 
1292
static struct utsname utsbuf;
 
1293
 
 
1294
const char *
 
1295
currentOS(void)
 
1296
{
 
1297
    uname(&utsbuf);
 
1298
    return utsbuf.sysname;
 
1299
}                               /* currentOS */
 
1300
 
 
1301
const char *
 
1302
currentMachine(void)
 
1303
{
 
1304
    uname(&utsbuf);
 
1305
    return utsbuf.machine;
 
1306
}                               /* currentMachine */