Link with C++ linker
[oweals/cde.git] / cde / programs / dtksh / docall.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 /* $TOG: docall.c /main/7 1998/04/17 11:22:59 mgreess $ */
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 "stdio.h"
33 #include "exksh.h" /* which includes sys/types.h */
34 #include "docall.h"
35 #include <sys/param.h>
36 #include <string.h>
37 #include <search.h>
38 #include <ctype.h>
39 #include "struct.h"
40 #include "misc.h"
41 #include "exksh_tbls.h"
42 #include "basetbl.h"
43 #include "msgs.h"
44
45 #include <X11/Xosdefs.h>
46 #include <errno.h>
47 #ifdef X_NOT_STDC_ENV
48 extern int errno;
49 #endif
50
51 static int allprint( 
52                         unsigned long *pargs,
53                         memtbl_t *tbls) ;
54 static pp_usage( void ) ;
55 static int call_postprompt( 
56                         char * argv0,
57                         unsigned long *pargs,
58                         memtbl_t *tbls,
59                         int *freeit) ;
60 static long get_prdebug( void ) ;
61 static long set_prdebug( 
62                         long n) ;
63 static int myprompt( 
64                         char *prompt) ;
65
66
67
68 struct memtbl Null_tbl = { NULL };
69
70 static char use[] = "0x%x";
71 static char use2[] = "%s=0x%x";
72
73 int Xk_errno = 0;
74
75 int Xkdebug = 0;
76
77 char xk_ret_buffer[100];
78 char *xk_ret_buf = xk_ret_buffer;
79 struct Bfunction xk_prdebug = { get_prdebug, set_prdebug };
80
81 int
82 do_field_get(
83         int argc,
84         char **argv )
85 {
86         char buf[BIGBUFSIZ], *p, *bufstart;
87         char *fld, *type, *ptr, *ptr2, **pptr2;
88         memtbl_t tbl[2], *tbl2;
89         int i;
90         char *targvar = NULL;
91         char fail = 0, always_ptr;
92         char * errmsg;
93
94         always_ptr = 0;
95         for (i = 1; (i < argc) && argv[i] != NULL && argv[i][0] == '-'; i++) {
96                 switch(argv[i][1]) {
97                    case 'p':
98                         always_ptr = 1;
99                         break;
100                    case 'v':
101                         targvar = argv[++i];
102                         break;
103                 }
104         }
105
106         if ((i + 1) >= argc)
107         {
108            XK_USAGE(argv[0]);
109         }
110
111         type = argv[i++];
112         if (!isdigit(argv[i][0]))
113                 always_ptr = 1;
114         ptr = (char *) getaddr(argv[i++]);
115         tbl[1] = Null_tbl;
116         if (!type || !ptr || (parse_decl(argv[0], tbl, type, 1) == FAIL)) {
117                 if (!type || !ptr)
118                 {
119                    XK_USAGE(argv[0]);
120                 }
121                 else
122                 {
123                    errmsg = strdup(GETMESSAGE(4,1, 
124                                    "Cannot parse the structure named '%s'; it may not have been defined"));
125                    printerrf(argv[0], errmsg, type, NULL, NULL,
126                              NULL, NULL, NULL, NULL, NULL);
127                    free(errmsg);
128                    return(SH_FAIL);
129                 }
130         }
131         if ((always_ptr || !IS_SIMPLE(tbl)) && !tbl->ptr && !(tbl->flags & F_TYPE_IS_PTR))
132                 tbl->ptr = 1;
133         else while (tbl->ptr > 1) {
134                 ptr = *((void **) ptr);
135                 tbl->ptr--;
136         }
137         Pr_tmpnonames = 1;
138         p = buf;
139         if (targvar) {
140                 strcpy(p, targvar);
141                 p += strlen(p);
142                 *p++ = '=';
143                 bufstart = p;
144         }
145         else
146                 bufstart = buf;
147         while ((i < argc) && (fld = argv[i++])) {
148                 if (p != bufstart)
149                         *p++ = targvar ? ' ' : '\n';
150                 tbl2 = tbl;
151                 ptr2 = ptr;
152                 pptr2 = &ptr2;
153                 if (!C_PAIR(fld, '.', '\0'))
154                         tbl2 = ffind(tbl, fld, (char **)&pptr2);
155                 if (!tbl2) {
156                         errmsg = strdup(GetSharedMsg(DT_BAD_FIELD_NAME));
157                         printerrf(argv[0], errmsg, fld, type,
158                                   NULL, NULL, NULL, NULL, NULL, NULL);
159                         free(errmsg);
160                         fail = 1;
161                         break;
162                 }
163                 if (XK_PRINT(tbl2, &p, (char *)pptr2, 0, 0, NULL, 
164                               all_tbl_find) == FAIL) 
165                 {
166                         errmsg=strdup(GETMESSAGE(4,2, 
167                             "Cannot print the field '%s' in structure '%s'"));
168                         printerrf(argv[0], errmsg, fld, type,
169                                   NULL, NULL, NULL, NULL, NULL, NULL);
170                         free(errmsg);
171                         fail = 1;
172                         break;
173                 }
174         }
175         if (!fail) {
176                 *p = '\0';
177                 if (targvar)
178                         env_set(buf);
179                 else
180                         ALTPUTS(buf);
181         }
182         Pr_tmpnonames = 0;
183         return(fail ? SH_FAIL : SH_SUCC);
184 }
185
186 static int
187 allprint(
188         unsigned long *pargs,
189         memtbl_t *tbls )
190 {
191         char buf[BIGBUFSIZ], *p;
192         int i;
193         char * errmsg;
194
195         for (i = 0; tbls[i].name; i++) {
196                 errmsg = strdup(GETMESSAGE(4,3, "Argument %d (type %s):\n\t"));
197                 printf(errmsg, i + 1, tbls[i].name);
198                 free(errmsg);
199                 p = buf;
200                 XK_PRINT(tbls + i, &p, (char *)(pargs + i), 0, 0, NULL, 
201                          all_tbl_find);
202                 ALTPUTS(buf);
203         }
204 }
205
206 static
207 pp_usage( void )
208 {
209         char * errmsg;
210
211         errmsg = strdup(GETMESSAGE(4,4, 
212                  "Please enter p(rint), s(end), q(uit) or field=value\n"));
213         printf(errmsg);
214         free(errmsg);
215 }
216
217 static int
218 call_postprompt(
219         char * argv0 ,
220         unsigned long *pargs,
221         memtbl_t *tbls,
222         int *freeit )
223 {
224         char buf[BUFSIZ];
225         char * errmsg;
226         char * quitStr, *printStr, *sendStr, *promptStr;
227         int returnVal = 0;
228
229         quitStr = strdup(GETMESSAGE(4,5, "q"));
230         printStr = strdup(GETMESSAGE(4,6, "p"));
231         sendStr = strdup(GETMESSAGE(4,7, "s"));
232         promptStr = strdup(GETMESSAGE(4,8, "Postprompt: "));
233
234         for ( ; ; ) {
235                 myprompt(promptStr);
236                 strcpy(buf, quitStr);
237
238                 *buf = '\0';
239                 fgets(buf, sizeof(buf), stdin);
240                 if (strlen(buf) && buf[strlen(buf)-1] == '\n')
241                   buf[strlen(buf)-1] = '\0';
242
243                 if (xk_Strncmp(buf, quitStr, 2) == 0)
244                 {
245                         errmsg=strdup(GETMESSAGE(4,9, 
246                                    "Warning: command was not executed\n"));
247                         printf(errmsg);
248                         free(errmsg);
249                         returnVal = 0;
250                         break;
251                 }
252                 else if (xk_Strncmp(buf, printStr, 2) == 0)
253                         allprint(pargs, tbls);
254                 else if (xk_Strncmp(buf, sendStr, 2) == 0)
255                 {
256                         returnVal = 1;
257                         break;
258                 }
259                 else if (!strchr(buf, '=') || 
260                  (asl_set(argv0,tbls, buf, (unsigned char **)pargs) == SH_FAIL))
261                 {
262                         pp_usage();
263                 }
264         }
265
266         free(quitStr);
267         free(printStr);
268         free(sendStr);
269         free(promptStr);
270         return(returnVal);
271 }
272
273 #define ZERORET         0
274 #define NONZERO         1
275 #define NONNEGATIVE     2
276
277 /* In shell, 0 is success so, ZERORET means direct return, NONZERO means
278 ** return the opposite of its truth value and NONNEGATIVE means return
279 ** true if the value IS negative (since FALSE is success)
280 */
281 #define CALL_RETURN(RET) return(SET_RET(RET), ((ret_type == ZERORET) ? (RET) : ((ret_type == NONZERO) ? !(RET) : ((RET) < 0))))
282 #define EARLY_RETURN(RET) return(SET_RET(RET))
283 #define SET_RET(RET) (((int) sprintf(xk_ret_buffer, use, (RET))), (int) (xk_ret_buf = xk_ret_buffer), RET)
284
285 int
286 do_call(
287         int argc,
288         char **argv )
289 {
290         void *pargs[MAX_CALL_ARGS];
291         memtbl_t tblarray[MAX_CALL_ARGS];
292         char freeit[MAX_CALL_ARGS];
293         unsigned long (*func)();
294         char *p;
295         char dorun, promptflag;
296         unsigned char freeval, ret_type;
297         register int i, j, ret;
298         char * msg;
299         char * errbuf;
300         char * errmsg;
301
302         promptflag = 0;
303         freeval = 1;
304         ret_type = ZERORET;
305         dorun = 1;
306         if (argc == 1) {
307                 errmsg = strdup(GetSharedMsg(DT_NO_FUNC_NAME));
308                 printerr(argv[0], errmsg, NULL);
309                 free(errmsg);
310                 xk_usage(argv[0]);
311                 EARLY_RETURN(1);
312         }
313
314         for (j = 1; (j < argc) && argv[j][0] == '-'; j++) {
315                 for (i = 1; argv[j][i]; i++) {
316                         switch(argv[j][i]) {
317                         case 'F':
318                                 /* Do not free */
319                                 freeval = 0;
320                                 break;
321                         case 'r':
322                                 /* reverse sense of return value */
323                                 ret_type = NONZERO;
324                                 break;
325                         case 'n':
326                                 /* Non-negative return value is okay */
327                                 ret_type = NONNEGATIVE;
328                                 break;
329                         default:
330                                 errmsg =strdup(GetSharedMsg(DT_UNKNOWN_OPTION));
331                                 printerrf(argv[0], errmsg,
332                                           argv[j], NULL, NULL, NULL,
333                                           NULL, NULL, NULL, NULL);
334                                 free(errmsg);
335                                 xk_usage(argv[0]);
336                                 EARLY_RETURN(1);
337                         }
338                 }
339         }
340         if (j >= argc) {
341                 errmsg = strdup(GetSharedMsg(DT_NO_FUNC_NAME));
342                 printerr(argv[0], errmsg, NULL);
343                 free(errmsg);
344                 xk_usage(argv[0]);
345                 CALL_RETURN(1);
346         }
347         memset(tblarray, '\0', MAX_CALL_ARGS * sizeof(memtbl_t));
348         memset(pargs, '\0', MAX_CALL_ARGS * sizeof(void *));
349         memset(freeit, '\0', MAX_CALL_ARGS * sizeof(char));
350         func = (unsigned long (*)()) fsym(argv[j], -1);
351         if (!func && ((argv[j][0] != '0') || (UPP(argv[j][1]) != 'X') || !(func = (unsigned long (*)()) strtoul(argv[j], &p, 16)) || *p)) {
352                 errmsg = strdup(GETMESSAGE(4,10, 
353                                   "Unable to locate the function '%s'"));
354                 printerrf(argv[0], errmsg, 
355                          argv[j], NULL, NULL, NULL, NULL, NULL, NULL, NULL);
356                 free(errmsg);
357                 CALL_RETURN(1);
358         }
359         j++;
360         for (i = 0; (i < MAX_CALL_ARGS) && (j < argc) && argv[j]; j++, i++) {
361                 char *val;
362                 char type[100];
363
364                 if (C_PAIR(argv[j], '+', '?')) {
365                         promptflag = 1;
366                         continue;
367                 }
368                 else if (C_PAIR(argv[j], '+', '+')) {
369                         j++;
370                         break;
371                 }
372                 if (argv[j][0] == '@') {
373                         if (!(val = strchr(argv[j] + 1, ':'))) {
374                                 dorun = 0;
375                                 ret = -1;
376                                 break;
377                         }
378                         strncpy(type, argv[j] + 1, val - argv[j] - 1);
379                         type[val - argv[j] - 1] = '\0';
380                         val++;
381                         if (parse_decl(argv[0], tblarray + i, type, 1) == FAIL)
382                         {
383                                 dorun = 0;
384                                 ret = -1;
385                                 break;
386                         }
387                         else {
388                                 if (!strparse(tblarray + i, 
389                                         (char **)(pargs + i), val)) 
390                                 {
391                                         errmsg=strdup(GETMESSAGE(4,11, 
392                                             "The value descriptor '%s' does not match the definition for structure '%s'"));
393                                         printerrf(argv[0], errmsg,
394                                                  val, type, NULL, NULL, NULL,
395                                                  NULL, NULL, NULL);
396                                         free(errmsg);
397                                         dorun = 0;
398                                         ret = -1;
399                                         break;
400                                 }
401                                 else
402                                         freeit[i] = freeval;
403                         }
404                 }
405                 else if (isdigit(argv[j][0])) {
406                         char *p;
407
408                         p = argv[j];
409                         tblarray[i] = T_unsigned_long[0];
410                         xk_par_int(&p, pargs + i, NULL);
411                 }
412                 else if (strcmp(argv[j], (char *) "NULL") == 0) {
413                         tblarray[i] = T_unsigned_long[0];
414                         pargs[i] = NULL;
415                 }
416                 else {
417                         pargs[i] = (void *) argv[j];
418                         tblarray[i] = T_string_t[0];
419                 }
420         }
421         /* Process special arguments */
422         while (j < argc) {
423                 asl_set(argv[0], tblarray, argv[j], (unsigned char **)pargs);
424                 j++;
425         }
426         if (dorun) {
427                 if (!promptflag || 
428                     call_postprompt(argv[0], (unsigned long *)pargs, tblarray, 
429                                      (int *)freeit))
430                 {
431                         ret = (*func)(pargs[0], pargs[1], pargs[2], pargs[3], 
432                                       pargs[4], pargs[5], pargs[6], pargs[7], 
433                                       pargs[8], pargs[9], pargs[10], pargs[11],
434                                       pargs[12], pargs[13], pargs[14]);
435                 }
436                 else
437                         ret = 0;
438                 Xk_errno = errno;
439         }
440         for (i = 0; i < MAX_CALL_ARGS; i++) {
441                 if (pargs[i] && freeit[i])
442                 {
443                         /* There is no recourse for failure */
444                         XK_FREE(tblarray + i, (char *)(pargs + i), 0, 0, 
445                                 all_tbl_find);
446                 }
447         }
448         CALL_RETURN(ret);
449 }
450
451 int _Prdebug;
452
453 static long
454 get_prdebug( void )
455 {
456         return(_Prdebug);
457 }
458
459 static long
460 set_prdebug(
461         long n )
462 {
463         _Prdebug = n;
464 }
465
466
467 int
468 asl_set(
469         char *argv0,
470         memtbl_t *tblarray,
471         char *desc,
472         unsigned char **pargs )
473 {
474         char *ptr;
475         char *val;
476         memtbl_t *tbl;
477         memtbl_t usetbl[2];
478         char op;
479         char field[80], *fldp = field;
480         unsigned long intval, i, newval;
481         unsigned long top, bottom;
482         char * errmsg;
483
484         if ((val = strchr(desc, '=')) == NULL)
485                 return(SH_FAIL);
486         if (ispunct(val[-1]) && (val[-1] != ']')) {
487                 op = val[-1];
488                 strncpy(field, desc, val - desc - 1);
489                 field[val - desc - 1] = '\0';
490                 val++;
491         }
492         else {
493                 op = '\0';
494                 strncpy(field, desc, val - desc);
495                 field[val - desc] = '\0';
496                 val++;
497         }
498         if (isdigit(fldp[0])) {
499                 top = bottom = strtoul(fldp, &fldp, 0) - 1;
500                 if (*fldp == '.')
501                         fldp++;
502         }
503         else {
504                 top = 9;
505                 bottom = 0;
506         }
507         usetbl[1] = Null_tbl;
508         for (i = bottom; i <= top; i++) {
509                 usetbl[0] = tblarray[i];
510                 ptr = (char *) (pargs + i);
511                 if (tbl = ffind(usetbl, fldp, &ptr))
512                         break;
513         }
514         if (!tbl || (i > top)) {
515                 errmsg=strdup(GETMESSAGE(4,12, "Cannot locate the field '%s'"));
516                 printerrf(argv0, errmsg, fldp, NULL, NULL, NULL,
517                           NULL, NULL, NULL, NULL);
518                 free(errmsg);
519                 return(SH_FAIL);
520         }
521         if (!op || !(tbl->flags & F_SIMPLE)) 
522         {
523            if (XK_PARSE(tbl, &val, ptr, 0, 0, NULL, all_tbl_find) < 0)
524            {
525               errmsg = strdup(GETMESSAGE(4,13, 
526                      "Cannot set the following value for the field '%s': %s"));
527               printerrf(argv0, errmsg, val, NULL,
528                                   NULL, NULL, NULL, NULL, NULL, NULL);
529               free(errmsg);
530            }
531         }
532         else {
533                 xk_par_int(&val, &newval, NULL);
534                 switch (tbl->size) {
535                 case sizeof(long):
536                         intval = ((unsigned long *) ptr)[0];
537                         break;
538                 case sizeof(short):
539                         intval = ((unsigned short *) ptr)[0];
540                         break;
541                 case sizeof(char):
542                         intval = ((unsigned char *) ptr)[0];
543                         break;
544                 default:
545                         if (tbl-size == sizeof(int))
546                         {
547                             intval = ((unsigned int *) ptr)[0];
548                             break;
549                         }
550                 }
551                 switch(op) {
552                 case '+':
553                         intval += newval;
554                         break;
555                 case '-':
556                         intval -= newval;
557                         break;
558                 case '*':
559                         intval *= newval;
560                         break;
561                 case '/':
562                         intval /= newval;
563                         break;
564                 case '%':
565                         intval %= newval;
566                         break;
567                 case '&':
568                         intval &= newval;
569                         break;
570                 case '|':
571                         intval |= newval;
572                         break;
573                 case '^':
574                         intval ^= newval;
575                         break;
576                 }
577                 switch (tbl->size) {
578                 case sizeof(long):
579                         ((unsigned long *) ptr)[0] = intval;
580                         break;
581                 case sizeof(short):
582                         ((unsigned short *) ptr)[0] = intval;
583                         break;
584                 case sizeof(char):
585                         ((unsigned char *) ptr)[0] = intval;
586                         break;
587                 default:
588                         if (tbl->size == sizeof(int))
589                         {
590                             ((unsigned int *) ptr)[0] = intval;
591                             break;
592                         }
593                 }
594         }
595         return(SH_SUCC);
596 }
597
598 int
599 do_field_comp(
600         int argc,
601         char **argv )
602 {
603         char *val, *type;
604         void *ptr, *ptr2, **pptr2, *nuptr;
605         memtbl_t tbl[2], *tbl2;
606         unsigned int i;
607         unsigned char always_ptr;
608         char pr1[5 * BUFSIZ], pr2[5 * BUFSIZ], *p1, *p2;
609         char * errbuf;
610         char * msg;
611         char * errmsg;
612
613         i = 1;
614         if (argc > 1 && C_PAIR(argv[i], '-', 'p')) {
615                 i++;
616                 always_ptr = 1;
617         }
618         else
619                 always_ptr = 0;
620
621         if ((i + 2) > argc)
622         {
623            XK_USAGE(argv[0]);
624         }
625
626         type = argv[i++];
627         if (!isdigit(argv[i][0]))
628                 always_ptr = 1;
629         ptr = getaddr(argv[i++]);
630         tbl[1] = Null_tbl;
631         if (!type || !ptr || (parse_decl(argv[0], tbl, type, 1) == FAIL))
632         {
633                 XK_USAGE(argv[0]);
634         }
635         if ((always_ptr || !IS_SIMPLE(tbl)) && !tbl->ptr && !(tbl->flags & F_TYPE_IS_PTR))
636                 tbl->ptr = 1;
637         else while (tbl->ptr > 1) {
638                 ptr = *((void **) ptr);
639                 tbl->ptr--;
640         }
641         for ( ; (i < argc) && argv[i]; i++) {
642                 tbl2 = tbl;
643                 ptr2 = ptr;
644                 pptr2 = &ptr2;
645                 if (val = strchr(argv[i], '=')) {
646                         *val++ = '\0';
647                         tbl2 = ffind(tbl, argv[i], (char **)&pptr2);
648                         if (!tbl2) {
649                            errmsg = strdup(GetSharedMsg(DT_BAD_FIELD_NAME));
650                            printerrf(argv[0], errmsg, argv[i],
651                                      type, NULL, NULL, NULL, NULL, NULL, NULL);
652                            free(errmsg);
653                            return(SH_FAIL);
654                         }
655                         val[-1] = '=';
656                 }
657                 else
658                         val = argv[i];
659                 p1 = pr1;
660                 p2 = pr2;
661                 Pr_tmpnonames = 1;
662                 XK_PRINT(tbl2, &p1, (char *)pptr2, 0, 0, NULL, all_tbl_find);
663                 if (XK_PARSE(tbl2, &val, (char *)&nuptr, 0, 0, NULL, 
664                     all_tbl_find) < 0) 
665                 {
666                         errmsg=strdup(GETMESSAGE(4,15, 
667                                   "Cannot parse the following expression: %s"));
668                         printerrf(argv[0], errmsg, argv[i],
669                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL);
670                         free(errmsg);
671                         return(SH_FAIL);
672                 }
673                 XK_PRINT(tbl2, &p2, (char *)&nuptr, 0, 0, NULL, all_tbl_find);
674                 XK_FREE(tbl2, (char *)&nuptr, 0, 0, all_tbl_find);
675                 Pr_tmpnonames = 0;
676                 if (strcmp(pr1, pr2)) {
677                         if (env_get((char *) "PRCOMPARE"))
678                         {
679                                 errmsg=strdup(GETMESSAGE(4,16, 
680                                         "The following comparision failed: '%s'\n\tActual:  %s\n\tCompare: %s"));
681                                 printerrf(argv[0], errmsg,
682                                           argv[i], pr1, pr2, NULL, NULL, NULL,
683                                           NULL, NULL);
684                                 free(errmsg);
685                         }
686                         return(SH_FAIL);
687                 }
688         }
689         return(SH_SUCC);
690 }
691
692 static int
693 myprompt(
694         char *prompt )
695 {
696         fprintf(stderr,prompt);
697 }
698
699
700 #if 0
701 /* This needs a functional proto, and needs to be extern'ed in docall.h */
702 unsigned long
703 strprint(va_alist)
704 va_dcl
705 {
706         va_list ap;
707         char *arg;
708         char *variable = NULL;
709         memtbl_t tbl;
710         char *p;
711         char buf[5 * BUFSIZ];
712         char *name;
713         void *val;
714         char always_ptr;
715         int nonames = 0;
716         int ret;
717
718         va_start(ap);
719         always_ptr = 0;
720         while ((arg = (char *) va_arg(ap, unsigned long)) && (arg[0] == '-')) {
721                 int i;
722
723                 for (i = 1; arg[i]; i++) {
724                         switch (arg[i]) {
725                         case 'v':
726                                 variable = va_arg(ap, char *);
727                                 i = strlen(arg) - 1;
728                                 break;
729                         case 'p':
730                                 always_ptr = 1;
731                                 break;
732                         case 'N':
733                                 nonames = 1;
734                         }
735                 }
736         }
737         name = arg;
738         if (!arg) {
739                 printerr(argv[0], "Insufficient arguments", NULL);
740                 va_end(ap);
741                 return(SH_FAIL);
742         }
743         val = (void *) va_arg(ap, unsigned long);
744         va_end(ap);
745         if (parse_decl("strprintf", &tbl, name, 1) == FAIL)
746                 return(SH_FAIL);
747         if (variable)
748                 p = buf + lsprintf(buf, "%s=", variable);
749         else
750                 p = buf;
751         if ((always_ptr || !IS_SIMPLE(&tbl)) && !tbl.ptr && !(tbl.flags & F_TYPE_IS_PTR))
752                 tbl.ptr = 1;
753         if (!val && (tbl.ptr || (tbl.flags & F_TYPE_IS_PTR))) {
754                 printerr(argv[0], "NULL value argument to strprint", NULL);
755                 return(SH_FAIL);
756         }
757         if (always_ptr && (tbl.flags & F_TYPE_IS_PTR))
758                 val = *((void **) val);
759         else while (tbl.ptr > 1) {
760                 val = *((void **) val);
761                 tbl.ptr--;
762         }
763         Pr_tmpnonames = nonames;
764         ret = XK_PRINT(&tbl, &p, (void *) &val, 0, 0, NULL, all_tbl_find);
765         Pr_tmpnonames = 0;
766         if (ret == FAIL)
767                 return(SH_FAIL);
768         if (variable)
769                 env_set(buf);
770         else
771                 ALTPUTS(buf);
772         return(SH_SUCC);
773 }
774 #endif