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