1 /* Copyright (c) 1998, 1999, 2001, 2002 John E. Davis
2 * This file is part of the S-Lang library.
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Perl Artistic License.
6 */
7 #include "slinclud.h"
8
9 #include "slang.h"
10 #include "_slang.h"
11
12 struct _SLang_BString_Type
13 {
14 unsigned int num_refs;
15 unsigned int len;
16 int ptr_type;
17 #define IS_SLSTRING 1
18 #define IS_MALLOCED 2
19 #define IS_NOT_TO_BE_FREED 3
20 union
21 {
22 unsigned char bytes[1];
23 unsigned char *ptr;
24 }
25 v;
26 };
27
28 #define BS_GET_POINTER(b) ((b)->ptr_type ? (b)->v.ptr : (b)->v.bytes)
29
create_bstring_of_type(char * bytes,unsigned int len,int type)30 static SLang_BString_Type *create_bstring_of_type (char *bytes, unsigned int len, int type)
31 {
32 SLang_BString_Type *b;
33 unsigned int size;
34
35 size = sizeof(SLang_BString_Type);
36 if (type == 0)
37 size += len;
38
39 if (NULL == (b = (SLang_BString_Type *)SLmalloc (size)))
40 return NULL;
41
42 b->len = len;
43 b->num_refs = 1;
44 b->ptr_type = type;
45
46 switch (type)
47 {
48 case 0:
49 if (bytes != NULL) memcpy ((char *) b->v.bytes, bytes, len);
50 /* Now \0 terminate it because we want to also use it as a C string
51 * whenever possible. Note that sizeof(SLang_BString_Type) includes
52 * space for 1 character and we allocated len extra bytes. Thus, it is
53 * ok to add a \0 to the end.
54 */
55 b->v.bytes[len] = 0;
56 break;
57
58 case IS_SLSTRING:
59 if (NULL == (b->v.ptr = (unsigned char *)SLang_create_nslstring (bytes, len)))
60 {
61 SLfree ((char *) b);
62 return NULL;
63 }
64 break;
65
66 case IS_MALLOCED:
67 case IS_NOT_TO_BE_FREED:
68 b->v.ptr = (unsigned char *)bytes;
69 bytes [len] = 0; /* NULL terminate */
70 break;
71 }
72
73 return b;
74 }
75
76 SLang_BString_Type *
SLbstring_create(unsigned char * bytes,unsigned int len)77 SLbstring_create (unsigned char *bytes, unsigned int len)
78 {
79 return create_bstring_of_type ((char *)bytes, len, 0);
80 }
81
82 /* Note that ptr must be len + 1 bytes long for \0 termination */
83 SLang_BString_Type *
SLbstring_create_malloced(unsigned char * ptr,unsigned int len,int free_on_error)84 SLbstring_create_malloced (unsigned char *ptr, unsigned int len, int free_on_error)
85 {
86 SLang_BString_Type *b;
87
88 if (ptr == NULL)
89 return NULL;
90
91 if (NULL == (b = create_bstring_of_type ((char *)ptr, len, IS_MALLOCED)))
92 {
93 if (free_on_error)
94 SLfree ((char *) ptr);
95 }
96 return b;
97 }
98
SLbstring_create_slstring(char * s)99 SLang_BString_Type *SLbstring_create_slstring (char *s)
100 {
101 if (s == NULL)
102 return NULL;
103
104 return create_bstring_of_type (s, strlen (s), IS_SLSTRING);
105 }
106
SLbstring_dup(SLang_BString_Type * b)107 SLang_BString_Type *SLbstring_dup (SLang_BString_Type *b)
108 {
109 if (b != NULL)
110 b->num_refs += 1;
111
112 return b;
113 }
114
SLbstring_get_pointer(SLang_BString_Type * b,unsigned int * len)115 unsigned char *SLbstring_get_pointer (SLang_BString_Type *b, unsigned int *len)
116 {
117 if (b == NULL)
118 {
119 *len = 0;
120 return NULL;
121 }
122 *len = b->len;
123 return BS_GET_POINTER(b);
124 }
125
SLbstring_free(SLang_BString_Type * b)126 void SLbstring_free (SLang_BString_Type *b)
127 {
128 if (b == NULL)
129 return;
130
131 if (b->num_refs > 1)
132 {
133 b->num_refs -= 1;
134 return;
135 }
136
137 switch (b->ptr_type)
138 {
139 case 0:
140 case IS_NOT_TO_BE_FREED:
141 default:
142 break;
143
144 case IS_SLSTRING:
145 SLang_free_slstring ((char *)b->v.ptr);
146 break;
147
148 case IS_MALLOCED:
149 SLfree ((char *)b->v.ptr);
150 break;
151 }
152
153 SLfree ((char *) b);
154 }
155
SLang_pop_bstring(SLang_BString_Type ** b)156 int SLang_pop_bstring (SLang_BString_Type **b)
157 {
158 return SLclass_pop_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR *)b);
159 }
160
SLang_push_bstring(SLang_BString_Type * b)161 int SLang_push_bstring (SLang_BString_Type *b)
162 {
163 if (b == NULL)
164 return SLang_push_null ();
165
166 b->num_refs += 1;
167
168 if (0 == SLclass_push_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR)b))
169 return 0;
170
171 b->num_refs -= 1;
172 return -1;
173 }
174
175 static int
bstring_bstring_bin_op_result(int op,unsigned char a,unsigned char b,unsigned char * c)176 bstring_bstring_bin_op_result (int op, unsigned char a, unsigned char b,
177 unsigned char *c)
178 {
179 (void) a;
180 (void) b;
181 switch (op)
182 {
183 default:
184 return 0;
185
186 case SLANG_PLUS:
187 *c = SLANG_BSTRING_TYPE;
188 break;
189
190 case SLANG_GT:
191 case SLANG_GE:
192 case SLANG_LT:
193 case SLANG_LE:
194 case SLANG_EQ:
195 case SLANG_NE:
196 *c = SLANG_CHAR_TYPE;
197 break;
198 }
199 return 1;
200 }
201
compare_bstrings(SLang_BString_Type * a,SLang_BString_Type * b)202 static int compare_bstrings (SLang_BString_Type *a, SLang_BString_Type *b)
203 {
204 unsigned int len;
205 int ret;
206
207 len = a->len;
208 if (b->len < len) len = b->len;
209
210 ret = memcmp ((char *)BS_GET_POINTER(b), (char *)BS_GET_POINTER(a), len);
211 if (ret != 0)
212 return ret;
213
214 if (a->len > b->len)
215 return 1;
216 if (a->len == b->len)
217 return 0;
218
219 return -1;
220 }
221
222 static SLang_BString_Type *
concat_bstrings(SLang_BString_Type * a,SLang_BString_Type * b)223 concat_bstrings (SLang_BString_Type *a, SLang_BString_Type *b)
224 {
225 unsigned int len;
226 SLang_BString_Type *c;
227 char *bytes;
228
229 len = a->len + b->len;
230
231 if (NULL == (c = SLbstring_create (NULL, len)))
232 return NULL;
233
234 bytes = (char *)BS_GET_POINTER(c);
235
236 memcpy (bytes, (char *)BS_GET_POINTER(a), a->len);
237 memcpy (bytes + a->len, (char *)BS_GET_POINTER(b), b->len);
238
239 return c;
240 }
241
free_n_bstrings(SLang_BString_Type ** a,unsigned int n)242 static void free_n_bstrings (SLang_BString_Type **a, unsigned int n)
243 {
244 unsigned int i;
245
246 if (a == NULL) return;
247
248 for (i = 0; i < n; i++)
249 {
250 SLbstring_free (a[i]);
251 a[i] = NULL;
252 }
253 }
254
255 static int
bstring_bstring_bin_op(int op,unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp,unsigned int nb,VOID_STAR cp)256 bstring_bstring_bin_op (int op,
257 unsigned char a_type, VOID_STAR ap, unsigned int na,
258 unsigned char b_type, VOID_STAR bp, unsigned int nb,
259 VOID_STAR cp)
260 {
261 char *ic;
262 SLang_BString_Type **a, **b, **c;
263 unsigned int n, n_max;
264 unsigned int da, db;
265
266 (void) a_type;
267 (void) b_type;
268
269 if (na == 1) da = 0; else da = 1;
270 if (nb == 1) db = 0; else db = 1;
271
272 if (na > nb) n_max = na; else n_max = nb;
273
274 a = (SLang_BString_Type **) ap;
275 b = (SLang_BString_Type **) bp;
276 for (n = 0; n < n_max; n++)
277 {
278 if ((*a == NULL) || (*b == NULL))
279 {
280 SLang_verror (SL_VARIABLE_UNINITIALIZED,
281 "Binary string element[%u] not initialized for binary operation", n);
282 return -1;
283 }
284 a += da; b += db;
285 }
286
287 a = (SLang_BString_Type **) ap;
288 b = (SLang_BString_Type **) bp;
289 ic = (char *) cp;
290 c = NULL;
291
292 switch (op)
293 {
294 case SLANG_PLUS:
295 /* Concat */
296 c = (SLang_BString_Type **) cp;
297 for (n = 0; n < n_max; n++)
298 {
299 if (NULL == (c[n] = concat_bstrings (*a, *b)))
300 goto return_error;
301
302 a += da; b += db;
303 }
304 break;
305
306 case SLANG_NE:
307 for (n = 0; n < n_max; n++)
308 {
309 ic [n] = (0 != compare_bstrings (*a, *b));
310 a += da;
311 b += db;
312 }
313 break;
314 case SLANG_GT:
315 for (n = 0; n < n_max; n++)
316 {
317 ic [n] = (compare_bstrings (*a, *b) > 0);
318 a += da;
319 b += db;
320 }
321 break;
322 case SLANG_GE:
323 for (n = 0; n < n_max; n++)
324 {
325 ic [n] = (compare_bstrings (*a, *b) >= 0);
326 a += da;
327 b += db;
328 }
329 break;
330 case SLANG_LT:
331 for (n = 0; n < n_max; n++)
332 {
333 ic [n] = (compare_bstrings (*a, *b) < 0);
334 a += da;
335 b += db;
336 }
337 break;
338 case SLANG_LE:
339 for (n = 0; n < n_max; n++)
340 {
341 ic [n] = (compare_bstrings (*a, *b) <= 0);
342 a += da;
343 b += db;
344 }
345 break;
346 case SLANG_EQ:
347 for (n = 0; n < n_max; n++)
348 {
349 ic [n] = (compare_bstrings (*a, *b) == 0);
350 a += da;
351 b += db;
352 }
353 break;
354 }
355 return 1;
356
357 return_error:
358 if (c != NULL)
359 {
360 free_n_bstrings (c, n);
361 while (n < n_max)
362 {
363 c[n] = NULL;
364 n++;
365 }
366 }
367 return -1;
368 }
369
370 /* If preserve_ptr, then use a[i] as the bstring data. See how this function
371 * is called by the binary op routines for why.
372 */
373 static SLang_BString_Type **
make_n_bstrings(SLang_BString_Type ** b,char ** a,unsigned int n,int ptr_type)374 make_n_bstrings (SLang_BString_Type **b, char **a, unsigned int n, int ptr_type)
375 {
376 unsigned int i;
377 int malloc_flag;
378
379 malloc_flag = 0;
380 if (b == NULL)
381 {
382 b = (SLang_BString_Type **) SLmalloc ((n + 1) * sizeof (SLang_BString_Type *));
383 if (b == NULL)
384 return NULL;
385 malloc_flag = 1;
386 }
387
388 for (i = 0; i < n; i++)
389 {
390 char *s = a[i];
391
392 if (s == NULL)
393 {
394 b[i] = NULL;
395 continue;
396 }
397
398 if (NULL == (b[i] = create_bstring_of_type (s, strlen(s), ptr_type)))
399 {
400 free_n_bstrings (b, i);
401 if (malloc_flag) SLfree ((char *) b);
402 return NULL;
403 }
404 }
405
406 return b;
407 }
408
409 static int
bstring_string_bin_op(int op,unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp,unsigned int nb,VOID_STAR cp)410 bstring_string_bin_op (int op,
411 unsigned char a_type, VOID_STAR ap, unsigned int na,
412 unsigned char b_type, VOID_STAR bp, unsigned int nb,
413 VOID_STAR cp)
414 {
415 SLang_BString_Type **b;
416 int ret;
417
418 if (NULL == (b = make_n_bstrings (NULL, (char **)bp, nb, IS_NOT_TO_BE_FREED)))
419 return -1;
420
421 b_type = SLANG_BSTRING_TYPE;
422 ret = bstring_bstring_bin_op (op,
423 a_type, ap, na,
424 b_type, (VOID_STAR) b, nb,
425 cp);
426 free_n_bstrings (b, nb);
427 SLfree ((char *) b);
428 return ret;
429 }
430
431 static int
string_bstring_bin_op(int op,unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp,unsigned int nb,VOID_STAR cp)432 string_bstring_bin_op (int op,
433 unsigned char a_type, VOID_STAR ap, unsigned int na,
434 unsigned char b_type, VOID_STAR bp, unsigned int nb,
435 VOID_STAR cp)
436 {
437 SLang_BString_Type **a;
438 int ret;
439
440 if (NULL == (a = make_n_bstrings (NULL, (char **)ap, na, IS_NOT_TO_BE_FREED)))
441 return -1;
442
443 a_type = SLANG_BSTRING_TYPE;
444 ret = bstring_bstring_bin_op (op,
445 a_type, (VOID_STAR) a, na,
446 b_type, bp, nb,
447 cp);
448 free_n_bstrings (a, na);
449 SLfree ((char *) a);
450
451 return ret;
452 }
453
bstring_destroy(unsigned char unused,VOID_STAR s)454 static void bstring_destroy (unsigned char unused, VOID_STAR s)
455 {
456 (void) unused;
457 SLbstring_free (*(SLang_BString_Type **) s);
458 }
459
bstring_push(unsigned char unused,VOID_STAR sptr)460 static int bstring_push (unsigned char unused, VOID_STAR sptr)
461 {
462 (void) unused;
463
464 return SLang_push_bstring (*(SLang_BString_Type **) sptr);
465 }
466
string_to_bstring(unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp)467 static int string_to_bstring (unsigned char a_type, VOID_STAR ap, unsigned int na,
468 unsigned char b_type, VOID_STAR bp)
469 {
470 char **s;
471 SLang_BString_Type **b;
472
473 (void) a_type;
474 (void) b_type;
475
476 s = (char **) ap;
477 b = (SLang_BString_Type **) bp;
478
479 if (NULL == make_n_bstrings (b, s, na, IS_SLSTRING))
480 return -1;
481
482 return 1;
483 }
484
bstring_to_string(unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp)485 static int bstring_to_string (unsigned char a_type, VOID_STAR ap, unsigned int na,
486 unsigned char b_type, VOID_STAR bp)
487 {
488 char **s;
489 unsigned int i;
490 SLang_BString_Type **a;
491
492 (void) a_type;
493 (void) b_type;
494
495 s = (char **) bp;
496 a = (SLang_BString_Type **) ap;
497
498 for (i = 0; i < na; i++)
499 {
500 SLang_BString_Type *ai = a[i];
501
502 if (ai == NULL)
503 {
504 s[i] = NULL;
505 continue;
506 }
507
508 if (NULL == (s[i] = SLang_create_slstring ((char *)BS_GET_POINTER(ai))))
509 {
510 while (i != 0)
511 {
512 i--;
513 SLang_free_slstring (s[i]);
514 s[i] = NULL;
515 }
516 return -1;
517 }
518 }
519
520 return 1;
521 }
522
bstring_string(unsigned char type,VOID_STAR v)523 static char *bstring_string (unsigned char type, VOID_STAR v)
524 {
525 SLang_BString_Type *s;
526 unsigned char buf[128];
527 unsigned char *bytes, *bytes_max;
528 unsigned char *b, *bmax;
529
530 (void) type;
531
532 s = *(SLang_BString_Type **) v;
533 bytes = BS_GET_POINTER(s);
534 bytes_max = bytes + s->len;
535
536 b = buf;
537 bmax = buf + (sizeof (buf) - 4);
538
539 while (bytes < bytes_max)
540 {
541 unsigned char ch = *bytes;
542
543 if ((ch < 32) || (ch >= 127) || (ch == '\\'))
544 {
545 if (b + 4 > bmax)
546 break;
547
548 sprintf ((char *) b, "\\%03o", ch);
549 b += 4;
550 }
551 else
552 {
553 if (b == bmax)
554 break;
555
556 *b++ = ch;
557 }
558
559 bytes++;
560 }
561
562 if (bytes < bytes_max)
563 {
564 *b++ = '.';
565 *b++ = '.';
566 *b++ = '.';
567 }
568 *b = 0;
569
570 return SLmake_string ((char *)buf);
571 }
572
bstrlen_cmd(SLang_BString_Type * b)573 static unsigned int bstrlen_cmd (SLang_BString_Type *b)
574 {
575 return b->len;
576 }
577
578 static SLang_Intrin_Fun_Type BString_Table [] = /*{{{*/
579 {
580 MAKE_INTRINSIC_1("bstrlen", bstrlen_cmd, SLANG_UINT_TYPE, SLANG_BSTRING_TYPE),
581 MAKE_INTRINSIC_0("pack", _SLpack, SLANG_VOID_TYPE),
582 MAKE_INTRINSIC_2("unpack", _SLunpack, SLANG_VOID_TYPE, SLANG_STRING_TYPE, SLANG_BSTRING_TYPE),
583 MAKE_INTRINSIC_1("pad_pack_format", _SLpack_pad_format, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
584 MAKE_INTRINSIC_1("sizeof_pack", _SLpack_compute_size, SLANG_UINT_TYPE, SLANG_STRING_TYPE),
585 SLANG_END_INTRIN_FUN_TABLE
586 };
587
_SLang_init_bstring(void)588 int _SLang_init_bstring (void)
589 {
590 SLang_Class_Type *cl;
591
592 if (NULL == (cl = SLclass_allocate_class ("BString_Type")))
593 return -1;
594 (void) SLclass_set_destroy_function (cl, bstring_destroy);
595 (void) SLclass_set_push_function (cl, bstring_push);
596 (void) SLclass_set_string_function (cl, bstring_string);
597
598 if (-1 == SLclass_register_class (cl, SLANG_BSTRING_TYPE, sizeof (char *),
599 SLANG_CLASS_TYPE_PTR))
600 return -1;
601
602 if ((-1 == SLclass_add_typecast (SLANG_BSTRING_TYPE, SLANG_STRING_TYPE, bstring_to_string, 1))
603 || (-1 == SLclass_add_typecast (SLANG_STRING_TYPE, SLANG_BSTRING_TYPE, string_to_bstring, 1))
604 || (-1 == SLclass_add_binary_op (SLANG_BSTRING_TYPE, SLANG_BSTRING_TYPE, bstring_bstring_bin_op, bstring_bstring_bin_op_result))
605 || (-1 == SLclass_add_binary_op (SLANG_STRING_TYPE, SLANG_BSTRING_TYPE, string_bstring_bin_op, bstring_bstring_bin_op_result))
606 || (-1 == SLclass_add_binary_op (SLANG_BSTRING_TYPE, SLANG_STRING_TYPE, bstring_string_bin_op, bstring_bstring_bin_op_result)))
607
608 return -1;
609
610 if (-1 == SLadd_intrin_fun_table (BString_Table, NULL))
611 return -1;
612
613 return 0;
614 }
615
616