perl 2.0 (no announcement message available)
[p5sagit/p5-mst-13.2.git] / eval.c
1 /* $Header: eval.c,v 2.0 88/06/05 00:08:48 root Exp $
2  *
3  * $Log:        eval.c,v $
4  * Revision 2.0  88/06/05  00:08:48  root
5  * Baseline version 2.0.
6  * 
7  */
8
9 #include "EXTERN.h"
10 #include "perl.h"
11
12 #include <signal.h>
13 #include <errno.h>
14
15 extern int errno;
16
17 #ifdef VOIDSIG
18 static void (*ihand)();
19 static void (*qhand)();
20 #else
21 static int (*ihand)();
22 static int (*qhand)();
23 #endif
24
25 ARG *debarg;
26 STR str_args;
27
28 STR *
29 eval(arg,retary,sargoff)
30 register ARG *arg;
31 STR ***retary;          /* where to return an array to, null if nowhere */
32 int sargoff;            /* how many elements in sarg are already assigned */
33 {
34     register STR *str;
35     register int anum;
36     register int optype;
37     int maxarg;
38     int maxsarg;
39     double value;
40     STR *quicksarg[5];
41     register STR **sarg = quicksarg;
42     register char *tmps;
43     char *tmps2;
44     int argflags;
45     int argtype;
46     union argptr argptr;
47     int cushion;
48     unsigned long tmplong;
49     long when;
50     FILE *fp;
51     STR *tmpstr;
52     FCMD *form;
53     STAB *stab;
54     ARRAY *ary;
55     bool assigning = FALSE;
56     double exp(), log(), sqrt(), modf();
57     char *crypt(), *getenv();
58
59     if (!arg)
60         return &str_no;
61     str = arg->arg_ptr.arg_str;
62     optype = arg->arg_type;
63     maxsarg = maxarg = arg->arg_len;
64     if (maxsarg > 3 || retary) {
65         if (sargoff >= 0) {     /* array already exists, just append to it */
66             cushion = 10;
67             sarg = (STR **)saferealloc((char*)*retary,
68               (maxsarg+sargoff+2+cushion) * sizeof(STR*)) + sargoff;
69               /* Note that sarg points into the middle of the array */
70         }
71         else {
72             sargoff = cushion = 0;
73             sarg = (STR **)safemalloc((maxsarg+2) * sizeof(STR*));
74         }
75     }
76     else
77         sargoff = 0;
78 #ifdef DEBUGGING
79     if (debug) {
80         if (debug & 8) {
81             deb("%s (%lx) %d args:\n",opname[optype],arg,maxarg);
82         }
83         debname[dlevel] = opname[optype][0];
84         debdelim[dlevel++] = ':';
85     }
86 #endif
87     for (anum = 1; anum <= maxarg; anum++) {
88         argflags = arg[anum].arg_flags;
89         if (argflags & AF_SPECIAL)
90             continue;
91         argtype = arg[anum].arg_type;
92         argptr = arg[anum].arg_ptr;
93       re_eval:
94         switch (argtype) {
95         default:
96             sarg[anum] = &str_no;
97 #ifdef DEBUGGING
98             tmps = "NULL";
99 #endif
100             break;
101         case A_EXPR:
102 #ifdef DEBUGGING
103             if (debug & 8) {
104                 tmps = "EXPR";
105                 deb("%d.EXPR =>\n",anum);
106             }
107 #endif
108             if (retary &&
109               (optype == O_LIST || optype == O_ITEM2 || optype == O_ITEM3)) {
110                 *retary = sarg - sargoff;
111                 eval(argptr.arg_arg, retary, anum - 1 + sargoff);
112                 sarg = *retary;         /* they do realloc it... */
113                 argtype = maxarg - anum;        /* how many left? */
114                 maxsarg = (int)(str_gnum(sarg[0])) + argtype;
115                 sargoff = maxsarg - maxarg;
116                 if (argtype > 9 - cushion) {    /* we don't have room left */
117                     sarg = (STR **)saferealloc((char*)sarg,
118                       (maxsarg+2+cushion) * sizeof(STR*));
119                 }
120                 sarg += sargoff;
121             }
122             else
123                 sarg[anum] = eval(argptr.arg_arg, Null(STR***),-1);
124             break;
125         case A_CMD:
126 #ifdef DEBUGGING
127             if (debug & 8) {
128                 tmps = "CMD";
129                 deb("%d.CMD (%lx) =>\n",anum,argptr.arg_cmd);
130             }
131 #endif
132             sarg[anum] = cmd_exec(argptr.arg_cmd);
133             break;
134         case A_STAB:
135             sarg[anum] = STAB_STR(argptr.arg_stab);
136 #ifdef DEBUGGING
137             if (debug & 8) {
138                 sprintf(buf,"STAB $%s",argptr.arg_stab->stab_name);
139                 tmps = buf;
140             }
141 #endif
142             break;
143         case A_LEXPR:
144 #ifdef DEBUGGING
145             if (debug & 8) {
146                 tmps = "LEXPR";
147                 deb("%d.LEXPR =>\n",anum);
148             }
149 #endif
150             str = eval(argptr.arg_arg,Null(STR***),-1);
151             if (!str)
152                 fatal("panic: A_LEXPR");
153             goto do_crement;
154         case A_LVAL:
155 #ifdef DEBUGGING
156             if (debug & 8) {
157                 sprintf(buf,"LVAL $%s",argptr.arg_stab->stab_name);
158                 tmps = buf;
159             }
160 #endif
161             str = STAB_STR(argptr.arg_stab);
162             if (!str)
163                 fatal("panic: A_LVAL");
164           do_crement:
165             assigning = TRUE;
166             if (argflags & AF_PRE) {
167                 if (argflags & AF_UP)
168                     str_inc(str);
169                 else
170                     str_dec(str);
171                 STABSET(str);
172                 sarg[anum] = str;
173                 str = arg->arg_ptr.arg_str;
174             }
175             else if (argflags & AF_POST) {
176                 sarg[anum] = str_static(str);
177                 if (argflags & AF_UP)
178                     str_inc(str);
179                 else
180                     str_dec(str);
181                 STABSET(str);
182                 str = arg->arg_ptr.arg_str;
183             }
184             else {
185                 sarg[anum] = str;
186             }
187             break;
188         case A_LARYLEN:
189             str = sarg[anum] =
190               argptr.arg_stab->stab_array->ary_magic;
191 #ifdef DEBUGGING
192             tmps = "LARYLEN";
193 #endif
194             if (!str)
195                 fatal("panic: A_LEXPR");
196             goto do_crement;
197         case A_ARYLEN:
198             stab = argptr.arg_stab;
199             sarg[anum] = stab->stab_array->ary_magic;
200             str_numset(sarg[anum],(double)(stab->stab_array->ary_fill+arybase));
201 #ifdef DEBUGGING
202             tmps = "ARYLEN";
203 #endif
204             break;
205         case A_SINGLE:
206             sarg[anum] = argptr.arg_str;
207 #ifdef DEBUGGING
208             tmps = "SINGLE";
209 #endif
210             break;
211         case A_DOUBLE:
212             (void) interp(str,str_get(argptr.arg_str));
213             sarg[anum] = str;
214 #ifdef DEBUGGING
215             tmps = "DOUBLE";
216 #endif
217             break;
218         case A_BACKTICK:
219             tmps = str_get(argptr.arg_str);
220             fp = popen(str_get(interp(str,tmps)),"r");
221             tmpstr = str_new(80);
222             str_set(str,"");
223             if (fp) {
224                 while (str_gets(tmpstr,fp) != Nullch) {
225                     str_scat(str,tmpstr);
226                 }
227                 statusvalue = pclose(fp);
228             }
229             else
230                 statusvalue = -1;
231             str_free(tmpstr);
232
233             sarg[anum] = str;
234 #ifdef DEBUGGING
235             tmps = "BACK";
236 #endif
237             break;
238         case A_INDREAD:
239             last_in_stab = stabent(str_get(STAB_STR(argptr.arg_stab)),TRUE);
240             goto do_read;
241         case A_GLOB:
242             argflags |= AF_POST;        /* enable newline chopping */
243         case A_READ:
244             last_in_stab = argptr.arg_stab;
245           do_read:
246             fp = Nullfp;
247             if (last_in_stab->stab_io) {
248                 fp = last_in_stab->stab_io->fp;
249                 if (!fp) {
250                     if (last_in_stab->stab_io->flags & IOF_ARGV) {
251                         if (last_in_stab->stab_io->flags & IOF_START) {
252                             last_in_stab->stab_io->flags &= ~IOF_START;
253                             last_in_stab->stab_io->lines = 0;
254                             if (alen(last_in_stab->stab_array) < 0) {
255                                 tmpstr = str_make("-"); /* assume stdin */
256                                 apush(last_in_stab->stab_array, tmpstr);
257                             }
258                         }
259                         fp = nextargv(last_in_stab);
260                         if (!fp)  /* Note: fp != last_in_stab->stab_io->fp */
261                             do_close(last_in_stab,FALSE);  /* now it does */
262                     }
263                     else if (argtype == A_GLOB) {
264                         (void) interp(str,str_get(last_in_stab->stab_val));
265                         tmps = str->str_ptr;
266                         if (*tmps == '!')
267                             sprintf(tokenbuf,"%s|",tmps+1);
268                         else {
269                             if (*tmps == ';')
270                                 sprintf(tokenbuf, "%s", tmps+1);
271                             else
272                                 sprintf(tokenbuf, "echo %s", tmps);
273                             strcat(tokenbuf,
274                               "|tr -s ' \t\f\r' '\\012\\012\\012\\012'|");
275                         }
276                         do_open(last_in_stab,tokenbuf);
277                         fp = last_in_stab->stab_io->fp;
278                     }
279                 }
280             }
281             if (!fp && dowarn)
282                 warn("Read on closed filehandle <%s>",last_in_stab->stab_name);
283           keepgoing:
284             if (!fp)
285                 sarg[anum] = &str_no;
286             else if (!str_gets(str,fp)) {
287                 if (last_in_stab->stab_io->flags & IOF_ARGV) {
288                     fp = nextargv(last_in_stab);
289                     if (fp)
290                         goto keepgoing;
291                     do_close(last_in_stab,FALSE);
292                     last_in_stab->stab_io->flags |= IOF_START;
293                 }
294                 else if (argflags & AF_POST) {
295                     do_close(last_in_stab,FALSE);
296                 }
297                 if (fp == stdin) {
298                     clearerr(fp);
299                 }
300                 sarg[anum] = &str_no;
301                 if (retary) {
302                     maxarg = anum - 1;
303                     maxsarg = maxarg + sargoff;
304                 }
305                 break;
306             }
307             else {
308                 last_in_stab->stab_io->lines++;
309                 sarg[anum] = str;
310                 if (argflags & AF_POST) {
311                     if (str->str_cur > 0)
312                         str->str_cur--;
313                     str->str_ptr[str->str_cur] = '\0';
314                 }
315                 if (retary) {
316                     sarg[anum] = str_static(sarg[anum]);
317                     anum++;
318                     if (anum > maxarg) {
319                         maxarg = anum + anum;
320                         maxsarg = maxarg + sargoff;
321                         sarg = (STR **)saferealloc((char*)(sarg-sargoff),
322                           (maxsarg+2+cushion) * sizeof(STR*)) + sargoff;
323                     }
324                     goto keepgoing;
325                 }
326             }
327             if (retary) {
328                 maxarg = anum - 1;
329                 maxsarg = maxarg + sargoff;
330             }
331 #ifdef DEBUGGING
332             tmps = "READ";
333 #endif
334             break;
335         }
336 #ifdef DEBUGGING
337         if (debug & 8)
338             deb("%d.%s = '%s'\n",anum,tmps,str_peek(sarg[anum]));
339 #endif
340     }
341     switch (optype) {
342     case O_ITEM:
343         if (maxarg > arg->arg_len)
344             goto array_return;
345         if (str != sarg[1])
346             str_sset(str,sarg[1]);
347         STABSET(str);
348         break;
349     case O_ITEM2:
350         if (str != sarg[--anum])
351             str_sset(str,sarg[anum]);
352         STABSET(str);
353         break;
354     case O_ITEM3:
355         if (str != sarg[--anum])
356             str_sset(str,sarg[anum]);
357         STABSET(str);
358         break;
359     case O_CONCAT:
360         if (str != sarg[1])
361             str_sset(str,sarg[1]);
362         str_scat(str,sarg[2]);
363         STABSET(str);
364         break;
365     case O_REPEAT:
366         if (str != sarg[1])
367             str_sset(str,sarg[1]);
368         anum = (int)str_gnum(sarg[2]);
369         if (anum >= 1) {
370             tmpstr = str_new(0);
371             str_sset(tmpstr,str);
372             while (--anum > 0)
373                 str_scat(str,tmpstr);
374         }
375         else
376             str_sset(str,&str_no);
377         STABSET(str);
378         break;
379     case O_MATCH:
380         str_sset(str, do_match(arg,
381           retary,sarg,&maxsarg,sargoff,cushion));
382         if (retary) {
383             sarg = *retary;     /* they realloc it */
384             goto array_return;
385         }
386         STABSET(str);
387         break;
388     case O_NMATCH:
389         str_sset(str, do_match(arg,
390           retary,sarg,&maxsarg,sargoff,cushion));
391         if (retary) {
392             sarg = *retary;     /* they realloc it */
393             goto array_return;  /* ignore negation */
394         }
395         str_set(str, str_true(str) ? No : Yes);
396         STABSET(str);
397         break;
398     case O_SUBST:
399         value = (double) do_subst(str, arg);
400         str = arg->arg_ptr.arg_str;
401         goto donumset;
402     case O_NSUBST:
403         str_set(arg->arg_ptr.arg_str, do_subst(str, arg) ? No : Yes);
404         str = arg->arg_ptr.arg_str;
405         break;
406     case O_ASSIGN:
407         if (arg[1].arg_flags & AF_SPECIAL)
408             do_assign(str,arg,sarg);
409         else {
410             if (str != sarg[2])
411                 str_sset(str, sarg[2]);
412             STABSET(str);
413         }
414         break;
415     case O_CHOP:
416         tmps = str_get(str);
417         tmps += str->str_cur - (str->str_cur != 0);
418         str_set(arg->arg_ptr.arg_str,tmps);     /* remember last char */
419         *tmps = '\0';                           /* wipe it out */
420         str->str_cur = tmps - str->str_ptr;
421         str->str_nok = 0;
422         str = arg->arg_ptr.arg_str;
423         break;
424     case O_STUDY:
425         value = (double)do_study(str);
426         str = arg->arg_ptr.arg_str;
427         goto donumset;
428     case O_MULTIPLY:
429         value = str_gnum(sarg[1]);
430         value *= str_gnum(sarg[2]);
431         goto donumset;
432     case O_DIVIDE:
433         if ((value = str_gnum(sarg[2])) == 0.0)
434             fatal("Illegal division by zero");
435         value = str_gnum(sarg[1]) / value;
436         goto donumset;
437     case O_MODULO:
438         if ((tmplong = (unsigned long) str_gnum(sarg[2])) == 0L)
439             fatal("Illegal modulus zero");
440         value = str_gnum(sarg[1]);
441         value = (double)(((unsigned long)value) % tmplong);
442         goto donumset;
443     case O_ADD:
444         value = str_gnum(sarg[1]);
445         value += str_gnum(sarg[2]);
446         goto donumset;
447     case O_SUBTRACT:
448         value = str_gnum(sarg[1]);
449         value -= str_gnum(sarg[2]);
450         goto donumset;
451     case O_LEFT_SHIFT:
452         value = str_gnum(sarg[1]);
453         anum = (int)str_gnum(sarg[2]);
454         value = (double)(((unsigned long)value) << anum);
455         goto donumset;
456     case O_RIGHT_SHIFT:
457         value = str_gnum(sarg[1]);
458         anum = (int)str_gnum(sarg[2]);
459         value = (double)(((unsigned long)value) >> anum);
460         goto donumset;
461     case O_LT:
462         value = str_gnum(sarg[1]);
463         value = (double)(value < str_gnum(sarg[2]));
464         goto donumset;
465     case O_GT:
466         value = str_gnum(sarg[1]);
467         value = (double)(value > str_gnum(sarg[2]));
468         goto donumset;
469     case O_LE:
470         value = str_gnum(sarg[1]);
471         value = (double)(value <= str_gnum(sarg[2]));
472         goto donumset;
473     case O_GE:
474         value = str_gnum(sarg[1]);
475         value = (double)(value >= str_gnum(sarg[2]));
476         goto donumset;
477     case O_EQ:
478         value = str_gnum(sarg[1]);
479         value = (double)(value == str_gnum(sarg[2]));
480         goto donumset;
481     case O_NE:
482         value = str_gnum(sarg[1]);
483         value = (double)(value != str_gnum(sarg[2]));
484         goto donumset;
485     case O_BIT_AND:
486         value = str_gnum(sarg[1]);
487         value = (double)(((unsigned long)value) &
488             (unsigned long)str_gnum(sarg[2]));
489         goto donumset;
490     case O_XOR:
491         value = str_gnum(sarg[1]);
492         value = (double)(((unsigned long)value) ^
493             (unsigned long)str_gnum(sarg[2]));
494         goto donumset;
495     case O_BIT_OR:
496         value = str_gnum(sarg[1]);
497         value = (double)(((unsigned long)value) |
498             (unsigned long)str_gnum(sarg[2]));
499         goto donumset;
500     case O_AND:
501         if (str_true(sarg[1])) {
502             anum = 2;
503             optype = O_ITEM2;
504             argflags = arg[anum].arg_flags;
505             argtype = arg[anum].arg_type;
506             argptr = arg[anum].arg_ptr;
507             maxarg = anum = 1;
508             goto re_eval;
509         }
510         else {
511             if (assigning) {
512                 str_sset(str, sarg[1]);
513                 STABSET(str);
514             }
515             else
516                 str = sarg[1];
517             break;
518         }
519     case O_OR:
520         if (str_true(sarg[1])) {
521             if (assigning) {
522                 str_sset(str, sarg[1]);
523                 STABSET(str);
524             }
525             else
526                 str = sarg[1];
527             break;
528         }
529         else {
530             anum = 2;
531             optype = O_ITEM2;
532             argflags = arg[anum].arg_flags;
533             argtype = arg[anum].arg_type;
534             argptr = arg[anum].arg_ptr;
535             maxarg = anum = 1;
536             goto re_eval;
537         }
538     case O_COND_EXPR:
539         anum = (str_true(sarg[1]) ? 2 : 3);
540         optype = (anum == 2 ? O_ITEM2 : O_ITEM3);
541         argflags = arg[anum].arg_flags;
542         argtype = arg[anum].arg_type;
543         argptr = arg[anum].arg_ptr;
544         maxarg = anum = 1;
545         goto re_eval;
546     case O_COMMA:
547         str = sarg[2];
548         break;
549     case O_NEGATE:
550         value = -str_gnum(sarg[1]);
551         goto donumset;
552     case O_NOT:
553         value = (double) !str_true(sarg[1]);
554         goto donumset;
555     case O_COMPLEMENT:
556         value = (double) ~(long)str_gnum(sarg[1]);
557         goto donumset;
558     case O_SELECT:
559         if (arg[1].arg_type == A_LVAL)
560             defoutstab = arg[1].arg_ptr.arg_stab;
561         else
562             defoutstab = stabent(str_get(sarg[1]),TRUE);
563         if (!defoutstab->stab_io)
564             defoutstab->stab_io = stio_new();
565         curoutstab = defoutstab;
566         str_set(str,curoutstab->stab_io->fp ? Yes : No);
567         STABSET(str);
568         break;
569     case O_WRITE:
570         if (maxarg == 0)
571             stab = defoutstab;
572         else if (arg[1].arg_type == A_LVAL)
573             stab = arg[1].arg_ptr.arg_stab;
574         else
575             stab = stabent(str_get(sarg[1]),TRUE);
576         if (!stab->stab_io) {
577             str_set(str, No);
578             STABSET(str);
579             break;
580         }
581         curoutstab = stab;
582         fp = stab->stab_io->fp;
583         debarg = arg;
584         if (stab->stab_io->fmt_stab)
585             form = stab->stab_io->fmt_stab->stab_form;
586         else
587             form = stab->stab_form;
588         if (!form || !fp) {
589             str_set(str, No);
590             STABSET(str);
591             break;
592         }
593         format(&outrec,form);
594         do_write(&outrec,stab->stab_io);
595         if (stab->stab_io->flags & IOF_FLUSH)
596             fflush(fp);
597         str_set(str, Yes);
598         STABSET(str);
599         break;
600     case O_OPEN:
601         if (arg[1].arg_type == A_WORD)
602             stab = arg[1].arg_ptr.arg_stab;
603         else
604             stab = stabent(str_get(sarg[1]),TRUE);
605         if (do_open(stab,str_get(sarg[2]))) {
606             value = (double)forkprocess;
607             stab->stab_io->lines = 0;
608             goto donumset;
609         }
610         else
611             str_set(str, No);
612         STABSET(str);
613         break;
614     case O_TRANS:
615         value = (double) do_trans(str,arg);
616         str = arg->arg_ptr.arg_str;
617         goto donumset;
618     case O_NTRANS:
619         str_set(arg->arg_ptr.arg_str, do_trans(str,arg) == 0 ? Yes : No);
620         str = arg->arg_ptr.arg_str;
621         break;
622     case O_CLOSE:
623         if (arg[1].arg_type == A_WORD)
624             stab = arg[1].arg_ptr.arg_stab;
625         else
626             stab = stabent(str_get(sarg[1]),TRUE);
627         str_set(str, do_close(stab,TRUE) ? Yes : No );
628         STABSET(str);
629         break;
630     case O_EACH:
631         str_sset(str,do_each(arg[1].arg_ptr.arg_stab->stab_hash,
632           retary,sarg,&maxsarg,sargoff,cushion));
633         if (retary) {
634             sarg = *retary;     /* they realloc it */
635             goto array_return;
636         }
637         STABSET(str);
638         break;
639     case O_VALUES:
640     case O_KEYS:
641         value = (double) do_kv(arg[1].arg_ptr.arg_stab->stab_hash, optype,
642           retary,sarg,&maxsarg,sargoff,cushion);
643         if (retary) {
644             sarg = *retary;     /* they realloc it */
645             goto array_return;
646         }
647         goto donumset;
648     case O_ARRAY:
649         if (maxarg == 1) {
650             ary = arg[1].arg_ptr.arg_stab->stab_array;
651             maxarg = ary->ary_fill;
652             maxsarg = maxarg + sargoff;
653             if (retary) { /* array wanted */
654                 sarg = (STR **)saferealloc((char*)(sarg-sargoff),
655                   (maxsarg+3+cushion)*sizeof(STR*)) + sargoff;
656                 for (anum = 0; anum <= maxarg; anum++) {
657                     sarg[anum+1] = str = afetch(ary,anum);
658                 }
659                 maxarg++;
660                 maxsarg++;
661                 goto array_return;
662             }
663             else
664                 str = afetch(ary,maxarg);
665         }
666         else
667             str = afetch(arg[2].arg_ptr.arg_stab->stab_array,
668                 ((int)str_gnum(sarg[1])) - arybase);
669         if (!str)
670             str = &str_no;
671         break;
672     case O_DELETE:
673         tmpstab = arg[2].arg_ptr.arg_stab;              /* XXX */
674         str = hdelete(tmpstab->stab_hash,str_get(sarg[1]));
675         if (!str)
676             str = &str_no;
677         break;
678     case O_HASH:
679         tmpstab = arg[2].arg_ptr.arg_stab;              /* XXX */
680         str = hfetch(tmpstab->stab_hash,str_get(sarg[1]));
681         if (!str)
682             str = &str_no;
683         break;
684     case O_LARRAY:
685         anum = ((int)str_gnum(sarg[1])) - arybase;
686         str = afetch(arg[2].arg_ptr.arg_stab->stab_array,anum);
687         if (!str || str == &str_no) {
688             str = str_new(0);
689             astore(arg[2].arg_ptr.arg_stab->stab_array,anum,str);
690         }
691         break;
692     case O_LHASH:
693         tmpstab = arg[2].arg_ptr.arg_stab;
694         str = hfetch(tmpstab->stab_hash,str_get(sarg[1]));
695         if (!str) {
696             str = str_new(0);
697             hstore(tmpstab->stab_hash,str_get(sarg[1]),str);
698         }
699         if (tmpstab == envstab) {       /* heavy wizardry going on here */
700             str->str_link.str_magic = tmpstab;/* str is now magic */
701             envname = savestr(str_get(sarg[1]));
702                                         /* he threw the brick up into the air */
703         }
704         else if (tmpstab == sigstab) {  /* same thing, only different */
705             str->str_link.str_magic = tmpstab;
706             signame = savestr(str_get(sarg[1]));
707         }
708         break;
709     case O_PUSH:
710         if (arg[1].arg_flags & AF_SPECIAL)
711             str = do_push(arg,arg[2].arg_ptr.arg_stab->stab_array);
712         else {
713             str = str_new(0);           /* must copy the STR */
714             str_sset(str,sarg[1]);
715             apush(arg[2].arg_ptr.arg_stab->stab_array,str);
716         }
717         break;
718     case O_POP:
719         str = apop(arg[1].arg_ptr.arg_stab->stab_array);
720         if (!str) {
721             str = &str_no;
722             break;
723         }
724 #ifdef STRUCTCOPY
725         *(arg->arg_ptr.arg_str) = *str;
726 #else
727         bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str);
728 #endif
729         safefree((char*)str);
730         str = arg->arg_ptr.arg_str;
731         break;
732     case O_SHIFT:
733         str = ashift(arg[1].arg_ptr.arg_stab->stab_array);
734         if (!str) {
735             str = &str_no;
736             break;
737         }
738 #ifdef STRUCTCOPY
739         *(arg->arg_ptr.arg_str) = *str;
740 #else
741         bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str);
742 #endif
743         safefree((char*)str);
744         str = arg->arg_ptr.arg_str;
745         break;
746     case O_SPLIT:
747         value = (double) do_split(arg[2].arg_ptr.arg_spat,
748           retary,sarg,&maxsarg,sargoff,cushion);
749         if (retary) {
750             sarg = *retary;     /* they realloc it */
751             goto array_return;
752         }
753         goto donumset;
754     case O_LENGTH:
755         value = (double) str_len(sarg[1]);
756         goto donumset;
757     case O_SPRINTF:
758         sarg[maxsarg+1] = Nullstr;
759         do_sprintf(str,arg->arg_len,sarg);
760         break;
761     case O_SUBSTR:
762         anum = ((int)str_gnum(sarg[2])) - arybase;
763         for (tmps = str_get(sarg[1]); *tmps && anum > 0; tmps++,anum--) ;
764         anum = (int)str_gnum(sarg[3]);
765         if (anum >= 0 && strlen(tmps) > anum)
766             str_nset(str, tmps, anum);
767         else
768             str_set(str, tmps);
769         break;
770     case O_JOIN:
771         if (arg[2].arg_flags & AF_SPECIAL && arg[2].arg_type == A_EXPR)
772             do_join(arg,str_get(sarg[1]),str);
773         else
774             ajoin(arg[2].arg_ptr.arg_stab->stab_array,str_get(sarg[1]),str);
775         break;
776     case O_SLT:
777         tmps = str_get(sarg[1]);
778         value = (double) strLT(tmps,str_get(sarg[2]));
779         goto donumset;
780     case O_SGT:
781         tmps = str_get(sarg[1]);
782         value = (double) strGT(tmps,str_get(sarg[2]));
783         goto donumset;
784     case O_SLE:
785         tmps = str_get(sarg[1]);
786         value = (double) strLE(tmps,str_get(sarg[2]));
787         goto donumset;
788     case O_SGE:
789         tmps = str_get(sarg[1]);
790         value = (double) strGE(tmps,str_get(sarg[2]));
791         goto donumset;
792     case O_SEQ:
793         tmps = str_get(sarg[1]);
794         value = (double) strEQ(tmps,str_get(sarg[2]));
795         goto donumset;
796     case O_SNE:
797         tmps = str_get(sarg[1]);
798         value = (double) strNE(tmps,str_get(sarg[2]));
799         goto donumset;
800     case O_SUBR:
801         str_sset(str,do_subr(arg,sarg));
802         STABSET(str);
803         break;
804     case O_SORT:
805         if (maxarg <= 1)
806             stab = defoutstab;
807         else {
808             if (arg[2].arg_type == A_WORD)
809                 stab = arg[2].arg_ptr.arg_stab;
810             else
811                 stab = stabent(str_get(sarg[2]),TRUE);
812             if (!stab)
813                 stab = defoutstab;
814         }
815         value = (double)do_sort(arg,stab,
816           retary,sarg,&maxsarg,sargoff,cushion);
817         if (retary) {
818             sarg = *retary;     /* they realloc it */
819             goto array_return;
820         }
821         goto donumset;
822     case O_PRTF:
823     case O_PRINT:
824         if (maxarg <= 1)
825             stab = defoutstab;
826         else {
827             if (arg[2].arg_type == A_WORD)
828                 stab = arg[2].arg_ptr.arg_stab;
829             else
830                 stab = stabent(str_get(sarg[2]),TRUE);
831             if (!stab)
832                 stab = defoutstab;
833         }
834         if (!stab->stab_io || !(fp = stab->stab_io->fp))
835             value = 0.0;
836         else {
837             if (arg[1].arg_flags & AF_SPECIAL)
838                 value = (double)do_aprint(arg,fp);
839             else {
840                 value = (double)do_print(sarg[1],fp);
841                 if (ors && optype == O_PRINT)
842                     fputs(ors, fp);
843             }
844             if (stab->stab_io->flags & IOF_FLUSH)
845                 fflush(fp);
846         }
847         goto donumset;
848     case O_CHDIR:
849         tmps = str_get(sarg[1]);
850         if (!tmps || !*tmps)
851             tmps = getenv("HOME");
852         if (!tmps || !*tmps)
853             tmps = getenv("LOGDIR");
854         value = (double)(chdir(tmps) >= 0);
855         goto donumset;
856     case O_DIE:
857         tmps = str_get(sarg[1]);
858         if (!tmps || !*tmps)
859             exit(1);
860         fatal("%s",str_get(sarg[1]));
861         value = 0.0;
862         goto donumset;
863     case O_EXIT:
864         exit((int)str_gnum(sarg[1]));
865         value = 0.0;
866         goto donumset;
867     case O_RESET:
868         str_reset(str_get(sarg[1]));
869         value = 1.0;
870         goto donumset;
871     case O_LIST:
872         if (arg->arg_flags & AF_LOCAL)
873             savelist(sarg,maxsarg);
874         if (maxarg > 0)
875             str = sarg[maxsarg];        /* unwanted list, return last item */
876         else
877             str = &str_no;
878         if (retary)
879             goto array_return;
880         break;
881     case O_EOF:
882         if (maxarg <= 0)
883             stab = last_in_stab;
884         else if (arg[1].arg_type == A_WORD)
885             stab = arg[1].arg_ptr.arg_stab;
886         else
887             stab = stabent(str_get(sarg[1]),TRUE);
888         str_set(str, do_eof(stab) ? Yes : No);
889         STABSET(str);
890         break;
891     case O_TELL:
892         if (maxarg <= 0)
893             stab = last_in_stab;
894         else if (arg[1].arg_type == A_WORD)
895             stab = arg[1].arg_ptr.arg_stab;
896         else
897             stab = stabent(str_get(sarg[1]),TRUE);
898         value = (double)do_tell(stab);
899         goto donumset;
900     case O_SEEK:
901         if (arg[1].arg_type == A_WORD)
902             stab = arg[1].arg_ptr.arg_stab;
903         else
904             stab = stabent(str_get(sarg[1]),TRUE);
905         value = str_gnum(sarg[2]);
906         str_set(str, do_seek(stab,
907           (long)value, (int)str_gnum(sarg[3]) ) ? Yes : No);
908         STABSET(str);
909         break;
910     case O_REDO:
911     case O_NEXT:
912     case O_LAST:
913         if (maxarg > 0) {
914             tmps = str_get(sarg[1]);
915             while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
916               strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
917 #ifdef DEBUGGING
918                 if (debug & 4) {
919                     deb("(Skipping label #%d %s)\n",loop_ptr,
920                         loop_stack[loop_ptr].loop_label);
921                 }
922 #endif
923                 loop_ptr--;
924             }
925 #ifdef DEBUGGING
926             if (debug & 4) {
927                 deb("(Found label #%d %s)\n",loop_ptr,
928                     loop_stack[loop_ptr].loop_label);
929             }
930 #endif
931         }
932         if (loop_ptr < 0)
933             fatal("Bad label: %s", maxarg > 0 ? tmps : "<null>");
934         longjmp(loop_stack[loop_ptr].loop_env, optype);
935     case O_GOTO:/* shudder */
936         goto_targ = str_get(sarg[1]);
937         longjmp(top_env, 1);
938     case O_INDEX:
939         tmps = str_get(sarg[1]);
940         if (!(tmps2 = fbminstr(tmps, tmps + sarg[1]->str_cur, sarg[2])))
941             value = (double)(-1 + arybase);
942         else
943             value = (double)(tmps2 - tmps + arybase);
944         goto donumset;
945     case O_TIME:
946         value = (double) time(Null(long*));
947         goto donumset;
948     case O_TMS:
949         value = (double) do_tms(retary,sarg,&maxsarg,sargoff,cushion);
950         if (retary) {
951             sarg = *retary;     /* they realloc it */
952             goto array_return;
953         }
954         goto donumset;
955     case O_LOCALTIME:
956         when = (long)str_gnum(sarg[1]);
957         value = (double)do_time(localtime(&when),
958           retary,sarg,&maxsarg,sargoff,cushion);
959         if (retary) {
960             sarg = *retary;     /* they realloc it */
961             goto array_return;
962         }
963         goto donumset;
964     case O_GMTIME:
965         when = (long)str_gnum(sarg[1]);
966         value = (double)do_time(gmtime(&when),
967           retary,sarg,&maxsarg,sargoff,cushion);
968         if (retary) {
969             sarg = *retary;     /* they realloc it */
970             goto array_return;
971         }
972         goto donumset;
973     case O_STAT:
974         value = (double) do_stat(arg,
975           retary,sarg,&maxsarg,sargoff,cushion);
976         if (retary) {
977             sarg = *retary;     /* they realloc it */
978             goto array_return;
979         }
980         goto donumset;
981     case O_CRYPT:
982 #ifdef CRYPT
983         tmps = str_get(sarg[1]);
984         str_set(str,crypt(tmps,str_get(sarg[2])));
985 #else
986         fatal(
987           "The crypt() function is unimplemented due to excessive paranoia.");
988 #endif
989         break;
990     case O_EXP:
991         value = exp(str_gnum(sarg[1]));
992         goto donumset;
993     case O_LOG:
994         value = log(str_gnum(sarg[1]));
995         goto donumset;
996     case O_SQRT:
997         value = sqrt(str_gnum(sarg[1]));
998         goto donumset;
999     case O_INT:
1000         value = str_gnum(sarg[1]);
1001         if (value >= 0.0)
1002             modf(value,&value);
1003         else {
1004             modf(-value,&value);
1005             value = -value;
1006         }
1007         goto donumset;
1008     case O_ORD:
1009         value = (double) *str_get(sarg[1]);
1010         goto donumset;
1011     case O_SLEEP:
1012         tmps = str_get(sarg[1]);
1013         time(&when);
1014         if (!tmps || !*tmps)
1015             sleep((32767<<16)+32767);
1016         else
1017             sleep((unsigned)atoi(tmps));
1018         value = (double)when;
1019         time(&when);
1020         value = ((double)when) - value;
1021         goto donumset;
1022     case O_FLIP:
1023         if (str_true(sarg[1])) {
1024             str_numset(str,0.0);
1025             anum = 2;
1026             arg->arg_type = optype = O_FLOP;
1027             arg[2].arg_flags &= ~AF_SPECIAL;
1028             arg[1].arg_flags |= AF_SPECIAL;
1029             argflags = arg[2].arg_flags;
1030             argtype = arg[2].arg_type;
1031             argptr = arg[2].arg_ptr;
1032             goto re_eval;
1033         }
1034         str_set(str,"");
1035         break;
1036     case O_FLOP:
1037         str_inc(str);
1038         if (str_true(sarg[2])) {
1039             arg->arg_type = O_FLIP;
1040             arg[1].arg_flags &= ~AF_SPECIAL;
1041             arg[2].arg_flags |= AF_SPECIAL;
1042             str_cat(str,"E0");
1043         }
1044         break;
1045     case O_FORK:
1046         value = (double)fork();
1047         goto donumset;
1048     case O_WAIT:
1049         ihand = signal(SIGINT, SIG_IGN);
1050         qhand = signal(SIGQUIT, SIG_IGN);
1051         value = (double)wait(&argflags);
1052         signal(SIGINT, ihand);
1053         signal(SIGQUIT, qhand);
1054         statusvalue = (unsigned short)argflags;
1055         goto donumset;
1056     case O_SYSTEM:
1057         while ((anum = vfork()) == -1) {
1058             if (errno != EAGAIN) {
1059                 value = -1.0;
1060                 goto donumset;
1061             }
1062             sleep(5);
1063         }
1064         if (anum > 0) {
1065             ihand = signal(SIGINT, SIG_IGN);
1066             qhand = signal(SIGQUIT, SIG_IGN);
1067             while ((argtype = wait(&argflags)) != anum && argtype != -1)
1068                 ;
1069             signal(SIGINT, ihand);
1070             signal(SIGQUIT, qhand);
1071             statusvalue = (unsigned short)argflags;
1072             if (argtype == -1)
1073                 value = -1.0;
1074             else {
1075                 value = (double)((unsigned int)argflags & 0xffff);
1076             }
1077             goto donumset;
1078         }
1079         if (arg[1].arg_flags & AF_SPECIAL)
1080             value = (double)do_aexec(arg);
1081         else {
1082             value = (double)do_exec(str_static(sarg[1]));
1083         }
1084         _exit(-1);
1085     case O_EXEC:
1086         if (arg[1].arg_flags & AF_SPECIAL)
1087             value = (double)do_aexec(arg);
1088         else {
1089             value = (double)do_exec(str_static(sarg[1]));
1090         }
1091         goto donumset;
1092     case O_HEX:
1093         argtype = 4;
1094         goto snarfnum;
1095
1096     case O_OCT:
1097         argtype = 3;
1098
1099       snarfnum:
1100         anum = 0;
1101         tmps = str_get(sarg[1]);
1102         for (;;) {
1103             switch (*tmps) {
1104             default:
1105                 goto out;
1106             case '8': case '9':
1107                 if (argtype != 4)
1108                     goto out;
1109                 /* FALL THROUGH */
1110             case '0': case '1': case '2': case '3': case '4':
1111             case '5': case '6': case '7':
1112                 anum <<= argtype;
1113                 anum += *tmps++ & 15;
1114                 break;
1115             case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1116             case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1117                 if (argtype != 4)
1118                     goto out;
1119                 anum <<= 4;
1120                 anum += (*tmps++ & 7) + 9;
1121                 break;
1122             case 'x':
1123                 argtype = 4;
1124                 tmps++;
1125                 break;
1126             }
1127         }
1128       out:
1129         value = (double)anum;
1130         goto donumset;
1131     case O_CHMOD:
1132     case O_CHOWN:
1133     case O_KILL:
1134     case O_UNLINK:
1135     case O_UTIME:
1136         if (arg[1].arg_flags & AF_SPECIAL)
1137             value = (double)apply(optype,arg,Null(STR**));
1138         else {
1139             sarg[2] = Nullstr;
1140             value = (double)apply(optype,arg,sarg);
1141         }
1142         goto donumset;
1143     case O_UMASK:
1144         value = (double)umask((int)str_gnum(sarg[1]));
1145         goto donumset;
1146     case O_RENAME:
1147         tmps = str_get(sarg[1]);
1148 #ifdef RENAME
1149         value = (double)(rename(tmps,str_get(sarg[2])) >= 0);
1150 #else
1151         tmps2 = str_get(sarg[2]);
1152         if (euid || stat(tmps2,&statbuf) < 0 ||
1153           (statbuf.st_mode & S_IFMT) != S_IFDIR )
1154             UNLINK(tmps2);      /* avoid unlinking a directory */
1155         if (!(anum = link(tmps,tmps2)))
1156             anum = UNLINK(tmps);
1157         value = (double)(anum >= 0);
1158 #endif
1159         goto donumset;
1160     case O_LINK:
1161         tmps = str_get(sarg[1]);
1162         value = (double)(link(tmps,str_get(sarg[2])) >= 0);
1163         goto donumset;
1164     case O_UNSHIFT:
1165         ary = arg[2].arg_ptr.arg_stab->stab_array;
1166         if (arg[1].arg_flags & AF_SPECIAL)
1167             do_unshift(arg,ary);
1168         else {
1169             str = str_new(0);           /* must copy the STR */
1170             str_sset(str,sarg[1]);
1171             aunshift(ary,1);
1172             astore(ary,0,str);
1173         }
1174         value = (double)(ary->ary_fill + 1);
1175         break;
1176     case O_DOFILE:
1177     case O_EVAL:
1178         str_sset(str,
1179             do_eval(arg[1].arg_type != A_NULL ? sarg[1] : defstab->stab_val,
1180               optype) );
1181         STABSET(str);
1182         break;
1183
1184     case O_FTRREAD:
1185         argtype = 0;
1186         anum = S_IREAD;
1187         goto check_perm;
1188     case O_FTRWRITE:
1189         argtype = 0;
1190         anum = S_IWRITE;
1191         goto check_perm;
1192     case O_FTREXEC:
1193         argtype = 0;
1194         anum = S_IEXEC;
1195         goto check_perm;
1196     case O_FTEREAD:
1197         argtype = 1;
1198         anum = S_IREAD;
1199         goto check_perm;
1200     case O_FTEWRITE:
1201         argtype = 1;
1202         anum = S_IWRITE;
1203         goto check_perm;
1204     case O_FTEEXEC:
1205         argtype = 1;
1206         anum = S_IEXEC;
1207       check_perm:
1208         str = &str_no;
1209         if (mystat(arg,sarg[1]) < 0)
1210             break;
1211         if (cando(anum,argtype))
1212             str = &str_yes;
1213         break;
1214
1215     case O_FTIS:
1216         if (mystat(arg,sarg[1]) >= 0)
1217             str = &str_yes;
1218         else
1219             str = &str_no;
1220         break;
1221     case O_FTEOWNED:
1222     case O_FTROWNED:
1223         if (mystat(arg,sarg[1]) >= 0 &&
1224           statbuf.st_uid == (optype == O_FTEOWNED ? euid : uid) )
1225             str = &str_yes;
1226         else
1227             str = &str_no;
1228         break;
1229     case O_FTZERO:
1230         if (mystat(arg,sarg[1]) >= 0 && !statbuf.st_size)
1231             str = &str_yes;
1232         else
1233             str = &str_no;
1234         break;
1235     case O_FTSIZE:
1236         if (mystat(arg,sarg[1]) >= 0 && statbuf.st_size)
1237             str = &str_yes;
1238         else
1239             str = &str_no;
1240         break;
1241
1242     case O_FTSOCK:
1243 #ifdef S_IFSOCK
1244         anum = S_IFSOCK;
1245         goto check_file_type;
1246 #else
1247         str = &str_no;
1248         break;
1249 #endif
1250     case O_FTCHR:
1251         anum = S_IFCHR;
1252         goto check_file_type;
1253     case O_FTBLK:
1254         anum = S_IFBLK;
1255         goto check_file_type;
1256     case O_FTFILE:
1257         anum = S_IFREG;
1258         goto check_file_type;
1259     case O_FTDIR:
1260         anum = S_IFDIR;
1261       check_file_type:
1262         if (mystat(arg,sarg[1]) >= 0 &&
1263           (statbuf.st_mode & S_IFMT) == anum )
1264             str = &str_yes;
1265         else
1266             str = &str_no;
1267         break;
1268     case O_FTPIPE:
1269 #ifdef S_IFIFO
1270         anum = S_IFIFO;
1271         goto check_file_type;
1272 #else
1273         str = &str_no;
1274         break;
1275 #endif
1276     case O_FTLINK:
1277 #ifdef S_IFLNK
1278         if (lstat(str_get(sarg[1]),&statbuf) >= 0 &&
1279           (statbuf.st_mode & S_IFMT) == S_IFLNK )
1280             str = &str_yes;
1281         else
1282 #endif
1283             str = &str_no;
1284         break;
1285     case O_SYMLINK:
1286 #ifdef SYMLINK
1287         tmps = str_get(sarg[1]);
1288         value = (double)(symlink(tmps,str_get(sarg[2])) >= 0);
1289         goto donumset;
1290 #else
1291         fatal("Unsupported function symlink()");
1292 #endif
1293     case O_FTSUID:
1294         anum = S_ISUID;
1295         goto check_xid;
1296     case O_FTSGID:
1297         anum = S_ISGID;
1298         goto check_xid;
1299     case O_FTSVTX:
1300         anum = S_ISVTX;
1301       check_xid:
1302         if (mystat(arg,sarg[1]) >= 0 && statbuf.st_mode & anum)
1303             str = &str_yes;
1304         else
1305             str = &str_no;
1306         break;
1307     case O_FTTTY:
1308         if (arg[1].arg_flags & AF_SPECIAL) {
1309             stab = arg[1].arg_ptr.arg_stab;
1310             tmps = "";
1311         }
1312         else
1313             stab = stabent(tmps = str_get(sarg[1]),FALSE);
1314         if (stab && stab->stab_io && stab->stab_io->fp)
1315             anum = fileno(stab->stab_io->fp);
1316         else if (isdigit(*tmps))
1317             anum = atoi(tmps);
1318         else
1319             anum = -1;
1320         if (isatty(anum))
1321             str = &str_yes;
1322         else
1323             str = &str_no;
1324         break;
1325     case O_FTTEXT:
1326     case O_FTBINARY:
1327         str = do_fttext(arg,sarg[1]);
1328         break;
1329     }
1330     if (retary) {
1331         sarg[1] = str;
1332         maxsarg = sargoff + 1;
1333     }
1334 #ifdef DEBUGGING
1335     if (debug) {
1336         dlevel--;
1337         if (debug & 8)
1338             deb("%s RETURNS \"%s\"\n",opname[optype],str_get(str));
1339     }
1340 #endif
1341     goto freeargs;
1342
1343 array_return:
1344 #ifdef DEBUGGING
1345     if (debug) {
1346         dlevel--;
1347         if (debug & 8)
1348             deb("%s RETURNS ARRAY OF %d ARGS\n",opname[optype],maxsarg-sargoff);
1349     }
1350 #endif
1351     goto freeargs;
1352
1353 donumset:
1354     str_numset(str,value);
1355     STABSET(str);
1356     if (retary) {
1357         sarg[1] = str;
1358         maxsarg = sargoff + 1;
1359     }
1360 #ifdef DEBUGGING
1361     if (debug) {
1362         dlevel--;
1363         if (debug & 8)
1364             deb("%s RETURNS \"%f\"\n",opname[optype],value);
1365     }
1366 #endif
1367
1368 freeargs:
1369     sarg -= sargoff;
1370     if (sarg != quicksarg) {
1371         if (retary) {
1372             sarg[0] = &str_args;
1373             str_numset(sarg[0], (double)(maxsarg));
1374             sarg[maxsarg+1] = Nullstr;
1375             *retary = sarg;     /* up to them to free it */
1376         }
1377         else
1378             safefree((char*)sarg);
1379     }
1380     return str;
1381 }
1382
1383 int
1384 ingroup(gid,effective)
1385 int gid;
1386 int effective;
1387 {
1388     if (gid == (effective ? getegid() : getgid()))
1389         return TRUE;
1390 #ifdef GETGROUPS
1391 #ifndef NGROUPS
1392 #define NGROUPS 32
1393 #endif
1394     {
1395         GIDTYPE gary[NGROUPS];
1396         int anum;
1397
1398         anum = getgroups(NGROUPS,gary);
1399         while (--anum >= 0)
1400             if (gary[anum] == gid)
1401                 return TRUE;
1402     }
1403 #endif
1404     return FALSE;
1405 }
1406
1407 /* Do the permissions allow some operation?  Assumes statbuf already set. */
1408
1409 int
1410 cando(bit, effective)
1411 int bit;
1412 int effective;
1413 {
1414     if ((effective ? euid : uid) == 0) {        /* root is special */
1415         if (bit == S_IEXEC) {
1416             if (statbuf.st_mode & 0111 ||
1417               (statbuf.st_mode & S_IFMT) == S_IFDIR )
1418                 return TRUE;
1419         }
1420         else
1421             return TRUE;                /* root reads and writes anything */
1422         return FALSE;
1423     }
1424     if (statbuf.st_uid == (effective ? euid : uid) ) {
1425         if (statbuf.st_mode & bit)
1426             return TRUE;        /* ok as "user" */
1427     }
1428     else if (ingroup((int)statbuf.st_gid,effective)) {
1429         if (statbuf.st_mode & bit >> 3)
1430             return TRUE;        /* ok as "group" */
1431     }
1432     else if (statbuf.st_mode & bit >> 6)
1433         return TRUE;    /* ok as "other" */
1434     return FALSE;
1435 }