cfad47cfa3/tads3/t3std.h

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* 
2
 *   Copyright (c) 1991, 2002 Michael J. Roberts.  All Rights Reserved.
3
 *   
4
 *   Please see the accompanying license file, LICENSE.TXT, for information
5
 *   on using and copying this software.  
6
 */
7
/*
8
Name
9
  t3std.h - standard definitions
10
Function
11
  Various standard definitions
12
Notes
13
  None
14
Modified
15
  10/17/98 MJRoberts  - creation (from TADS 2 lib.h)
16
*/
17
18
#ifndef T3_STD_INCLUDED
19
#define T3_STD_INCLUDED
20
21
#include <stddef.h>
22
#include <string.h>
23
#include <stdlib.h>
24
#include <stdarg.h>
25
#include <ctype.h>
26
27
#include "os.h"
28
29
30
/* short-hand for various types */
31
#ifndef OS_UCHAR_DEFINED
32
typedef unsigned char  uchar;
33
#endif
34
35
#ifndef OS_USHORT_DEFINED
36
typedef unsigned short ushort;
37
#endif
38
39
#ifndef OS_UINT_DEFINED
40
typedef unsigned int   uint;
41
#endif
42
43
#ifndef OS_ULONG_DEFINED
44
typedef unsigned long  ulong;
45
#endif
46
47
/* maximum/minimum portable values for various types */
48
#define ULONGMAXVAL   0xffffffffUL
49
#define USHORTMAXVAL  0xffffU
50
#define UCHARMAXVAL   0xffU
51
#define SLONGMAXVAL   0x7fffffffL
52
#define SSHORTMAXVAL  0x7fff
53
#define SCHARMAXVAL   0x7f
54
#define SLONGMINVAL   (-(0x7fffffff)-1)
55
#define SSHORTMINVAL  (-(0x7fff)-1)
56
#define SCHARMINVAL   (-(0x7f)-1)
57
58
59
/*
60
 *   Text character 
61
 */
62
typedef char textchar_t;
63
64
/*
65
 *   16-bit signed/unsigned integer types 
66
 */
67
#ifndef OS_INT16_DEFINED
68
typedef short int16;
69
#endif
70
#ifndef OS_UINT16_DEFINED
71
typedef unsigned short uint16;
72
#endif
73
74
/*
75
 *   32-bit signed/unsigned integer types 
76
 */
77
#ifndef OS_INT32_DEFINED
78
typedef long int32;
79
#endif
80
#ifndef OS_UINT32_DEFINED
81
typedef unsigned long uint32;
82
#endif
83
84
85
/* clear a struture */
86
#define CLRSTRUCT(x) memset(&(x), 0, (size_t)sizeof(x))
87
#define CPSTRUCT(dst,src) memcpy(&(dst), &(src), (size_t)sizeof(dst))
88
89
90
/* TRUE and FALSE */
91
#ifndef TRUE
92
# define TRUE 1
93
#endif /* TRUE */
94
#ifndef FALSE
95
# define FALSE 0
96
#endif /* FALSE */
97
98
99
/* bitwise operations */
100
#define bit(va, bt) ((va) & (bt))
101
#define bis(va, bt) ((va) |= (bt))
102
#define bic(va, bt) ((va) &= ~(bt))
103
104
105
/* conditionally compile code if debugging is enabled */
106
#ifdef DEBUG
107
# define IF_DEBUG(x) x
108
#else /* DEBUG */
109
# define IF_DEBUG(x)
110
#endif /* DEBUG */
111
112
/* offset within a structure of a member of the structure */
113
#ifndef offsetof
114
# define offsetof(s_name, m_name) (size_t)&(((s_name *)0)->m_name)
115
#endif /* offsetof */
116
117
118
/*
119
 *   Read an unsigned 32-bit value from the portable external-file
120
 *   representation.  This is parallel to osrp4(), but explicitly reads an
121
 *   unsigned value.  The important thing is that we mask the result to 32
122
 *   bits, to prevent unwarranted sign extension on architectures with word
123
 *   sizes greater than 32 bits (at the moment, this basically means 64-bit
124
 *   machines, but it would apply to any >32-bit architecture). 
125
 */
126
#define t3rp4u(p) ((ulong)(osrp4(p) & 0xFFFFFFFFU))
127
128
129
/* ------------------------------------------------------------------------ */
130
/*
131
 *   Allocate space for a null-terminated string and save a copy of the
132
 *   string 
133
 */
134
char *lib_copy_str(const char *str);
135
char *lib_copy_str(const char *str, size_t len);
136
137
/* 
138
 *   allocate space for a string of a given length; we'll add in space for
139
 *   a null terminator 
140
 */
141
char *lib_alloc_str(size_t len);
142
143
/*
144
 *   Free a string previously allocated with lib_copy_str() or
145
 *   lib_alloc_str() 
146
 */
147
void lib_free_str(char *buf);
148
149
/* ------------------------------------------------------------------------ */
150
/*
151
 *   Safe strcpy - checks the output buffer size and truncates the string if
152
 *   necessary; always null-terminates the result.  
153
 */
154
inline void lib_strcpy(char *dst, size_t dstsiz, const char *src)
155
{
156
    if (dstsiz > 0)
157
    {
158
        size_t copylen = strlen(src);
159
        if (copylen > dstsiz - 1)
160
            copylen = dstsiz - 1;
161
        memcpy(dst, src, copylen);
162
        dst[copylen] = '\0';
163
    }
164
}
165
166
/* ------------------------------------------------------------------------ */
167
/*
168
 *   Compare two strings, ignoring differences in whitespace between the
169
 *   strings.  Returns true if the strings are equal (other than
170
 *   whitespace, false if not.
171
 *   
172
 *   Note that we do not ignore the *presence* of whitespace; we only
173
 *   ignore differences in the amount of whitespace.  For example, "login"
174
 *   does not equal "log_in" (underscore = whitespace for these examples
175
 *   only, to emphasize the spacing), because the first lacks whitespace
176
 *   where the second has it; but "log_in" equals "log___in", because both
177
 *   strings have whitespace, albeit in different amounts, in the same
178
 *   place, and are otherwise the same.  
179
 */
180
int lib_strequal_collapse_spaces(const char *a, size_t a_len,
181
                                 const char *b, size_t b_len);
182
183
184
/* ------------------------------------------------------------------------ */
185
/*
186
 *   Find a version suffix in an identifier string.  A version suffix
187
 *   starts with the given character.  If we don't find the character,
188
 *   we'll return the default version suffix.  In any case, we'll set
189
 *   name_len to the length of the name portion, excluding the version
190
 *   suffix and its leading separator.
191
 *   
192
 *   For example, with a '/' suffix, a versioned name string would look
193
 *   like "tads-gen/030000" - the name is "tads_gen" and the version is
194
 *   "030000".  
195
 */
196
const char *lib_find_vsn_suffix(const char *name_string, char suffix_char,
197
                                const char *default_vsn, size_t *name_len);
198
199
200
/* ------------------------------------------------------------------------ */
201
/*
202
 *   Unicode-compatible character classification functions.  These
203
 *   functions accept any Unicode character, but classify all non-ASCII
204
 *   characters in the Unicode character set as unknown; hence,
205
 *   is_digit(ch) will always return false for any non-ASCII character,
206
 *   even if the character is considered a digit in the Unicode character
207
 *   set, and to_upper(ch) will return ch for any non-ASCII character,
208
 *   even if the character has a case conversion defined in the Unicode
209
 *   set.
210
 *   
211
 *   Use the t3_is_xxx() and t3_to_xxx() functions defined vmuni.h for
212
 *   classifications and conversions that operate over the entire Unicode
213
 *   character set.  
214
 */
215
216
/* determine if a character is an ASCII character */
217
inline int is_ascii(wchar_t c) { return (((unsigned int)c) <= 127); }
218
219
/* determine if a character is an ASCII space */
220
inline int is_space(wchar_t c) { return (is_ascii(c) && isspace((char)c)); }
221
222
/* determine if a character is an ASCII alphabetic character */
223
inline int is_alpha(wchar_t c) { return (is_ascii(c) && isalpha((char)c)); }
224
225
/* determine if a character is an ASCII numeric character */
226
inline int is_digit(wchar_t c) { return (is_ascii(c) && isdigit((char)c)); }
227
228
/* determine if a character is an ASCII octal numeric character */
229
inline int is_odigit(wchar_t c)
230
    { return (is_ascii(c) && isdigit((char)c) && c <= '7'); }
231
232
/* determine if a character is an ASCII hex numeric character */
233
inline int is_xdigit(wchar_t c)
234
{
235
    return (is_ascii(c)
236
            && (isdigit((char)c)
237
                || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')));
238
}
239
240
/* get the numeric value of a decimal digit character */
241
inline int value_of_digit(wchar_t c)
242
{
243
    return (int)(c - '0');
244
}
245
246
/* get the numeric value of an octal numeric character */
247
inline int value_of_odigit(wchar_t c)
248
{
249
    return (int)(c - '0');
250
}
251
252
/* get the numeric value of a hex numeric character */
253
inline int value_of_xdigit(wchar_t c)
254
{
255
    /* 
256
     *   since our internal characters are always in unicode, we can take
257
     *   advantage of the order of unicode characters to reduce the number
258
     *   of comparisons we must make here 
259
     */
260
    return (int)(c >= 'a'
261
                 ? c - 'a' + 10
262
                 : c >= 'A' ? c - 'A' + 10
263
                            : c - '0');
264
}
265
266
/* determine if a character is a symbol initial character */
267
inline int is_syminit(wchar_t c)
268
{
269
    /* underscores and alphabetic characters can start symbols */
270
    return (is_ascii(c) && (c == '_' || isalpha((char)c)));
271
}
272
273
/* determine if a character is a symbol non-initial character */
274
inline int is_sym(wchar_t c)
275
{
276
    /* underscores, alphabetics, and digits can be in symbols */
277
    return (is_ascii(c) && (c == '_' || isalpha((char)c)
278
                            || isdigit((char)c)));
279
}
280
281
/* determine if a character is ASCII lower-case */
282
inline int is_lower(wchar_t c) { return (is_ascii(c) && islower((char)c)); }
283
284
/* convert ASCII lower-case to upper-case */
285
inline wchar_t to_upper(wchar_t c)
286
{
287
    return (is_ascii(c) ? toupper((char)c) : c);
288
}
289
290
/* ------------------------------------------------------------------------ */
291
/*
292
 *   sprintf and vsprintf replacements.  These versions provide subsets of
293
 *   the full 'printf' format capabilities, but check for buffer overflow,
294
 *   which the standard library's sprintf functions do not.  
295
 */
296
void t3sprintf(char *buf, size_t buflen, const char *fmt, ...);
297
void t3vsprintf(char *buf, size_t buflen, const char *fmt, va_list args);
298
299
300
/* ------------------------------------------------------------------------ */
301
/*
302
 *   Basic heap allocation functions.  We don't call malloc and free
303
 *   directly, but use our own cover functions; when we compile the system
304
 *   for debugging, we use diagnostic memory allocators so that we can more
305
 *   easily find memory mismanagement errors (such as leaks, multiple
306
 *   deletes, and use after deletion).  
307
 */
308
309
#ifdef T3_DEBUG
310
311
/* 
312
 *   Compiling in debug mode - use our diagnostic heap functions.
313
 *   Override C++ operators new, new[], delete, and delete[] as well, so
314
 *   that we can handle those allocations through our diagnostic heap
315
 *   manager, too.  
316
 */
317
318
void *t3malloc(size_t siz);
319
void *t3realloc(void *oldptr, size_t siz);
320
void  t3free(void *ptr);
321
322
void *operator new(size_t siz);
323
void *operator new[](size_t siz);
324
void operator delete(void *ptr);
325
void operator delete[](void *ptr);
326
327
/*
328
 *   List all allocated memory blocks - displays heap information on stdout.
329
 *   This can be called at program termination to detect un-freed memory
330
 *   blocks, the existence of which could indicate a memory leak.
331
 *   
332
 *   If cb is provided, we'll display output through the given callback
333
 *   function; otherwise we'll display the output directly on stderr.  
334
 */
335
void t3_list_memory_blocks(void (*cb)(const char *msg));
336
337
#else /* T3_DEBUG */
338
339
/*
340
 *   Compiling in production mode - use the system memory allocators
341
 *   directly.  Note that we go through the osmalloc() et. al. functions
342
 *   rather than calling malloc() directly, so that individual ports can
343
 *   use customized memory management where necessary or desirable.  
344
 */
345
#define t3malloc(siz)          (::osmalloc(siz))
346
#define t3realloc(ptr, siz)    (::osrealloc(ptr, siz))
347
#define t3free(ptr)            (::osfree(ptr))
348
349
#define t3_list_memory_blocks(cb)
350
351
#endif /* T3_DEBUG */
352
353
354
/* ------------------------------------------------------------------------ */
355
/*
356
 *   A simple array list type.  We keep an underlying array of elements,
357
 *   automatically expanding the underlying array as needed to accomodate new
358
 *   elements.  
359
 */
360
361
/* array list element type codes */
362
#define ARRAY_LIST_ELE_INT   1
363
#define ARRAY_LIST_ELE_LONG  2
364
#define ARRAY_LIST_ELE_PTR   3
365
366
/* array list element - we can store various types here */
367
union array_list_ele_t
368
{
369
    array_list_ele_t(int i) { intval = i; }
370
    array_list_ele_t(long l) { longval = l; }
371
    array_list_ele_t(void *p) { ptrval = p; }
372
373
    int intval;
374
    long longval;
375
    void *ptrval;
376
377
    /* compare to a given value for equality */
378
    int equals(array_list_ele_t other, int typ)
379
    {
380
        return ((typ == ARRAY_LIST_ELE_INT && intval == other.intval)
381
                || (typ == ARRAY_LIST_ELE_LONG && longval == other.longval)
382
                || (typ == ARRAY_LIST_ELE_PTR && ptrval == other.ptrval));
383
    }
384
};
385
386
/*
387
 *   The array list type 
388
 */
389
class CArrayList
390
{
391
public:
392
    CArrayList()
393
    {
394
        /* we have nothing allocated yet */
395
        arr_ = 0;
396
        cnt_ = 0;
397
398
        /* use default initial size and increment */
399
        alloc_ = 16;
400
        inc_siz_ = 16;
401
    }
402
    CArrayList(size_t init_cnt, size_t inc_siz)
403
    {
404
        /* we have nothing allocated yet */
405
        arr_ = 0;
406
        cnt_ = 0;
407
408
        /* remember the initial size and increment */
409
        alloc_ = init_cnt;
410
        inc_siz_ = inc_siz;
411
    }
412
413
    virtual ~CArrayList()
414
    {
415
        /* delete our underlying array */
416
        free_mem(arr_);
417
    }
418
419
    /* get the number of elements in the array */
420
    size_t get_count() const { return cnt_; }
421
422
    /* get the element at the given index (no error checking) */
423
    int get_ele_int(size_t idx) const { return arr_[idx].intval; }
424
    long get_ele_long(size_t idx) const { return arr_[idx].longval; }
425
    void *get_ele_ptr(size_t idx) const { return arr_[idx].ptrval; }
426
427
    /* find an element's index; returns -1 if not found */
428
    int find_ele(int i) const
429
        { return find_ele(array_list_ele_t(i), ARRAY_LIST_ELE_INT); }
430
    int find_ele(long l) const
431
        { return find_ele(array_list_ele_t(l), ARRAY_LIST_ELE_LONG); }
432
    int find_ele(void *p) const
433
        { return find_ele(array_list_ele_t(p), ARRAY_LIST_ELE_PTR); }
434
435
    /* find an element's index; returns -1 if not found */
436
    int find_ele(array_list_ele_t ele, int typ) const
437
    {
438
        size_t i;
439
        array_list_ele_t *p;
440
441
        /* scan for the element */
442
        for (i = 0, p = arr_ ; i < cnt_ ; ++i, ++p)
443
        {
444
            /* if this is the element, return the index */
445
            if (p->equals(ele, typ))
446
                return (int)i;
447
        }
448
449
        /* didn't find it */
450
        return -1;
451
    }
452
453
    /* add a new element */
454
    void add_ele(int i) { add_ele(array_list_ele_t(i)); }
455
    void add_ele(long l) { add_ele(array_list_ele_t(l)); }
456
    void add_ele(void *p) { add_ele(array_list_ele_t(p)); }
457
458
    /* add a new element */
459
    void add_ele(array_list_ele_t ele)
460
    {
461
        /* expand the array if necessary */
462
        if (arr_ == 0)
463
        {
464
            /* we don't have an array yet, so allocate at the initial size */
465
            init();
466
        }
467
        if (cnt_ >= alloc_)
468
        {
469
            /* allocate at the new size */
470
            arr_ = (array_list_ele_t *)
471
                   realloc_mem(arr_, alloc_ * sizeof(arr_[0]),
472
                               (alloc_ + inc_siz_) * sizeof(arr_[0]));
473
474
            /* remember the new size */
475
            alloc_ += inc_siz_;
476
        }
477
478
        /* add the new element */
479
        arr_[cnt_++] = ele;
480
    }
481
482
    /* remove one element by value; returns true if found, false if not */
483
    void remove_ele(int i)
484
        { remove_ele(array_list_ele_t(i), ARRAY_LIST_ELE_INT); }
485
    void remove_ele(long l)
486
        { remove_ele(array_list_ele_t(l), ARRAY_LIST_ELE_LONG); }
487
    void remove_ele(void *p)
488
        { remove_ele(array_list_ele_t(p), ARRAY_LIST_ELE_PTR); }
489
490
    /* remove one element by value; returns true if found, false if not */
491
    int remove_ele(array_list_ele_t ele, int typ)
492
    {
493
        size_t i;
494
        array_list_ele_t *p;
495
496
        /* scan for the element */
497
        for (i = 0, p = arr_ ; i < cnt_ ; ++i, ++p)
498
        {
499
            /* if this is the element, remove it */
500
            if (p->equals(ele, typ))
501
            {
502
                /* remove the element at this index */
503
                remove_ele(i);
504
505
                /* indicate that we found the element */
506
                return TRUE;
507
            }
508
        }
509
510
        /* we didn't find the element */
511
        return FALSE;
512
    }
513
514
    /* remove the element at the given index */
515
    void remove_ele(size_t idx)
516
    {
517
        array_list_ele_t *p;
518
519
        /* move each following element down one slot */
520
        for (p = arr_ + idx, ++idx ; idx < cnt_ ; ++idx, ++p)
521
            *p = *(p + 1);
522
523
        /* reduce the in-use count */
524
        --cnt_;
525
    }
526
527
    /* clear the entire list */
528
    void clear() { cnt_ = 0; }
529
530
protected:
531
    /* 
532
     *   Initialize.  This is called to set up the array at the initial size,
533
     *   stored in alloc_, when we first need memory.  Note that we defer
534
     *   this until we actually need the memory for two reasons.  First, we
535
     *   can't call it from the constructor, because the vtable won't be
536
     *   built at construction, and we need to call the virtual alloc_mem().
537
     *   Second, by waiting, we ensure that we won't allocate any memory if
538
     *   our list is never actually needed.  
539
     */
540
    void init()
541
    {
542
        /* allocate the array */
543
        arr_ = (array_list_ele_t *)alloc_mem(alloc_ * sizeof(arr_[0]));
544
    }
545
546
    /* memory management */
547
    virtual void *alloc_mem(size_t siz)
548
        { return t3malloc(siz); }
549
    virtual void *realloc_mem(void *p, size_t oldsiz, size_t newsiz)
550
        { return t3realloc(p, newsiz); }
551
    virtual void free_mem(void *p)
552
        { t3free(p); }
553
554
    /* our array of elements */
555
    array_list_ele_t *arr_;
556
557
    /* number of elements allocated */
558
    size_t alloc_;
559
560
    /* number of elements currently in use */
561
    size_t cnt_;
562
563
    /* increment size */
564
    size_t inc_siz_;
565
};
566
567
#endif /* T3_STD_INCLUDED */
568