Link with C++ linker
[oweals/cde.git] / cde / programs / dtksh / exksh_tbls.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: exksh_tbls.c /main/4 1995/11/01 15:54:33 rswiston $ */
24 /*      Copyright (c) 1991, 1992 UNIX System Laboratories, Inc. */
25 /*      All Rights Reserved     */
26
27 /*      THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF    */
28 /*      UNIX System Laboratories, Inc.                  */
29 /*      The copyright notice above does not evidence any       */
30 /*      actual or intended publication of such source code.    */
31
32 #include        "name.h" 
33 #include        "shell.h" 
34 #include "stdio.h"
35 #include <string.h>
36 #include <sys/types.h>
37 #include <ctype.h>
38 #include "exksh.h"
39 #include "exksh_tbls.h"
40 #include "exksh_prpar.h"
41 #include "docall.h"
42 #include "msgs.h"
43
44 int _Delim;
45 static int strglen;
46 static int struct_size;
47
48 int Pr_tmpnonames = 0;
49
50 static const char *Str_close_curly = "}";
51 static const char *Str_open_curly = "{";
52
53 #define MALMEMBERS      (4)     /* initial number of members of malloc'ed array to malloc */
54
55 #define UPPER(C) (islower(C) ? toupper(C) : (C))
56 #define isvarchar(C) (isalnum(C) || ((C) == '_'))
57
58 /*
59  * Some of our test programs use xk_parse() to parse cdata from command
60  * lines.  This has the drawback that anys or externals will get a malloc'ed
61  * buffer for their char * on the send side, which would not normally be
62  * freed, because xk_free() knows that such any's usually point into the
63  * ubuf rather than being malloced.  On the receive side, this would be
64  * true even in our test program.  So, on the send side, we keep a table
65  * of any any or external char * that is malloc'ed, and xk_free checks
66  * this table before free'ing the given item.  After being freed, the
67  * stack is decremented for efficiency.
68  */
69
70 #define ANYTBLINC       (4)
71
72 static char **Anytbl = NULL;
73 static int Nanytbl = 0;
74 static int Maxanytbl = 0;
75
76 struct special {
77         char *name;
78         int (*free)();
79         int (*parse)();
80         int (*print)();
81 };
82
83 #define SPEC_FREE       0
84 #define SPEC_PARSE      1
85 #define SPEC_PRINT      2
86
87 static struct special *Special = NULL;
88 static int Nspecs = 0;
89
90 static char **Dont = NULL;
91 static int Ndont, Sdont;
92
93 int
94 (*find_special(
95         int type,
96         char *name ))()
97 {
98         int i;
99
100         if (!Special)
101                 return(NULL);
102         for (i = 0; i < Nspecs; i++) {
103                 if (strcmp(Special[i].name, name) == 0) {
104                         switch(type) {
105                         case SPEC_PRINT:
106                                 return(Special[i].print);
107                         case SPEC_FREE:
108                                 return(Special[i].free);
109                         case SPEC_PARSE:
110                                 return(Special[i].parse);
111                         }
112                 }
113         }
114         return(NULL);
115 }
116
117 int
118 set_special(
119         char *name,
120         int (*free)(),
121         int (*parse)(),
122         int (*print)() )
123 {
124         int i;
125
126         for (i = 0; i < Nspecs; i++)
127                 if (strcmp(Special[i].name, name) == 0)
128                         break;
129         if (i == Nspecs) {
130                 if (!Special) {
131                         Special = (struct special *) malloc(sizeof(struct special));
132                         Special[0].name = strdup(name);
133                         Nspecs = 1;
134                 }
135                 else {
136                         Special = (struct special *) realloc(Special, (Nspecs + 1) * sizeof(struct special));
137                         Special[i].name = strdup(name);
138                         Nspecs++;
139                 }
140         }
141         if (!Special)
142                 return(FAIL);
143         Special[i].free = free;
144         Special[i].parse = parse;
145         Special[i].print = print;
146         return(SUCCESS);
147 }
148
149 /*
150  * xk_parse:  Takes a pointer to a structure member table, a pointer
151  * to a buffer containing an ascii representation of the structure
152  * represented by the table pointer, and the number of pointers saved
153  * from previous recursive calls to this routine, and parses the
154  * buf into p.
155  *
156  * Increments buf to the last point at which it read a character,
157  * and returns SUCCESS or FAIL.
158  */
159
160 int
161 xk_parse(
162         memtbl_t *tbl,
163         char **buf,
164         char *p,
165         int nptr,
166         int sub,
167         void *pass,
168         memtbl_t *(*tbl_find)() )
169 {
170         memtbl_t *ntbl;
171         register int i = 0;
172         int skind, delim_type;
173         long val = 0;           /* used for choice selection */
174         char *np;
175         int delim = _Delim;
176         int nmal;               /* number of members malloc'ed arrays */
177         char *pp;
178         int (*spec_parse)();
179         char * errmsg;
180
181         if (tbl == NULL) {
182                 if (_Prdebug)
183                 {
184                    errmsg=strdup(GETMESSAGE(8,1, 
185                        "xk_parse: A NULL 'type' table was specified\n"));
186                    fprintf(stderr, errmsg);
187                    free(errmsg);
188                 }
189                 return(FAIL);
190         }
191         xk_skipwhite(buf);
192         /*
193          * If this is supposed to be a pointer, and we have a string that
194          * starts with "P" and a number then we should take the pointer
195          * itself. This is done by stripping off the 'p' and parsing it as a
196          * unsigned long.
197          *
198          * Further, if it starts with an '&', then we want the address of
199          * a variable, use fsym() to find it.
200          */
201         if (((tbl->flags & F_TYPE_IS_PTR) || ((tbl->ptr + nptr) > 0)) &&
202                 (((UPPER((*buf)[0]) == 'P') && isdigit((*buf)[1])) || ((*buf)[0] == '&'))) {
203                 if ((*buf)[0] == '&') {
204                         char *start;
205
206                         (*buf)++;
207                         for (start = *buf; isvarchar(*buf[0]); (*buf)++)
208                                 ;
209                         if ((((unsigned long *) p)[0] = fsym(start, -1)) == NULL)
210                                 return(FAIL);
211                 }
212                 else {
213                         (*buf)++;
214                         RIF(xk_par_int(buf, (long *)p, pass));
215                 }
216                 if (Ndont == Sdont) {
217                         if (Dont)
218                                 Dont = (char **) realloc(Dont, (Sdont + 20) * sizeof(char *));
219                         else
220                                 Dont = (char **) malloc((Sdont + 20) * sizeof(char *));
221                         if (!Dont) {
222                            errmsg = strdup(GetSharedMsg(DT_ALLOC_FAILURE));
223                            ALTPUTS(errmsg);
224                            free(errmsg);
225                            exit(1);
226                         }
227                         Sdont += 20;
228                 }
229                 Dont[Ndont++] = ((char **) p)[0];
230                 return(SUCCESS);
231         }
232         if (tbl->tname && (spec_parse = find_special(SPEC_PARSE, tbl->tname)))
233                 return(spec_parse(tbl, buf, p, nptr, sub, pass, tbl_find));
234         if (tbl->name && (spec_parse = find_special(SPEC_PARSE, tbl->name)))
235                 return(spec_parse(tbl, buf, p, nptr, sub, pass, tbl_find));
236         nptr += tbl->ptr;
237         if (sub > 0 && tbl->subscr > 0) {
238                 if (_Prdebug)
239                 {
240                    errmsg=strdup(GETMESSAGE(8,2, 
241                          "xk_parse: Multiple array subscripts are not handled in '%s'\n"));
242                    fprintf(stderr, errmsg, tbl->name);
243                    free(errmsg);
244                 }
245                 return(FAIL);
246         }
247         /*
248          * If there is exactly one pointer associated with this
249          * member, and no length delimiters, and no subscripts,
250          * or there are multiple pointers,
251          * then malloc space for the structure and call ourself
252          * recursively.
253          */
254         if ((nptr > 1 && tbl->delim != 0) || (nptr == 1 && tbl->delim == 0 && tbl->subscr == 0)) {
255                 if (PARPEEK(buf, ",") || PARPEEK(buf, Str_close_curly)) {
256                         ((char **)p)[0] = NULL;
257                         if (_Prdebug)
258                         {
259                            errmsg=strdup(GetSharedMsg(DT_XK_PARSE_SET_NULL));
260                            fprintf(stderr, errmsg, tbl->name);
261                            free(errmsg);
262                         }
263                         return(SUCCESS);
264                 }
265                         if (xk_parpeek(buf, "NULL")) {
266                                 RIF(xk_parexpect(buf, "NULL"));
267                                 ((char **)p)[0] = NULL;
268                                 if (_Prdebug)
269                                 {
270                                    errmsg=strdup(GetSharedMsg(
271                                                  DT_XK_PARSE_SET_NULL));
272                                    fprintf(stderr, errmsg, tbl->name);
273                                    free(errmsg);
274                                 }
275                                 return(SUCCESS);
276                         }
277
278                 if ((((char **)p)[0] = malloc(tbl->size)) == NULL) {
279                         return(FAIL);
280                 }
281                 if (_Prdebug)
282                 {
283                    errmsg=strdup(GETMESSAGE(8,3, 
284                         "xk_parse: Setting '%s' to malloc'ed address 0x%x, of size %d\n"));
285                    fprintf(stderr,errmsg,tbl->name, ((char **)p)[0], tbl->size);
286                    free(errmsg);
287                 }
288                 return(xk_parse(tbl, buf, ((char **)p)[0], nptr-1-tbl->ptr, sub, pass, tbl_find));
289         }
290         /*
291          * If there is exactly one pointer level, or one subscripting level,
292          * and there is a delimiter,
293          * and no subscript, then we are a length delimited malloced array.
294          */
295         xk_skipwhite(buf);
296         if (tbl->delim != 0 && ((nptr == 1 && tbl->subscr == 0) ||
297                 (nptr == 0 && tbl->subscr != 0 && tbl->kind != K_STRING))) {
298
299                 if (tbl->subscr == 0) {
300                         if (PARPEEK(buf, ",") || PARPEEK(buf, Str_close_curly)) {
301                                 ((char **)p)[0] = NULL;
302                                 if (_Prdebug)
303                                 {
304                                    errmsg=strdup(GETMESSAGE(8,4, 
305                                      "xk_parse: Setting malloc'ed array '%s' to NULL\n"));
306                                    fprintf(stderr, errmsg, tbl->name);
307                                    free(errmsg);
308                                 }
309                                 return(SUCCESS);
310                         }
311                         if (xk_parpeek(buf, "NULL")) {
312                                 RIF(xk_parexpect(buf, "NULL"));
313                                 ((char **)p)[0] = NULL;
314                                 if (_Prdebug)
315                                 {
316                                    errmsg=strdup(GetSharedMsg(
317                                                     DT_XK_PARSE_SET_NULL));
318                                    fprintf(stderr, errmsg, tbl->name);
319                                    free(errmsg);
320                                 }
321                                 return(SUCCESS);
322                         }
323                         nmal = MALMEMBERS;
324                         if ((np = malloc(nmal*tbl->size)) == NULL) {
325                                 return(FAIL);
326                         }
327                         ((char **)p)[0] = np;
328                         if (_Prdebug)
329                         {
330                            errmsg=strdup(GETMESSAGE(8,5, 
331                                 "xk_parse: Setting member '%s' to malloc'ed pointer 0x%x, of size %d\n"));
332                            fprintf(stderr, errmsg, tbl->name, np, 4*tbl->size);
333                            free(errmsg);
334                         }
335                 } else {
336                         np = p;
337                 }
338                 xk_skipwhite(buf);
339                 RIF(PAREXPECT(buf, Str_open_curly));
340                 *buf += 1;
341                 i = 0;
342                 xk_skipwhite(buf);
343                 while (PARPEEK(buf, Str_close_curly) == FALSE) {
344                         if (tbl->subscr == 0 && i >= nmal) {
345                                 nmal += MALMEMBERS;
346                                 if((np = realloc(np, nmal*tbl->size)) == NULL) {
347                                         return(FAIL);
348                                 }
349                                 ((char **)p)[0] = np;
350                                 if (_Prdebug) {
351                                    errmsg=strdup(GetSharedMsg(
352                                              DT_XK_PARSE_ARRAY_OVERFLOW));
353                                    fprintf(stderr, errmsg, tbl->name, nmal, nmal*tbl->size);
354                                    free(errmsg);
355                                 }
356                         } else if (tbl->subscr > 0 && i > tbl->subscr) {
357                                 if (_Prdebug)
358                                 {
359                                    errmsg=strdup(GETMESSAGE(8,6, 
360                                           "xk_parse: The array '%s' overflowed at element number %d\n"));
361                                    fprintf(stderr, errmsg, tbl->name, i);
362                                    free(errmsg);
363                                 }
364                         }
365                         if (_Prdebug)
366                         {
367                            errmsg=strdup(GETMESSAGE(8,7, 
368                                  "xk_parse: Parsing array element [%d] of '%s' into address 0x%x\n"));
369                            fprintf(stderr, errmsg, i, tbl->name, &np[i*tbl->size]);
370                            free(errmsg);
371                         }
372                         if (i) {
373                                 xk_skipwhite(buf);
374                                 if (PARPEEK(buf, ",") == FALSE) {
375                                         if (PARPEEK(buf, Str_close_curly) == FALSE) {
376                                                 RIF(PAREXPECT(buf, ","));
377                                                 *buf += 1;
378                                         }
379                                 }
380                                 else {
381                                         RIF(PAREXPECT(buf, ","));
382                                         *buf += 1;
383                                 }
384                         }
385                         RIF(xk_parse(tbl, buf, &np[i*tbl->size], nptr ? -1 : 0,
386                                      0, (void *)-1, tbl_find));
387                         i++;
388                         struct_size = i;
389                         xk_skipwhite(buf);
390                 }
391                 RIF(PAREXPECT(buf, Str_close_curly));
392                 *buf += 1;
393                 return(SUCCESS);
394         }
395         /*
396          * If there is no delimiter, and there are two levels of pointer,
397          * then we are a NULL terminated array of pointers
398          */
399         if (tbl->delim == 0 &&
400                 ((nptr == 2 && sub == 0) || (sub == 1 && nptr == 1))) {
401                 /*
402                  * malloc a few members, realloc as needed
403                  */
404                 nmal = MALMEMBERS;
405                 if ((((char **)p)[0] = malloc(nmal*tbl->size)) == NULL) {
406                         return(FAIL);
407                 }
408                 xk_skipwhite(buf);
409                 RIF(PAREXPECT(buf, Str_open_curly));
410                 *buf += 1;
411                 xk_skipwhite(buf);
412                 while (PARPEEK(buf, Str_close_curly) == FALSE) {
413                         if (i >= nmal) {
414                                 nmal += MALMEMBERS;
415                                 if ((((char **)p)[0] = realloc(((char **)p)[0], nmal*tbl->size)) == NULL) {
416                                         return(FAIL);
417                                 }
418                                 if (_Prdebug) {
419                                    errmsg=strdup(GetSharedMsg(
420                                                DT_XK_PARSE_ARRAY_OVERFLOW));
421                                    fprintf(stderr, errmsg, tbl->name, nmal, nmal*tbl->size);
422                                    free(errmsg);
423                                 }
424                         }
425                         if (_Prdebug)
426                         {
427                            errmsg=strdup(GETMESSAGE(8,8, 
428                              "xk_parse: Parsing array element [%d] of '%s'\n"));
429                            fprintf(stderr, errmsg, i, tbl->name);
430                            free(errmsg);
431                         }
432                         if (i) {
433                                 RIF(PAREXPECT(buf, ","));
434                                 *buf += 1;
435                         }
436                         RIF(xk_parse(tbl, buf, &p[i*tbl->size], 
437                                      nptr == 2 ? -2 : -1, 0, (void *)-1, 
438                                      tbl_find));
439
440                         xk_skipwhite(buf);
441                 }
442                 RIF(PAREXPECT(buf, Str_close_curly));
443                 *buf++;
444                 ((char **)p)[i*tbl->size] = NULL;
445                 return(SUCCESS);
446         }
447
448         switch(tbl->kind) {
449         case K_CHAR:
450                 RIF(xk_par_int(buf, &val, pass));
451                 ((unsigned char *)p)[0] = val;
452                 break;
453         case K_SHORT:
454                 RIF(xk_par_int(buf, &val, pass));
455                 ((ushort *)p)[0] = val;
456                 break;
457         case K_INT:
458                 RIF(xk_par_int(buf, &val, pass));
459                 ((int *)p)[0] = val;
460                 break;
461         case K_LONG:
462                 RIF(xk_par_int(buf, (long *)p, pass));
463                 break;
464         case K_STRING:
465                 if (tbl->subscr) {
466                         val = tbl->subscr;
467                         RIF(xk_par_chararr(buf, (char *)p, (int *)&val));
468                         if (tbl->delim <= 0 && val > -1) {
469                                 p[val] = '\0';
470                         }
471                 } else {
472                         val = 0;
473                         RIF(xk_par_charstr(buf, (char **)p, (int *)&val));
474                         /* If this is not a delimited char string,
475                          * then it must be null terminated
476                          */
477                         if (tbl->delim <= 0 && val > -1) {
478                                 ((char **) p)[0][val] = '\0';
479                         }
480                         strglen = val;
481                 }
482                 break;
483         case K_TYPEDEF:
484                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
485                 RIF(xk_parse(ntbl, buf, p, nptr, 0, pass, tbl_find));
486                 return(SUCCESS);
487         case K_STRUCT:
488                 xk_skipwhite(buf);
489                 RIF(PAREXPECT(buf, Str_open_curly));
490                 *buf += 1;
491                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
492                 pp = NULL;
493                 for (i = 0; ntbl[i].name != NULL; i++) {
494                         _Delim = xk_get_pardelim(&ntbl[i], p);
495                         if (ntbl[i].kind >= K_DSHORT) {
496                                 skind = ntbl[i].kind;
497                                 pp = p + ntbl[i].offset;
498                                 struct_size = 0;
499                         }
500                         if (ntbl[i].delim) {
501                                 delim_type = ntbl[i].kind;
502                         }
503                         if (i && ntbl[i-1].kind < K_DSHORT) {
504                                 xk_skipwhite(buf);
505                                 if (PARPEEK(buf, ",") == FALSE) {
506                                         if (PARPEEK(buf, Str_close_curly) == FALSE) {
507                                                 RIF(PAREXPECT(buf, ","));
508                                                 *buf += 1;
509                                         }
510                                 }
511                                 else  {
512                                         RIF(PAREXPECT(buf, ","));
513                                         *buf += 1;
514                                 }
515                         }
516                         if (_Prdebug)
517                         {
518                            errmsg=strdup(GETMESSAGE(8,9, 
519                               "xk_parse: Parsing member '%s' into location 0x%x\n"));
520                            fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
521                            free(errmsg);
522                         }
523                         if (xk_parse(&ntbl[i], buf, p+ntbl[i].offset, nptr, sub, pass, tbl_find) == FAIL) {
524                                 if (_Prdebug)
525                                 {
526                                    errmsg=strdup(GetSharedMsg(
527                                                     DT_XK_PARSE_ERROR));
528                                    fprintf(stderr, errmsg, ntbl[i].name);
529                                    free(errmsg);
530                                 }
531                                 return(FAIL);
532                         }
533                 }
534                 if (pp != NULL) {
535                         switch(skind) {
536                                 case K_DSHORT:
537                                         if (delim_type == K_STRING)
538                                                 ((short *)pp)[0] = strglen;
539                                         else
540                                                 ((short *)pp)[0] = struct_size;
541                                         break;
542                                 case K_DINT:
543                                         if (delim_type == K_STRING)
544                                                 ((int *)pp)[0] = strglen;
545                                         else
546                                                 ((int *)pp)[0] = struct_size;
547                                         break;
548                                 case K_DLONG:
549                                         if (delim_type == K_STRING)
550                                                 ((long *)pp)[0] = strglen;
551                                         else
552                                                 ((long *)pp)[0] = struct_size;
553                                         break;
554                                 default:
555                                         break;
556                         }
557                 }
558                 xk_skipwhite(buf);
559                 RIF(PAREXPECT(buf, Str_close_curly));
560                 *buf += 1;
561                 break;
562         case K_UNION:
563                 if (strncmp(tbl[-1].name, "ch_", 3) != 0) {
564                         if (_Prdebug)
565                         {
566                            errmsg=strdup(GETMESSAGE(8,10, 
567                             "xk_parse: Cannot determine the choice in '%s'\n"));
568                            fprintf(stderr, errmsg, tbl->name);
569                            free(errmsg);
570                         }
571                         return(FAIL);
572                 }
573                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
574                 xk_skipwhite(buf);
575                 RIF(PAREXPECT(buf, Str_open_curly));
576                 *buf += 1;
577                 for (i = 0; ntbl[i].name != NULL; i++) {
578                         if (xk_parpeek(buf, ntbl[i].name) == TRUE) {
579                                 RIF(xk_parexpect(buf, ntbl[i].name));
580                                 ((long *)(p - sizeof(long)))[0] = ntbl[i].choice;
581                                 if (_Prdebug)
582                                 {
583                                    errmsg=strdup(GETMESSAGE(8,11, 
584                                        "xk_parse: Parsing union member '%s' into location 0x%x\n"));
585                                    fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
586                                    free(errmsg);
587                                 }
588                                 if (xk_parse(&ntbl[i], buf, p, nptr, sub, pass, tbl_find) == FAIL) {
589                                    if (_Prdebug)
590                                    {
591                                       errmsg=strdup(GetSharedMsg(
592                                                      DT_XK_PARSE_ERROR));
593                                       fprintf(stderr, errmsg, ntbl[i].name);
594                                       free(errmsg);
595                                    }
596                                    return(FAIL);
597                                 }
598                                 break;
599                         }
600                 }
601                 xk_skipwhite(buf);
602                 RIF(PAREXPECT(buf, Str_close_curly));
603                 *buf += 1;
604                 break;
605         case K_DSHORT:
606         case K_DINT:
607         case K_DLONG:
608                 break;
609         default:
610                 return(FAIL);
611         }
612         return(SUCCESS);
613 }
614
615 int
616 xk_get_delim(
617         memtbl_t *tbl,
618         char *p )
619 {
620         memtbl_t *dtbl = &tbl[tbl->delim];
621         char * errmsg;
622
623         if (tbl->delim == 0) {
624                 return(-1);
625         }
626         if (_Prdebug)
627         {
628            errmsg=strdup(GETMESSAGE(8,12, 
629                  "xk_get_delim: The delimiter for field '%s' is field '%s'\n"));
630            fprintf(stderr, errmsg, tbl->name, dtbl->name);
631            free(errmsg);
632         }
633         p += dtbl->offset;
634         switch (dtbl->kind) {
635         case K_DLONG:
636         case K_LONG:
637                 return(((long *)p)[0]);
638         case K_CHAR:
639                 return(((char *)p)[0]);
640         case K_DSHORT:
641         case K_SHORT:
642                 return(((short *)p)[0]);
643         case K_DINT:
644         case K_INT:
645                 return(((int *)p)[0]);
646         default:
647            if (_Prdebug)
648            {
649               errmsg=strdup(GETMESSAGE(8,13, 
650                   "xk_get_delim: Cannot find a delimiter value in '%s'\n"));
651               fprintf(stderr, errmsg, tbl->name);
652               free(errmsg);
653            }
654            return(0);
655         }
656 }
657
658
659 int
660 xk_get_pardelim(
661         memtbl_t *tbl,
662         char *p )
663 {
664         memtbl_t *dtbl = &tbl[tbl->delim];
665         char * errmsg;
666
667         if (tbl->delim == 0) {
668                 return(-1);
669         }
670         if (_Prdebug)
671         {
672            errmsg=strdup(GETMESSAGE(8,14, 
673               "xk_get_pardelim: The delimiter for field '%s' is field '%s'\n"));
674            fprintf(stderr, errmsg, tbl->name, dtbl->name);
675            free(errmsg);
676         }
677         p += dtbl->offset;
678         switch (dtbl->kind) {
679            case K_DLONG:
680                 return(-1);
681            case K_LONG:
682                 return(((long *)p)[0]);
683            case K_DSHORT:
684                 return(-1);
685            case K_CHAR:
686                 return(((char *)p)[0]);
687            case K_SHORT:
688                 return(((short *)p)[0]);
689            case K_DINT:
690                 return(-1);
691            case K_INT:
692                 return(((int *)p)[0]);
693            default:
694            if (_Prdebug)
695            {
696               errmsg=strdup(GETMESSAGE(8,15, 
697                  "xk_get_pardelim: Cannot find a delimiter value in '%s'\n"));
698               fprintf(stderr, errmsg, tbl->name);
699               free(errmsg);
700            }
701            return(0);
702         }
703 }
704
705 /*
706  * xk_print:  Takes a pointer to a structure member table, a pointer
707  * to a buffer big enough to hold an ascii representation of the structure
708  * represented by the table pointer, and a pointer to a structure to
709  * be filled in, and the number of pointers saved
710  * from previous recursive calls to this routine, and prints the
711  * buf into p.
712  *
713  * Increments buf to the last point at which it wrote a character,
714  * and returns SUCCESS or FAIL.
715  */
716
717
718 int
719 xk_print(
720         memtbl_t *tbl,
721         char **buf,
722         char *p,
723         int nptr,
724         int sub,
725         void *pass,
726         memtbl_t *(*tbl_find)() )
727 {
728         memtbl_t *ntbl;
729         register int i;
730         long val;               /* used for choice selection */
731         char *np;
732         int delim = _Delim;
733         int (*spec_print)();
734         char * errmsg;
735
736         if (p == NULL) {
737                 *buf += lsprintf(*buf, "NULL");
738                 return(SUCCESS);
739         }
740         if (tbl == NULL) {
741                 if (_Prdebug)
742                 {
743                    errmsg=strdup(GETMESSAGE(8,16, 
744                        "xk_print: A NULL 'type' table was specified\n"));
745                    fprintf(stderr, errmsg);
746                    free(errmsg);
747                 }
748                 return(FAIL);
749         }
750         if (tbl->tname && (spec_print = find_special(SPEC_PRINT, tbl->tname)))
751                 return(spec_print(tbl, buf, p, nptr, sub, pass, tbl_find));
752         if (tbl->name && (spec_print = find_special(SPEC_PRINT, tbl->name)))
753                 return(spec_print(tbl, buf, p, nptr, sub, pass, tbl_find));
754         nptr += tbl->ptr;
755         if (sub > 0 && tbl->subscr > 0) {
756            if (_Prdebug)
757            {
758               errmsg=strdup(GETMESSAGE(8,17, 
759               "xk_print: Multiple array subscripts are not handled in '%s'\n"));
760               fprintf(stderr, errmsg, tbl->name);
761               free(errmsg);
762            }
763            return(FAIL);
764         }
765         /*
766          * If there is exactly one pointer associated with this
767          * member, and no length delimiters, and no subscripts,
768          * or there are multiple pointers,
769          * then dereference the structure and call ourself
770          * recursively.
771          */
772         if ((nptr > 1 && tbl->delim != 0) || (nptr == 1 && tbl->delim == 0 && tbl->subscr == 0)) {
773                 if (_Prdebug)
774                 {
775                    errmsg=strdup(GETMESSAGE(8,18, 
776                           "xk_print: Dereferencing '%s' to address 0x%x\n"));
777                    fprintf(stderr, errmsg, tbl->name, ((char **)p)[0]);
778                    free(errmsg);
779                 }
780                 return(xk_print(tbl, buf, ((char **)p)[0], nptr-1-tbl->ptr, sub, pass, tbl_find));
781         }
782         /*
783          * If there is exactly one pointer level, or one subscripting level,
784          * and there is a delimiter,
785          * and no subscript, then we are a length delimited array.
786          */
787         if (tbl->delim != 0 && ((nptr == 1 && tbl->subscr == 0) ||
788                 nptr == 0 && tbl->subscr != 0 && tbl->kind != K_STRING)) {
789
790                 if (_Prdebug)
791                 {
792                    errmsg=strdup(GETMESSAGE(8,19, 
793                              "xk_print: The delimiter for '%s' is %d\n"));
794                    fprintf(stderr, errmsg, tbl->name, delim);
795                    free(errmsg);
796                 }
797                 if (tbl->subscr == 0) {
798                         np = ((char **)p)[0];
799                         if (_Prdebug)
800                         {
801                            errmsg=strdup(GETMESSAGE(8,20, 
802                              "xk_print: Using the pointer 0x%x as an array\n"));
803                            fprintf(stderr, errmsg, np);
804                            free(errmsg);
805                         }
806                 } else {
807                         np = p;
808                 }
809                 if (np == NULL) {
810                         *buf += lsprintf(*buf, "NULL");
811                         return(SUCCESS);
812                 }
813                 *buf += lsprintf(*buf, Str_open_curly);
814                 for (i = 0; i < delim; i++) {
815                         if (_Prdebug)
816                         {
817                            errmsg=strdup(GETMESSAGE(8,21, 
818                                   "xk_print: Printing array level %d of member '%s' at location 0x%x\n"));
819                            fprintf(stderr, errmsg, i, tbl->name, &np[i*tbl->size]);
820                            free(errmsg);
821                         }
822                         if (i)
823                                 *buf += lsprintf(*buf, ", ");
824                         RIF(xk_print(tbl, buf, &np[i*tbl->size], nptr ? -1 : 0,
825                             0, (void *)-1, tbl_find));
826                 }
827                 *buf += lsprintf(*buf, Str_close_curly);
828                 return(SUCCESS);
829         }
830         /*
831          * If there is no delimiter, and there are two levels of pointer,
832          * then we are a NULL terminated array.
833          */
834         if (tbl->delim == 0 &&
835                 ((nptr == 2 && sub == 0) || (sub == 1 && nptr == 1))) {
836                 *buf += lsprintf(*buf, Str_open_curly);
837                 for (i = 0; ((char **)p)[i*tbl->size] != NULL; i++) {
838                         if (i)
839                                 *buf += lsprintf(*buf, ", ");
840                         if (_Prdebug)
841                         {
842                            errmsg=strdup(GETMESSAGE(8,22, 
843                                "xk_print: Printing array level %d of member '%s'\n"));
844                            fprintf(stderr, errmsg, i, tbl->name);
845                            free(errmsg);
846                         }
847                         RIF(xk_print(tbl, buf, ((char **)p)[i*tbl->size], 
848                                      nptr-(!sub), 0, (void *)-1, tbl_find));
849                 }
850                 *buf += lsprintf(*buf, Str_close_curly);
851                 return(SUCCESS);
852         }
853
854         if (!Pr_tmpnonames && (Pr_format & PRNAMES)) {
855                 switch(tbl->kind) {
856                 case K_CHAR:
857                 case K_SHORT:
858                 case K_INT:
859                 case K_LONG:
860                 case K_STRING:
861                         *buf += lsprintf(*buf, "%s=", tbl->name);
862                 }
863         }
864         switch(tbl->kind) {
865         case K_CHAR:
866         case K_SHORT:
867         case K_INT:
868         case K_LONG:
869                 RIF(xk_prin_int(tbl, buf, (unsigned long *)p));
870                 break;
871         case K_STRING:
872                 if (delim > 0) {
873                         if (tbl->subscr) {
874                                 RIF(xk_prin_hexstr(buf, (char *)p, delim));
875                         } else {
876                                 RIF(xk_prin_hexstr(buf, ((char **)p)[0], delim));
877                         }
878                 } else {
879                         if (tbl->subscr) {
880                                 RIF(xk_prin_nts(buf, (char *)p));
881                         } else {
882                                 RIF(xk_prin_nts(buf, ((char **)p)[0]));
883                         }
884                 }
885                 break;
886         case K_TYPEDEF:
887                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
888                 return(xk_print(ntbl, buf, p, nptr, 0, pass, tbl_find));
889         case K_STRUCT:
890                 *buf += lsprintf(*buf, Str_open_curly);
891                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
892                 for (i = 0; ntbl[i].name != NULL; i++) {
893                         _Delim = xk_get_delim(&ntbl[i], p);
894                         if (_Prdebug)
895                         {
896                            errmsg=strdup(GETMESSAGE(8,23, 
897                               "xk_print: Printing member '%s' at location 0x%x\n"));
898                            fprintf(stderr, errmsg, ntbl[i].name, p+ntbl[i].offset);
899                            free(errmsg);
900                         }
901                         RIF(xk_print(&ntbl[i], buf, p+ntbl[i].offset, nptr, sub, pass, tbl_find));
902                         if (ntbl[i].kind < K_DSHORT && ntbl[i+1].name != NULL)
903                                 *buf += lsprintf(*buf, ", ");
904                 }
905                 *buf += lsprintf(*buf, Str_close_curly);
906                 break;
907         case K_UNION:
908                 if (strncmp(tbl[-1].name, "ch_", 3) != 0) {
909                         if (_Prdebug)
910                         {
911                            errmsg=strdup(GETMESSAGE(8,24, 
912                             "xk_print: Cannot determine the choice in '%s'\n"));
913                            fprintf(stderr, errmsg, tbl->name);
914                            free(errmsg);
915                         }
916                         return(FAIL);
917                 }
918                 val = *((long *)(p - sizeof(long)));
919                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
920                 *buf += lsprintf(*buf, Str_open_curly);
921                 for (i = 0; ntbl[i].name != NULL; i++) {
922                         if (ntbl[i].choice == val) {
923                                 *buf += lsprintf(*buf, "%s ", ntbl[i].name);
924                                 if (_Prdebug)
925                                 {
926                                    errmsg=strdup(GETMESSAGE(8,25, 
927                                       "xk_print: Printing union member '%s' into location 0x%x\n"));
928                                    fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
929                                    free(errmsg);
930                                 }
931                                 RIF(xk_print(&ntbl[i], buf, p, nptr, sub, pass, tbl_find));
932                                 break;
933                         }
934                 }
935                 *buf += lsprintf(*buf, Str_close_curly);
936                 break;
937         case K_DSHORT:
938         case K_DINT:
939         case K_DLONG:
940                 break;
941         default:
942                 return(FAIL);
943         }
944         return(SUCCESS);
945 }
946
947 /*
948  * xk_free:  Takes a pointer to a structure member table, and
949  * free any malloc'ec elements in it at all levels.
950  * Returns SUCCESS or FAIL.
951  *
952  * Contains an optimization that if a structure or union contains a
953  * type that is a simple type and nptr is zero, does not do a recursive call.
954  */
955
956 int
957 xk_free(
958         memtbl_t *tbl,
959         char *p,
960         int nptr,
961         int sub,
962         memtbl_t *(*tbl_find)() )
963 {
964         memtbl_t *ntbl;
965         register int i;
966         long val;               /* used for choice selection */
967         char *np;
968         int delim = _Delim;
969         int (*spec_free)();
970         char * errmsg;
971
972         if (tbl == NULL) {
973                 if (_Prdebug)
974                 {
975                    errmsg=strdup(GETMESSAGE(8,26, 
976                        "xk_free: A NULL 'type' table was specified\n"));
977                    fprintf(stderr, errmsg);
978                    free(errmsg);
979                 }
980                 return(FAIL);
981         }
982         if (tbl->tname && (spec_free = find_special(SPEC_FREE, tbl->tname)))
983                 return(spec_free(tbl, p, nptr, sub, tbl_find));
984         if (tbl->name && (spec_free = find_special(SPEC_FREE, tbl->name)))
985                 return(spec_free(tbl, p, nptr, sub, tbl_find));
986         nptr += tbl->ptr;
987         if ((tbl->flags & F_TYPE_IS_PTR) || (nptr > 0)) {
988                 for (i = Ndont - 1; i >= 0; i--) {
989                         if (Dont[i] == ((char **) p)[0]) {
990                                 for ( ; i < Ndont - 1; i++)
991                                         Dont[i] = Dont[i + 1];
992                                 Ndont--;
993                                 return(SUCCESS);
994                         }
995                 }
996         }
997         if (sub > 0 && tbl->subscr > 0) {
998                 if (_Prdebug)
999                 {
1000                    errmsg=strdup(GETMESSAGE(8,27, 
1001                        "xk_free: Multiple array subscripts are not handled in '%s'\n"));
1002                    fprintf(stderr, errmsg, tbl->name);
1003                    free(errmsg);
1004                 }
1005                 return(FAIL);
1006         }
1007         /*
1008          * If there is exactly one pointer associated with this
1009          * member, and no length delimiters, and no subscripts,
1010          * or there are multiple pointers,
1011          * then recursively call ourselves on the structure, then
1012          * free the structure itself.
1013          */
1014         if ((nptr > 1 && tbl->delim != 0) || (nptr == 1 && tbl->delim == 0 && tbl->subscr == 0)) {
1015                 if (((char **)p)[0] != NULL) {
1016                         RIF(xk_free(tbl, ((char **)p)[0], nptr-1-tbl->ptr, sub, tbl_find));
1017                         free(((char **)p)[0]);
1018                         if (_Prdebug)
1019                         {
1020                            errmsg=strdup(GETMESSAGE(8,28, 
1021                                   "xk_free: The member '%s' at location 0x%x was freed and set to NULL\n"));
1022                            fprintf(stderr, errmsg, tbl->name, ((char **)p)[0]);
1023                            free(errmsg);
1024                         }
1025                         ((char **)p)[0] = NULL;
1026                 } else {
1027                         if (_Prdebug)
1028                         {
1029                            errmsg=strdup(GETMESSAGE(8,29, 
1030                               "xk_free: The member '%s' is NULL; no free occurred\n"));
1031                            fprintf(stderr, errmsg, tbl->name);
1032                            free(errmsg);
1033                         }
1034                 }
1035                 return(SUCCESS);
1036         }
1037         /*
1038          * If there is exactly one pointer level, or one subscripting level,
1039          * and there is a delimiter,
1040          * and no subscript, then we are a length delimited malloced array.
1041          * Free each element, then free the whole array.
1042          */
1043         if (tbl->delim != 0 && ((nptr == 1 && tbl->subscr == 0) ||
1044                 nptr == 0 && tbl->subscr != 0 && tbl->kind != K_STRING)) {
1045                 if (_Prdebug)
1046                 {
1047                    errmsg=strdup(GETMESSAGE(8,30, 
1048                             "xk_free: The delimiter for '%s' is %d\n"));
1049                    fprintf(stderr, errmsg, tbl->name, delim);
1050                    free(errmsg);
1051                 }
1052                 if (tbl->subscr == 0)
1053                         np = ((char **)p)[0];
1054                 else
1055                         np = p;
1056                 for (i = 0; i < delim; i++) {
1057                         if (_Prdebug)
1058                         {
1059                            errmsg=strdup(GETMESSAGE(8,31, 
1060                                 "xk_free: Freeing array element [%d] of '%s' at address 0x%x\n"));
1061                            fprintf(stderr, errmsg, i, tbl->name, &np[i*tbl->size]);
1062                            free(errmsg);
1063                         }
1064                         RIF(xk_free(tbl, &np[i*tbl->size], nptr ? -1 : 0, 0, tbl_find));
1065                 }
1066                 if (tbl->subscr == 0) {
1067                         if (np != NULL) {
1068                                 if (_Prdebug)
1069                                 {
1070                                    errmsg=strdup(GETMESSAGE(8,32, 
1071                                        "xk_free: Freeing pointer to array of '%s' at location 0x%x and setting to NULL\n"));
1072                                    fprintf(stderr, errmsg, tbl->name, np);
1073                                    free(errmsg);
1074                                 }
1075                                 free(np);
1076                                 if (tbl->subscr == 0)
1077                                         ((char **)p)[0] = NULL;
1078                         } else if (_Prdebug) {
1079                            errmsg=strdup(GETMESSAGE(8,33, 
1080                                  "xk_free: The pointer to array of '%s'is NULL; no free occurred\n"));
1081                            fprintf(stderr, errmsg, tbl->name);
1082                            free(errmsg);
1083                         }
1084                 }
1085                 return(SUCCESS);
1086         }
1087
1088         switch(tbl->kind) {
1089         case K_DSHORT:
1090         case K_SHORT:
1091         case K_DINT:
1092         case K_INT:
1093         case K_DLONG:
1094         case K_LONG:
1095                 break;
1096         case K_STRING:
1097                 if (!tbl->subscr) {
1098                         if (((char **)p)[0] != NULL) {
1099                                 if (_Prdebug)
1100                                 {
1101                                    errmsg=strdup(GETMESSAGE(8,34, 
1102                                       "xk_free: Freeing string '%s' at location 0x%x, and setting to NULL\n"));
1103                                    fprintf(stderr, errmsg, tbl->name, p);
1104                                    free(errmsg);
1105                                 }
1106                                 free(((char **)p)[0]);
1107                                 ((char **)p)[0] = NULL;
1108                         } else if (_Prdebug) {
1109                            errmsg=strdup(GETMESSAGE(8,35, 
1110                                  "xk_free: The string '%s' is NULL; no free occurred\n"));
1111                            fprintf(stderr, errmsg, tbl->name, p);
1112                            free(errmsg);
1113                         }
1114                 }
1115                 break;
1116         case K_TYPEDEF:
1117                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
1118                 return(xk_free(ntbl, p, nptr, 0, tbl_find));
1119         case K_STRUCT:
1120                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
1121                 for (i = 0; ntbl[i].name != NULL; i++) {
1122                         if ((ntbl[i].flags & F_SIMPLE) && nptr+ntbl[i].ptr == 0) {
1123                                 if (_Prdebug)
1124                                 {
1125                                    errmsg=strdup(GetSharedMsg(
1126                                                   DT_XK_FREE_NO_MEMBER));
1127                                    fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
1128                                    free(errmsg);
1129                                 }
1130                                 continue;
1131                         }
1132                         _Delim = xk_get_delim(&ntbl[i], p);
1133                         if (_Prdebug)
1134                         {
1135                            errmsg=strdup(GETMESSAGE(8,36, 
1136                             "xk_free: Freeing member '%s' at location 0x%x\n"));
1137                            fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
1138                            free(errmsg);
1139                         }
1140                         if (xk_free(&ntbl[i], p+ntbl[i].offset, nptr, sub, tbl_find) == FAIL) {
1141                            if (_Prdebug)
1142                            {
1143                               errmsg=strdup(GETMESSAGE(8,37, 
1144                                  "xk_free: A failure occurred while freeing the '%s' member\n"));
1145                               fprintf(stderr, errmsg, ntbl[i].name);
1146                               free(errmsg);
1147                            }
1148                            return(FAIL);
1149                         }
1150                 }
1151                 break;
1152         case K_UNION:
1153                 if (strncmp(tbl[-1].name, "ch_", 3) != 0) {
1154                         if (_Prdebug)
1155                         {
1156                            errmsg=strdup(GETMESSAGE(8,38, 
1157                              "xk_free: Cannot determine the choice in '%s'\n"));
1158                            fprintf(stderr, errmsg, tbl->name);
1159                            free(errmsg);
1160                         }
1161                         return(FAIL);
1162                 }
1163                 val = *((long *)(p - sizeof(long)));
1164                 ntbl = tbl_find(tbl->tname, tbl->tbl, tbl->id);
1165                 for (i = 0; ntbl[i].name != NULL; i++) {
1166                         if (ntbl[i].choice == val) {
1167                                 if ((ntbl[i].flags & F_SIMPLE) && nptr+ntbl[i].ptr == 0) {
1168                                         if (_Prdebug)
1169                                         {
1170                                            errmsg=strdup(GetSharedMsg(
1171                                                       DT_XK_FREE_NO_MEMBER));
1172                                            fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
1173                                            free(errmsg);
1174                                         }
1175                                         continue;
1176                                 }
1177                                 if (_Prdebug)
1178                                 {
1179                                    errmsg=strdup(GETMESSAGE(8,39, 
1180                                       "xk_free: Freeing union member '%s' at location 0x%x\n"));
1181                                    fprintf(stderr, errmsg, ntbl[i].name, p + ntbl[i].offset);
1182                                    free(errmsg);
1183                                 }
1184                                 RIF(xk_free(&ntbl[i], p, nptr, sub, tbl_find));
1185                                 break;
1186                         }
1187                 }
1188                 if (ntbl[i].name == NULL && _Prdebug)
1189                         if (_Prdebug)
1190                         {
1191                            errmsg=strdup(GETMESSAGE(8,40, 
1192                                "xk_free: There is no legal union choice for '%s' (value is 0x%x); no free occurred\n"));
1193                            fprintf(stderr, errmsg, tbl->name, val);
1194                            free(errmsg);
1195                         }
1196                 break;
1197         default:
1198                 return(FAIL);
1199         }
1200         return(SUCCESS);
1201 }