1 /* Basic type operations for S-Lang */
2 /*
3 Copyright (C) 2004-2017,2018 John E. Davis
4 
5 This file is part of the S-Lang Library.
6 
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11 
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA.
21 */
22 
23 #include "slinclud.h"
24 
25 #if SLANG_HAS_FLOAT
26 # include <math.h>
27 #endif
28 
29 /* #define SL_APP_WANTS_FOREACH	*/       /* for String_Type */
30 #include "slang.h"
31 #include "_slang.h"
32 
SLpop_string(char ** s)33 int SLpop_string (char **s) /*{{{*/
34 {
35    char *sls;
36 
37    *s = NULL;
38 
39    if (-1 == SLang_pop_slstring (&sls))
40      return -1;
41 
42    if (NULL == (*s = SLmake_string (sls)))
43      {
44 	SLang_free_slstring (sls);
45 	return -1;
46      }
47 
48    SLang_free_slstring (sls);
49    return 0;
50 }
51 
52 /*}}}*/
53 
SLang_pop_slstring(char ** s)54 int SLang_pop_slstring (char **s) /*{{{*/
55 {
56    return SLclass_pop_ptr_obj (SLANG_STRING_TYPE, (VOID_STAR *)s);
57 }
58 
59 /*}}}*/
60 
_pSLang_push_slstring(char * s)61 int _pSLang_push_slstring (char *s)
62 {
63    if (0 == SLclass_push_ptr_obj (SLANG_STRING_TYPE, (VOID_STAR)s))
64      return 0;
65 
66    SLang_free_slstring (s);
67    return -1;
68 }
69 
70 /* Frees s upon error */
_pSLpush_alloced_slstring(char * s,size_t len)71 int _pSLpush_alloced_slstring (char *s, size_t len)
72 {
73    if (NULL == (s = _pSLcreate_via_alloced_slstring (s, len)))
74      return -1;
75 
76    return _pSLang_push_slstring (s);
77 }
78 
SLang_push_string(SLFUTURE_CONST char * t)79 int SLang_push_string (SLFUTURE_CONST char *t) /*{{{*/
80 {
81    if (t == NULL)
82      return SLang_push_null ();
83 
84    if (NULL == (t = SLang_create_slstring (t)))
85      return -1;
86 
87    return _pSLang_push_slstring ((char *) t);
88 }
89 
90 /*}}}*/
91 
_pSLang_dup_and_push_slstring(SLCONST char * s)92 int _pSLang_dup_and_push_slstring (SLCONST char *s)
93 {
94    if (NULL == (s = _pSLstring_dup_slstring (s)))
95      return SLang_push_null ();
96 
97    return _pSLang_push_slstring ((char *) s);
98 }
99 
100 /* This function _always_ frees the malloced string */
SLang_push_malloced_string(char * c)101 int SLang_push_malloced_string (char *c) /*{{{*/
102 {
103    int ret;
104 
105    ret = SLang_push_string (c);
106    SLfree (c);
107 
108    return ret;
109 }
110 
111 /*}}}*/
112 
113 #if 0
114 static int int_int_power (int a, int b)
115 {
116    int r, s;
117 
118    if (a == 0) return 0;
119    if (b < 0) return 0;
120    if (b == 0) return 1;
121 
122    s = 1;
123    if (a < 0)
124      {
125 	if ((b % 2) == 1) s = -1;
126 	a = -a;
127      }
128 
129    /* FIXME: Priority=low
130     * This needs optimized
131     */
132    r = 1;
133    while (b)
134      {
135 	r = r * a;
136 	b--;
137      }
138    return r * s;
139 }
140 #endif
141 
142 static int
string_string_bin_op_result(int op,SLtype a,SLtype b,SLtype * c)143 string_string_bin_op_result (int op, SLtype a, SLtype b,
144 			     SLtype *c)
145 {
146    (void) a;
147    (void) b;
148    switch (op)
149      {
150       default:
151 	return 0;
152 
153       case SLANG_PLUS:
154 	*c = SLANG_STRING_TYPE;
155 	break;
156 
157       case SLANG_GT:
158       case SLANG_GE:
159       case SLANG_LT:
160       case SLANG_LE:
161       case SLANG_EQ:
162       case SLANG_NE:
163 	*c = SLANG_CHAR_TYPE;
164 	break;
165      }
166    return 1;
167 }
168 
169 static int
string_string_bin_op(int op,SLtype a_type,VOID_STAR ap,SLuindex_Type na,SLtype b_type,VOID_STAR bp,SLuindex_Type nb,VOID_STAR cp)170 string_string_bin_op (int op,
171 		      SLtype a_type, VOID_STAR ap, SLuindex_Type na,
172 		      SLtype b_type, VOID_STAR bp, SLuindex_Type nb,
173 		      VOID_STAR cp)
174 {
175    char *ic;
176    char **a, **b, **c;
177    SLuindex_Type n, n_max;
178    unsigned int da, db;
179 
180    (void) a_type;
181    (void) b_type;
182 
183    if (na == 1) da = 0; else da = 1;
184    if (nb == 1) db = 0; else db = 1;
185 
186    if (na > nb) n_max = na; else n_max = nb;
187 
188    a = (char **) ap;
189    b = (char **) bp;
190 
191    if ((op != SLANG_NE) && (op != SLANG_EQ))
192      for (n = 0; n < n_max; n++)
193        {
194 	  if ((*a == NULL) || (*b == NULL))
195 	    {
196 	       _pSLang_verror (SL_VARIABLE_UNINITIALIZED, "String element[%lu] not initialized for binary operation", (unsigned long)n);
197 	       return -1;
198 	    }
199 	  a += da; b += db;
200        }
201 
202    a = (char **) ap;
203    b = (char **) bp;
204    ic = (char *) cp;
205    c = NULL;
206 
207    switch (op)
208      {
209       case SLANG_DIVIDE:
210       case SLANG_MINUS:
211       default:
212 	return 0;
213 
214        case SLANG_PLUS:
215 	/* Concat */
216 	c = (char **) cp;
217 	for (n = 0; n < n_max; n++)
218 	  {
219 	     if (NULL == (c[n] = SLang_concat_slstrings (*a, *b)))
220 	       goto return_error;
221 
222 	     a += da; b += db;
223 	  }
224 	break;
225 
226       case SLANG_NE:
227 	for (n = 0; n < n_max; n++)
228 	  {
229 	     if ((*a == NULL) || (*b == NULL))
230 	       ic [n] = (*a != *b);
231 	     else
232 	       ic [n] = (*a != *b) && (0 != strcmp (*a, *b));
233 
234 	     a += da;
235 	     b += db;
236 	  }
237 	break;
238       case SLANG_GT:
239 	for (n = 0; n < n_max; n++)
240 	  {
241 	     ic [n] = (strcmp (*a, *b) > 0);
242 	     a += da;
243 	     b += db;
244 	  }
245 	break;
246       case SLANG_GE:
247 	for (n = 0; n < n_max; n++)
248 	  {
249 	     ic [n] = (strcmp (*a, *b) >= 0);
250 	     a += da;
251 	     b += db;
252 	  }
253 	break;
254       case SLANG_LT:
255 	for (n = 0; n < n_max; n++)
256 	  {
257 	     ic [n] = (strcmp (*a, *b) < 0);
258 	     a += da;
259 	     b += db;
260 	  }
261 	break;
262       case SLANG_LE:
263 	for (n = 0; n < n_max; n++)
264 	  {
265 	     ic [n] = (strcmp (*a, *b) <= 0);
266 	     a += da;
267 	     b += db;
268 	  }
269 	break;
270       case SLANG_EQ:
271 	for (n = 0; n < n_max; n++)
272 	  {
273 	     if ((*a == NULL) || (*b == NULL))
274 	       ic[n] = (*a == *b);
275 	     else
276 	       ic [n] = (*a == *b) || (strcmp (*a, *b) == 0);
277 	     a += da;
278 	     b += db;
279 	  }
280 	break;
281      }
282    return 1;
283 
284    return_error:
285    if (c != NULL)
286      {
287 	SLuindex_Type nn;
288 	for (nn = 0; nn < n; nn++)
289 	  {
290 	     SLang_free_slstring (c[nn]);
291 	     c[nn] = NULL;
292 	  }
293 	for (nn = n; nn < n_max; nn++)
294 	  c[nn] = NULL;
295      }
296    return -1;
297 }
298 
string_destroy(SLtype unused,VOID_STAR s)299 static void string_destroy (SLtype unused, VOID_STAR s)
300 {
301    (void) unused;
302    SLang_free_slstring (*(char **) s);
303 }
304 
string_push(SLtype unused,VOID_STAR sptr)305 static int string_push (SLtype unused, VOID_STAR sptr)
306 {
307    (void) unused;
308    return SLang_push_string (*(char **) sptr);
309 }
310 
string_cmp(SLtype unused,VOID_STAR ap,VOID_STAR bp,int * c)311 static int string_cmp (SLtype unused, VOID_STAR ap, VOID_STAR bp, int *c)
312 {
313    char *a, *b;
314    (void) unused;
315 
316    a = *(char **) ap;
317    b = *(char **) bp;
318    if (a != b)
319      {
320 	if (a == NULL) *c = -1;
321 	else if (b == NULL) *c = 1;
322 	else *c = strcmp (a, b);
323 	return 0;
324      }
325    *c = 0;
326    return 0;
327 }
328 
string_to_int(SLtype a_type,VOID_STAR ap,SLuindex_Type na,SLtype b_type,VOID_STAR bp)329 static int string_to_int (SLtype a_type, VOID_STAR ap, SLuindex_Type na,
330 			  SLtype b_type, VOID_STAR bp)
331 {
332    char **s;
333    unsigned int i;
334    int *b;
335 
336    (void) a_type;
337    (void) b_type;
338 
339    s = (char **) ap;
340    b = (int *) bp;
341    for (i = 0; i < na; i++)
342      {
343 	if (s[i] == NULL) b[i] = 0;
344 	else b[i] = s[i][0];
345      }
346    return 1;
347 }
348 
string_acopy(SLtype unused,VOID_STAR src_sptr,VOID_STAR dest_sptr)349 static int string_acopy (SLtype unused, VOID_STAR src_sptr, VOID_STAR dest_sptr)
350 {
351    char *s;
352    (void) unused;
353    if (NULL == (s = SLang_create_slstring (*(char **)src_sptr)))
354      return -1;
355    *(char **)dest_sptr = s;
356    return 0;
357 }
358 
_pSLstrings_to_array(char ** strs,unsigned int n)359 SLang_Array_Type *_pSLstrings_to_array (char **strs, unsigned int n)
360 {
361    char **data;
362    SLindex_Type i, inum;
363    SLang_Array_Type *at;
364 
365    inum = (SLindex_Type) n;
366 
367    if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &inum, 1)))
368      return NULL;
369 
370    data = (char **)at->data;
371    for (i = 0; i < inum; i++)
372      {
373 	if (strs[i] == NULL)
374 	  {
375 	     data[i] = NULL;
376 	     continue;
377 	  }
378 
379 	if (NULL == (data[i] = SLang_create_slstring (strs[i])))
380 	  {
381 	     SLang_free_array (at);
382 	     return NULL;
383 	  }
384      }
385    return at;
386 }
387 
string_list_to_array(_pSLString_List_Type * p,int delete_list)388 static SLang_Array_Type *string_list_to_array (_pSLString_List_Type *p, int delete_list)
389 {
390    unsigned int num;
391    SLindex_Type inum;
392    SLang_Array_Type *at;
393    char **buf;
394 
395    buf = p->buf;
396    num = p->num;
397 
398    if (delete_list == 0)
399      return _pSLstrings_to_array (buf, num);
400 
401    inum = (SLindex_Type) num;
402    if (num == 0) num++;		       /* so realloc succeeds */
403 
404    /* Since the list is to be deleted, we can steal the buffer */
405    if ((num != p->max_num)
406        && (NULL == (buf = (char **)SLrealloc ((char *) buf, sizeof (char *) * num))))
407      {
408 	_pSLstring_list_delete (p);
409 	return NULL;
410      }
411    p->max_num = num;
412    p->buf = buf;
413 
414    if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) buf, &inum, 1)))
415      {
416 	_pSLstring_list_delete (p);
417 	return NULL;
418      }
419    p->buf = NULL;
420    _pSLstring_list_delete (p);
421    return at;
422 }
423 
_pSLstring_list_push(_pSLString_List_Type * p,int delete_list)424 int _pSLstring_list_push (_pSLString_List_Type *p, int delete_list)
425 {
426    SLang_Array_Type *at;
427 
428    if ((p == NULL)
429        || (p->buf == NULL))
430      {
431 	int ret = SLang_push_null ();
432 	if (delete_list)
433 	  _pSLstring_list_delete (p);
434 	return ret;
435      }
436 
437    if (NULL == (at = string_list_to_array (p, delete_list)))
438      return -1;
439 
440    return SLang_push_array (at, 1);
441 }
442 
_pSLstring_list_init(_pSLString_List_Type * p,unsigned int max_num,unsigned int delta_num)443 int _pSLstring_list_init (_pSLString_List_Type *p, unsigned int max_num, unsigned int delta_num)
444 {
445    if (NULL == (p->buf = (char **) _SLcalloc (max_num, sizeof (char *))))
446      return -1;
447 
448    p->max_num = max_num;
449    p->num = 0;
450    p->delta_num = delta_num;
451    p->is_malloced = 0;
452    return 0;
453 }
454 
_pSLstring_list_append(_pSLString_List_Type * p,char * s)455 int _pSLstring_list_append (_pSLString_List_Type *p, char *s)
456 {
457    if (s == NULL)
458      return -1;
459 
460    if (p->max_num == p->num)
461      {
462 	char **b;
463 	unsigned int max_num = p->num + p->delta_num;
464 	b = (char **)SLrealloc ((char *)p->buf, max_num * sizeof (char *));
465 	if (b == NULL)
466 	  return -1;
467 	p->buf = b;
468 	p->max_num = max_num;
469      }
470 
471    p->buf[p->num] = s;
472    p->num++;
473    return 0;
474 }
475 
_pSLstring_list_append_copy(_pSLString_List_Type * p,char * s)476 int _pSLstring_list_append_copy (_pSLString_List_Type *p, char *s)
477 {
478    s = SLang_create_slstring (s);
479    if (s == NULL)
480      return -1;
481    if (-1 == _pSLstring_list_append (p, s))
482      {
483 	SLang_free_slstring (s);
484 	return -1;
485      }
486    return 0;
487 }
488 
_pSLstring_list_delete(_pSLString_List_Type * p)489 void _pSLstring_list_delete (_pSLString_List_Type *p)
490 {
491    if (p == NULL)
492      return;
493 
494    if (p->buf != NULL)
495      {
496 	unsigned int i, imax;
497 	char **buf = p->buf;
498 	imax = p->num;
499 	for (i = 0; i < imax; i++)
500 	  SLang_free_slstring (buf[i]);
501 	SLfree ((char *)buf);
502 	p->buf = NULL;
503      }
504    if (p->is_malloced)
505      SLfree ((char *) p);
506 }
507 
_pSLstring_list_new(unsigned int max_num,unsigned int delta_num)508 _pSLString_List_Type *_pSLstring_list_new (unsigned int max_num, unsigned int delta_num)
509 {
510    _pSLString_List_Type *p;
511 
512    p = (_pSLString_List_Type *)SLmalloc (sizeof (_pSLString_List_Type));
513    if (p == NULL)
514      return NULL;
515 
516    if (-1 == _pSLstring_list_init (p, max_num, delta_num))
517      {
518 	SLfree ((char *) p);
519 	return NULL;
520      }
521    p->is_malloced = 1;
522    return p;
523 }
524 
525 /* Ref type */
526 
_pSLang_deref_assign(SLang_Ref_Type * ref)527 int _pSLang_deref_assign (SLang_Ref_Type *ref)
528 {
529    return ref->deref_assign (ref->data);
530 }
531 
SLang_pop_ref(SLang_Ref_Type ** ref)532 int SLang_pop_ref (SLang_Ref_Type **ref)
533 {
534    return SLclass_pop_ptr_obj (SLANG_REF_TYPE, (VOID_STAR *)ref);
535 }
536 
SLang_push_ref(SLang_Ref_Type * ref)537 int SLang_push_ref (SLang_Ref_Type *ref)
538 {
539    ref->num_refs++;
540    if (0 == SLclass_push_ptr_obj (SLANG_REF_TYPE, (VOID_STAR) ref))
541      return 0;
542    ref->num_refs--;
543    return -1;
544 }
545 
SLang_free_ref(SLang_Ref_Type * ref)546 void SLang_free_ref (SLang_Ref_Type *ref)
547 {
548    if (ref == NULL)
549      return;
550 
551    if (ref->num_refs > 1)
552      {
553 	ref->num_refs--;
554 	return;
555      }
556 
557    if (ref->destroy != NULL)
558      (*ref->destroy)(ref->data);
559    SLfree ((char *)ref->data);
560    SLfree ((char *)ref);
561 }
562 
_pSLang_new_ref(unsigned int sizeof_data)563 SLang_Ref_Type *_pSLang_new_ref (unsigned int sizeof_data)
564 {
565    SLang_Ref_Type *ref;
566 
567    if (NULL == (ref = (SLang_Ref_Type *)SLcalloc (1, sizeof (SLang_Ref_Type))))
568      return NULL;
569    if (NULL == (ref->data = (VOID_STAR)SLcalloc (1, sizeof_data)))
570      {
571 	SLfree ((char *)ref);
572 	return NULL;
573      }
574    ref->num_refs = 1;
575    ref->sizeof_data = sizeof_data;
576    return ref;
577 }
578 
ref_destroy(SLtype type,VOID_STAR ptr)579 static void ref_destroy (SLtype type, VOID_STAR ptr)
580 {
581    (void) type;
582    SLang_free_ref (*(SLang_Ref_Type **)ptr);
583 }
584 
ref_push(SLtype type,VOID_STAR ptr)585 static int ref_push (SLtype type, VOID_STAR ptr)
586 {
587    SLang_Ref_Type *ref;
588 
589    (void) type;
590 
591    ref = *(SLang_Ref_Type **) ptr;
592 
593    if (ref == NULL)
594      return SLang_push_null ();
595 
596    return SLang_push_ref (ref);
597 }
598 
SLang_assign_to_ref(SLang_Ref_Type * ref,SLtype type,VOID_STAR v)599 int SLang_assign_to_ref (SLang_Ref_Type *ref, SLtype type, VOID_STAR v)
600 {
601    SLang_Object_Type *stkptr;
602    SLang_Class_Type *cl;
603 
604    cl = _pSLclass_get_class (type);
605 
606    /* Use apush since this function is passing ``array'' bytes rather than the
607     * address of the data.  I need to somehow make this more consistent.  To
608     * see what I mean, consider:
609     *
610     *    double z[2];
611     *    char *s = "silly";
612     *    char bytes[10];  BAD--- Don't do this
613     *    int i;
614     *
615     *    SLang_assign_to_ref (ref, SLANG_INT_TYPE,    &i);
616     *    SLang_assign_to_ref (ref, SLANG_STRING_TYPE, &s);
617     *    SLang_assign_to_ref (ref, SLANG_COMPLEX_TYPE, z);
618     *
619     * That is, all external routines that take a VOID_STAR argument need to
620     * be documented such that how the function should be called with the
621     * various class_types.
622     */
623    if (-1 == (*cl->cl_apush) (type, v))
624      return -1;
625 
626    stkptr = _pSLang_get_run_stack_pointer ();
627    if (0 == _pSLang_deref_assign (ref))
628      return 0;
629 
630    if (stkptr != _pSLang_get_run_stack_pointer ())
631      SLdo_pop ();
632 
633    return -1;
634 }
635 
ref_string(SLtype type,VOID_STAR ptr)636 static char *ref_string (SLtype type, VOID_STAR ptr)
637 {
638    SLang_Ref_Type *ref;
639 
640    (void) type;
641    ref = *(SLang_Ref_Type **) ptr;
642    if (ref->string != NULL)
643      return ref->string (ref->data);
644    return SLmake_string ("Ref_Type");
645 }
646 
ref_dereference(SLtype unused,VOID_STAR ptr)647 static int ref_dereference (SLtype unused, VOID_STAR ptr)
648 {
649    (void) unused;
650    return _pSLang_dereference_ref (*(SLang_Ref_Type **) ptr);
651 }
652 
ref_cmp(SLtype type,VOID_STAR a,VOID_STAR b,int * c)653 static int ref_cmp (SLtype type, VOID_STAR a, VOID_STAR b, int *c)
654 {
655    SLang_Ref_Type *ra, *rb;
656 
657    (void) type;
658 
659    ra = *(SLang_Ref_Type **)a;
660    rb = *(SLang_Ref_Type **)b;
661 
662    if (ra == NULL)
663      {
664 	if (rb == NULL) *c = 0;
665 	else *c = -1;
666 	return 0;
667      }
668    if (rb == NULL)
669      {
670 	*c = 1;
671 	return 0;
672      }
673    if (ra->sizeof_data != rb->sizeof_data)
674      {
675 	*c = (int)ra->sizeof_data - (int)rb->sizeof_data;
676 	return 0;
677      }
678 
679    *c = memcmp (ra->data, rb->data, ra->sizeof_data);
680    return 0;
681 }
682 
683 /* NULL is permitted here */
SLang_push_function(SLang_Name_Type * nt)684 int SLang_push_function (SLang_Name_Type *nt)
685 {
686    return _pSLang_push_nt_as_ref (nt);
687 }
688 
SLang_pop_function(void)689 SLang_Name_Type *SLang_pop_function (void)
690 {
691    SLang_Ref_Type *ref;
692    SLang_Name_Type *f;
693 
694    if (SLang_peek_at_stack () == SLANG_STRING_TYPE)
695      {
696 	char *name;
697 
698 	if (-1 == SLang_pop_slstring (&name))
699 	  return NULL;
700 
701 	if (NULL == (f = SLang_get_function (name)))
702 	  {
703 	     _pSLang_verror (SL_UNDEFINED_NAME, "Function %s does not exist", name);
704 	     SLang_free_slstring (name);
705 	     return NULL;
706 	  }
707 	SLang_free_slstring (name);
708 	return f;
709      }
710 
711    if (-1 == SLang_pop_ref (&ref))
712      return NULL;
713 
714    f = SLang_get_fun_from_ref (ref);
715    SLang_free_ref (ref);
716    return f;
717 }
718 
719 /* This is a placeholder for version 3 --- NULL assumed to be ok */
SLang_free_function(SLang_Name_Type * f)720 void SLang_free_function (SLang_Name_Type *f)
721 {
722    (void) f;
723 }
724 
SLang_copy_function(SLang_Name_Type * f)725 SLang_Name_Type *SLang_copy_function (SLang_Name_Type *f)
726 {
727    /* Add ref-count here */
728    return f;
729 }
730 
731 /* NULL type */
SLang_push_null(void)732 int SLang_push_null (void)
733 {
734    return SLclass_push_ptr_obj (SLANG_NULL_TYPE, NULL);
735 }
736 
SLang_pop_null(void)737 int SLang_pop_null (void)
738 {
739    SLang_Object_Type obj;
740    return _pSLang_pop_object_of_type (SLANG_NULL_TYPE, &obj, 0);
741 }
742 
null_push(SLtype unused,VOID_STAR ptr_unused)743 static int null_push (SLtype unused, VOID_STAR ptr_unused)
744 {
745    (void) unused; (void) ptr_unused;
746    return SLang_push_null ();
747 }
748 
null_pop(SLtype type,VOID_STAR ptr)749 static int null_pop (SLtype type, VOID_STAR ptr)
750 {
751    (void) type;
752 
753    if (-1 == SLang_pop_null ())
754      return -1;
755 
756    *(char **) ptr = NULL;
757    return 0;
758 }
759 
null_dereference(SLtype unused,VOID_STAR ptr)760 static int null_dereference (SLtype unused, VOID_STAR ptr)
761 {
762    (void) unused; (void) ptr;
763    return SLang_push_null ();
764 }
765 
766 /* Implement foreach (NULL) using (whatever) to do nothing.  This is useful
767  * because suppose that X is a list but is NULL in some situations.  Then
768  * when it is NULL, we want foreach(X) to do nothing.
769  */
770 static SLang_Foreach_Context_Type *
null_foreach_open(SLtype type,unsigned int num)771 null_foreach_open (SLtype type, unsigned int num)
772 {
773    (void) type;
774    SLdo_pop_n (num + 1);
775    return (SLang_Foreach_Context_Type *)1;
776 }
777 
null_foreach_close(SLtype type,SLang_Foreach_Context_Type * c)778 static void null_foreach_close (SLtype type, SLang_Foreach_Context_Type *c)
779 {
780    (void) type;
781    (void) c;
782 }
783 
null_foreach(SLtype type,SLang_Foreach_Context_Type * c)784 static int null_foreach (SLtype type, SLang_Foreach_Context_Type *c)
785 {
786    (void) type;
787    (void) c;
788    return 0;
789 }
790 
null_to_bool(SLtype type,int * t)791 static int null_to_bool (SLtype type, int *t)
792 {
793    (void) type;
794    *t = 0;
795    return SLang_pop_null ();
796 }
797 
798 /* AnyType */
_pSLanytype_typecast(SLtype a_type,VOID_STAR ap,SLuindex_Type na,SLtype b_type,VOID_STAR bp)799 int _pSLanytype_typecast (SLtype a_type, VOID_STAR ap, SLuindex_Type na,
800 			  SLtype b_type, VOID_STAR bp)
801 {
802    SLang_Class_Type *cl;
803    SLang_Any_Type **any;
804    SLuindex_Type i;
805    size_t sizeof_type;
806 
807    (void) b_type;
808 
809    any = (SLang_Any_Type **) bp;
810 
811    cl = _pSLclass_get_class (a_type);
812    sizeof_type = cl->cl_sizeof_type;
813 
814    for (i = 0; i < na; i++)
815      {
816 	if ((-1 == (*cl->cl_apush) (a_type, ap))
817 	    || (-1 == SLang_pop_anytype (&any[i])))
818 	  {
819 	     while (i != 0)
820 	       {
821 		  i--;
822 		  SLang_free_anytype (any[i]);
823 		  any[i] = NULL;
824 	       }
825 	     return -1;
826 	  }
827 	ap = (VOID_STAR)((char *)ap + sizeof_type);
828      }
829 
830    return 1;
831 }
832 
SLang_pop_anytype(SLang_Any_Type ** any)833 int SLang_pop_anytype (SLang_Any_Type **any)
834 {
835    SLang_Object_Type *obj;
836 
837    if (NULL == (obj = (SLang_Object_Type *) SLmalloc (sizeof (SLang_Object_Type))))
838      {
839 	*any = NULL;
840 	return -1;
841      }
842 
843    if (-1 == SLang_pop (obj))
844      {
845 	*any = NULL;
846 	SLfree ((char *) obj);
847 	return -1;
848      }
849    *any = (SLang_Any_Type *)obj;
850    return 0;
851 }
852 
853 /* This function will result in an object that is represented by the
854  * anytype object.
855  */
SLang_push_anytype(SLang_Any_Type * any)856 int SLang_push_anytype (SLang_Any_Type *any)
857 {
858    return _pSLpush_slang_obj ((SLang_Object_Type *)any);
859 }
860 
861 /* After this call, the stack will contain an Any_Type object */
anytype_push(SLtype type,VOID_STAR ptr)862 static int anytype_push (SLtype type, VOID_STAR ptr)
863 {
864    SLang_Any_Type *obj;
865 
866    /* Push the object onto the stack, then pop it back off into our anytype
867     * container.  That way, any memory managing associated with the type
868     * will be performed automatically.  Another way to think of it is that
869     * pushing an Any_Type onto the stack will create another copy of the
870     * object represented by it.
871     */
872    if (-1 == _pSLpush_slang_obj (*(SLang_Object_Type **)ptr))
873      return -1;
874 
875    if (-1 == SLang_pop_anytype (&obj))
876      return -1;
877 
878    /* There is no need to reference count the anytype objects since every
879     * push results in a new anytype container.
880     */
881    if (-1 == SLclass_push_ptr_obj (type, (VOID_STAR) obj))
882      {
883 	SLang_free_anytype (obj);
884 	return -1;
885      }
886 
887    return 0;
888 }
889 
anytype_destroy(SLtype type,VOID_STAR ptr)890 static void anytype_destroy (SLtype type, VOID_STAR ptr)
891 {
892    SLang_Object_Type *obj;
893 
894    (void) type;
895    obj = *(SLang_Object_Type **)ptr;
896    SLang_free_object (obj);
897    SLfree ((char *) obj);
898 }
899 
SLang_free_anytype(SLang_Any_Type * any)900 void SLang_free_anytype (SLang_Any_Type *any)
901 {
902    if (any != NULL)
903      anytype_destroy (SLANG_ANY_TYPE, (VOID_STAR) &any);
904 }
905 
anytype_dereference(SLtype unused,VOID_STAR ptr)906 static int anytype_dereference (SLtype unused, VOID_STAR ptr)
907 {
908    (void) unused;
909    return _pSLpush_slang_obj (*(SLang_Object_Type **) ptr);
910 }
911 
912 #if 0
913 /* This function performs a deref since we may want the symmetry
914  *  a = Any_Type[1];  a[x] = "foo"; bar = a[x]; ==> bar == "foo"
915  * That is, we do not want bar to be an Any_Type.
916  *
917  * Unfortunately, this does not work because of the use of the transfer
918  * buffer by both slarray.c and sltypecast.c.  I can work around that
919  * but I am not sure that I like typeof(Any_Type[0]) != Any_Type.
920  */
921 static int anytype_apush (SLtype type, VOID_STAR ptr)
922 {
923    (void) type;
924    return _pSLpush_slang_obj (*(SLang_Object_Type **)ptr);
925 }
926 #endif
927 
928 /* SLANG_INTP_TYPE */
intp_push(SLtype unused,VOID_STAR ptr)929 static int intp_push (SLtype unused, VOID_STAR ptr)
930 {
931    int *addr;
932    (void) unused;
933    addr = *(int **)ptr;
934    if (addr == NULL)
935      return SLclass_push_int_obj (SLANG_INT_TYPE, 0);
936    return SLclass_push_int_obj (SLANG_INT_TYPE, *addr);
937 }
938 
intp_pop(SLtype unused,VOID_STAR ptr)939 static int intp_pop (SLtype unused, VOID_STAR ptr)
940 {
941    int *addr;
942 
943    (void) unused;
944    addr = *(int **)ptr;
945    if (addr == NULL)
946      {
947 	SLang_verror (SL_VariableUninitialized_Error, "_IntegerP_Type: integer pointer address is NULL");
948 	return -1;
949      }
950    return SLang_pop_integer (addr);
951 }
952 
_pSLang_pop_wchar(SLwchar_Type * wcp)953 int _pSLang_pop_wchar (SLwchar_Type *wcp)
954 {
955    /* FIXME: This bit of code will be merged into the SLang_pop_wchar function
956     * for the next major version.  Currently, SLang_pop_wchar is a macro.
957     */
958    if (SLang_peek_at_stack () == SLANG_CHAR_TYPE)
959      {
960 	char ch;
961 	if (-1 == SLang_pop_char (&ch))
962 	  return -1;
963 	*wcp = (unsigned char)ch;
964 	return 0;
965      }
966    return SLang_pop_wchar (wcp);
967 }
968 
undefined_method(SLtype t,VOID_STAR p)969 static int undefined_method (SLtype t, VOID_STAR p)
970 {
971    (void) t; (void) p;
972    SLang_set_error (SL_VARIABLE_UNINITIALIZED);
973    return -1;
974 }
void_undefined_method(SLtype t,VOID_STAR p)975 static void void_undefined_method (SLtype t, VOID_STAR p)
976 {
977    (void) t; (void) p;
978 }
979 
check_sizeof(size_t c,size_t s,const char * obj,int * errp)980 static void check_sizeof (size_t c, size_t s, const char *obj, int *errp)
981 {
982    if (c == s) return;
983    (void) fprintf (stderr, "C sizeof (%s) is %d, configured to be %d\n",
984 		   obj, (int)c, (int)s);
985    *errp = 1;
986 }
987 
_pSLregister_types(void)988 int _pSLregister_types (void)
989 {
990    SLang_Class_Type *cl;
991    int err = 0;
992 
993    check_sizeof (sizeof(short), SIZEOF_SHORT, "short", &err);
994    check_sizeof (sizeof(int), SIZEOF_INT, "int", &err);
995    check_sizeof (sizeof(long), SIZEOF_LONG, "long", &err);
996    check_sizeof (sizeof(float), SIZEOF_FLOAT, "float", &err);
997    check_sizeof (sizeof(double), SIZEOF_DOUBLE, "double", &err);
998    check_sizeof (sizeof(size_t), SIZEOF_SIZE_T, "size_t", &err);
999    check_sizeof (sizeof(off_t), SIZEOF_OFF_T, "off_t", &err);
1000 
1001    if (err)
1002      SLang_exit_error ("S-Lang Library not built properly.  Fix SIZEOF_* in config.h and recompile");
1003 
1004    if (-1 == _pSLclass_init ())
1005      return -1;
1006 
1007    /* Undefined Type */
1008    if (NULL == (cl = SLclass_allocate_class ("Undefined_Type")))
1009      return -1;
1010    (void) SLclass_set_push_function (cl, undefined_method);
1011    (void) SLclass_set_pop_function (cl, undefined_method);
1012    (void) SLclass_set_destroy_function (cl, void_undefined_method);
1013    if (-1 == SLclass_register_class (cl, SLANG_UNDEFINED_TYPE, sizeof (int),
1014 				     SLANG_CLASS_TYPE_SCALAR))
1015      return -1;
1016    /* Make Void_Type a synonym for Undefined_Type.  Note that this does
1017     * not mean that Void_Type represents SLANG_VOID_TYPE.  Void_Type is
1018     * used by array_map to indicate no array is to be created.
1019     */
1020    if (-1 == SLclass_create_synonym ("Void_Type", SLANG_UNDEFINED_TYPE))
1021      return -1;
1022 
1023    if (-1 == _pSLarith_register_types ())
1024      return -1;
1025 
1026    /* SLANG_INTP_TYPE -- not used within the interpreter */
1027    if (NULL == (cl = SLclass_allocate_class ("_IntegerP_Type")))
1028      return -1;
1029    (void) SLclass_set_push_function (cl, intp_push);
1030    (void) SLclass_set_pop_function (cl, intp_pop);
1031    if (-1 == SLclass_register_class (cl, SLANG_INTP_TYPE, sizeof (int *),
1032 				     SLANG_CLASS_TYPE_SCALAR))
1033      return -1;
1034 
1035    /* String Type */
1036 
1037    if (NULL == (cl = SLclass_allocate_class ("String_Type")))
1038      return -1;
1039    (void) SLclass_set_destroy_function (cl, string_destroy);
1040    (void) SLclass_set_push_function (cl, string_push);
1041    (void) SLclass_set_acopy_function (cl, string_acopy);
1042    cl->cl_foreach_open = _pSLbstring_foreach_open;
1043    cl->cl_foreach_close = _pSLbstring_foreach_close;
1044    cl->cl_foreach = _pSLbstring_foreach;
1045    cl->cl_cmp = string_cmp;
1046    if (-1 == SLclass_register_class (cl, SLANG_STRING_TYPE, sizeof (char *),
1047 				     SLANG_CLASS_TYPE_PTR))
1048      return -1;
1049 
1050    /* ref Type */
1051    if (NULL == (cl = SLclass_allocate_class ("Ref_Type")))
1052      return -1;
1053    cl->cl_dereference = ref_dereference;
1054    cl->cl_push = ref_push;
1055    cl->cl_destroy = ref_destroy;
1056    cl->cl_string = ref_string;
1057    cl->cl_cmp = ref_cmp;
1058    if (-1 == SLclass_register_class (cl, SLANG_REF_TYPE,
1059 				     sizeof (SLang_Ref_Type *),
1060 				     SLANG_CLASS_TYPE_PTR))
1061      return -1;
1062 
1063    /* NULL Type */
1064 
1065    if (NULL == (cl = SLclass_allocate_class ("Null_Type")))
1066      return -1;
1067    cl->cl_dereference = null_dereference,
1068    cl->cl_push = null_push;
1069    cl->cl_pop = null_pop;
1070    cl->cl_foreach_open = null_foreach_open;
1071    cl->cl_foreach_close = null_foreach_close;
1072    cl->cl_foreach = null_foreach;
1073    cl->cl_to_bool = null_to_bool;
1074    if (-1 == SLclass_register_class (cl, SLANG_NULL_TYPE, sizeof (char *),
1075 				     SLANG_CLASS_TYPE_SCALAR))
1076      return -1;
1077 
1078    /* AnyType */
1079    if (NULL == (cl = SLclass_allocate_class ("Any_Type")))
1080      return -1;
1081    (void) SLclass_set_push_function (cl, anytype_push);
1082    (void) SLclass_set_destroy_function (cl, anytype_destroy);
1083 #if 0
1084    (void) SLclass_set_apush_function (cl, anytype_apush);
1085 #endif
1086    cl->cl_dereference = anytype_dereference;
1087    if (-1 == SLclass_register_class (cl, SLANG_ANY_TYPE, sizeof (VOID_STAR),
1088 				     SLANG_CLASS_TYPE_PTR))
1089      return -1;
1090 
1091    if (-1 == _pSLang_init_bstring ())
1092      return -1;
1093 
1094    if ((-1 == SLclass_add_typecast (SLANG_STRING_TYPE, SLANG_INT_TYPE, string_to_int, 0))
1095        || (-1 == SLclass_add_binary_op (SLANG_STRING_TYPE, SLANG_STRING_TYPE, string_string_bin_op, string_string_bin_op_result)))
1096      return -1;
1097 
1098    return 0;
1099 }
1100 
1101