1 /*
2    entity.c -- Miscellaneous routines for entities.
3 
4    Copyright (C) 1994-2002  K. Scott Hunziker.
5    Copyright (C) 1990-1994  The Boeing Company.
6 
7    See the file COPYING for license, warranty, and permission details.
8  */
9 
10 static char rcsid[] =
11 "$Id: entity.c,v 1.5 2002/07/30 22:05:17 ksh Exp $";
12 
13 #include "entity.h"
14 #include "scalar.h"
15 #include "vector.h"
16 #include "matrix.h"
17 #include "table.h"
18 #include "function.h"
19 #include "cast.h"
20 
21 #define ENUM_STRNG_INIT		1
22 #include "enum_strng.h"
23 
24 /*
25  * When debugging, a message is printed if the number of references
26  * to an entity exceeds DB_REF_THRESHOLD.
27  */
28 
29 #ifndef DB_REF_THRESHOLD
30 #define DB_REF_THRESHOLD 1000
31 #endif
32 
33 char NULL_string[1] = "";	/* Most NULL strings point here. */
34 
35 void *
eat(p)36 eat (p)
37      void **p;
38 {
39   void *e;
40 
41   e = *p;
42   *p = NULL;
43   return (e);
44 }
45 
46 ENTITY *
DB_copy_entity(p,file,line)47 DB_copy_entity (p, file, line)
48      ENTITY *p;
49      char *file;
50      int line;
51 {
52   EASSERT (p, 0, 0);
53 
54   if (++p->ref_count >= DB_REF_THRESHOLD || debug_level > 1)
55     inform ("%s \"ref_count\" increment:  %x, %d, %s, %d.",
56 	    class_string[p->class], p, p->ref_count, file, line);
57 
58   return (p);
59 }
60 
61 void
DB_delete_entity(p,file,line)62 DB_delete_entity (p, file, line)
63      ENTITY *p;
64      char *file;
65      int line;
66 {
67   /*
68    * This is the DEBUG version of `delete_entity'.  It decrements
69    * the entity's reference count, and frees it if it is unreferenced.
70    */
71 
72   if (p)
73     {
74 
75       if (--p->ref_count < 0)
76 	{
77 	  wipeout ("A %s's \"ref_count\" went below zero:  %s, %d.",
78 		   class_string[p->class], file, line);
79 	}
80 
81       if (p->ref_count >= DB_REF_THRESHOLD || debug_level > 1)
82 	{
83 	  inform ("%s \"ref_count\" decrement:  %x, %d, %s, %d.",
84 		  class_string[p->class], p, p->ref_count, file, line);
85 	}
86 
87       if (p->ref_count == 0)
88 	free_entity (p);
89 
90     }
91 }
92 
93 void
free_entity(p)94 free_entity (p)
95      ENTITY *p;
96 {
97   assert (p != NULL);
98   assert (p->ref_count == 0);
99 
100   switch (p->class)
101     {
102     case scalar:
103       free_scalar ((SCALAR *) p);
104       break;
105     case vector:
106       free_vector ((VECTOR *) p);
107       break;
108     case matrix:
109       free_matrix ((MATRIX *) p);
110       break;
111     case table:
112       free_table ((TABLE *) p);
113       break;
114     case function:
115       free_function ((FUNCTION *) p);
116       break;
117     default:
118       BAD_CLASS (p->class);
119       delete_entity (p);
120       raise_exception ();
121     }
122 }
123 
124 ENTITY *
dup_entity(p)125 dup_entity (p)
126      ENTITY *p;
127 {
128   EASSERT (p, 0, 0);
129 
130   switch (p->class)
131     {
132     case scalar:
133       return (dup_scalar ((SCALAR *) p));
134     case vector:
135       return (dup_vector ((VECTOR *) p));
136     case matrix:
137       return (dup_matrix ((MATRIX *) p));
138     case table:
139       return (dup_table ((TABLE *) p));
140     case function:
141       return (dup_function ((FUNCTION *) p));
142     default:
143       BAD_CLASS (p->class);
144       delete_entity (p);
145       raise_exception ();
146     }
147 }
148 
149 char *
dup_char(p)150 dup_char (p)
151      char *p;
152 {
153   assert (p != NULL);
154 
155   if (*p == '\0')
156     return (NULL_string);
157 
158   return (strcpy (MALLOC (strlen (p) + 1), p));
159 }
160 
161 char *
append_char(l,r)162 append_char (l, r)
163      char *l;
164      char *r;
165 {
166   char *p;
167 
168   assert (l != NULL && r != NULL);
169   p = MALLOC (strlen (l) + strlen (r) + 1);
170   return (strcat (strcpy (p, l), r));
171 }
172 
173 void *
dup_mem(p,len)174 dup_mem (p, len)
175      void *p;
176      int len;
177 {
178   assert (p != NULL);
179 
180   return (memcpy (MALLOC (len), p, len));
181 }
182 
183 ENTITY *
not_NULL(p)184 not_NULL (p)
185      ENTITY *p;
186 {
187   if (p == NULL)
188     raise_exception ();
189   return (p);
190 }
191 
192 int
member_cmp(keyval,dat)193 member_cmp (keyval, dat)
194      const void *keyval;
195      const void *dat;
196 {
197   return (strcmp ((char *) keyval, ((MEMBER_ID *) dat)->name));
198 }
199 
200 ENTITY *
bi_class(n,p)201 bi_class (n, p)
202      int n;
203      ENTITY *p;
204 {
205   char *c;
206 
207   if (p)
208     {
209       c = class_string[p->class];
210       delete_entity (p);
211     }
212   else
213     {
214       c = "NULL";
215     }
216 
217   return char_to_scalar (dup_char (c));
218 }
219 
220 char *
th(i)221 th (i)
222      int i;
223 {
224   if (i < 0)
225     {
226       return ("");
227     }
228   else if (i > 3 && i < 21)
229     {
230       return ("th");
231     }
232   else
233     {
234       switch (i % 10)
235 	{
236 	case 1:
237 	  return ("st");
238 	case 2:
239 	  return ("nd");
240 	case 3:
241 	  return ("rd");
242 	default:
243 	  return ("th");
244 	}
245     }
246 }
247 
248 int
entity_to_int(e)249 entity_to_int (e)
250      ENTITY *e;
251 {
252   /* Convert an entity to an integer */
253 
254   int i;
255 
256   e = cast_scalar ((SCALAR *) scalar_entity (e), integer);
257   i = ((SCALAR *) e)->v.integer;
258 
259   delete_scalar ((SCALAR *) e);
260   return (i);
261 }
262 
263 REAL
entity_to_real(e)264 entity_to_real (e)
265      ENTITY *e;
266 {
267   /* Convert an entity to a real. */
268 
269   REAL r;
270 
271   e = cast_scalar ((SCALAR *) scalar_entity (e), real);
272   r = ((SCALAR *) e)->v.real;
273 
274   delete_scalar ((SCALAR *) e);
275   return r;
276 }
277 
278 COMPLEX
entity_to_complex(e)279 entity_to_complex (e)
280      ENTITY *e;
281 {
282   /* Convert an entity to a complex. */
283 
284   COMPLEX r;
285 
286   e = cast_scalar ((SCALAR *) scalar_entity (e), complex);
287   r.real = ((SCALAR *) e)->v.complex.real;
288   r.imag = ((SCALAR *) e)->v.complex.imag;
289 
290   delete_scalar ((SCALAR *) e);
291   return r;
292 }
293 
294 char *
entity_to_string(e)295 entity_to_string (e)
296      ENTITY *e;
297 {
298   /* Convert an entity to a character string. */
299 
300   char *s;
301 
302   e = cast_scalar ((SCALAR *) scalar_entity (e), character);
303 
304   /*
305    * We'll try to take a little shortcut here.  If the ref_count
306    * is 1, we'll just steal the entity's copy of the string
307    * instead of malloc'ing another.
308    */
309 
310   if (e->ref_count == 1)
311     {
312       s = ((SCALAR *) e)->v.character;
313       ((SCALAR *) e)->v.character = NULL_string;
314     }
315   else
316     {
317       s = dup_char (((SCALAR *) e)->v.character);
318     }
319 
320   delete_scalar ((SCALAR *) e);
321   return (s);
322 }
323 
324 void *
memmove_forward(s,t,n)325 memmove_forward (s, t, n)
326      void *s;
327      void *t;
328      size_t n;
329 {
330   /*
331    * Copy `n' characters from `t' to `s', and return `s'.  This
332    * works if `t' and `s' overlap, provided that s>=t.
333    */
334 
335   assert (s && t && n > 0);
336 
337   while (n--)
338     ((char *) s)[n] = ((char *) t)[n];
339 
340   return (s);
341 }
342