1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2  *@ Commands: conditional constructs.
3  *
4  * Copyright (c) 2014 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
5  * SPDX-License-Identifier: ISC
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #undef su_FILE
20 #define su_FILE cmd_cnd
21 #define mx_SOURCE
22 
23 #ifndef mx_HAVE_AMALGAMATION
24 # include "mx/nail.h"
25 #endif
26 
27 #include <su/cs.h>
28 #include <su/icodec.h>
29 #include <su/mem.h>
30 
31 /* TODO fake */
32 #include "su/code-in.h"
33 
34 #define a_CCND_IF_IS_ACTIVE() (n_go_data->gdc_ifcond != su_NIL)
35 #define a_CCND_IF_IS_SKIP() \
36    (a_CCND_IF_IS_ACTIVE() &&\
37       (((struct a_ccnd_if_node*)n_go_data->gdc_ifcond)->cin_noop ||\
38        !((struct a_ccnd_if_node*)n_go_data->gdc_ifcond)->cin_go))
39 
40 struct a_ccnd_if_node{
41    struct a_ccnd_if_node *cin_outer;
42    boole cin_error;    /* Bad expression, skip entire if..endif */
43    boole cin_noop;     /* Outer stack !cin_go, entirely no-op */
44    boole cin_go;       /* Green light */
45    boole cin_else;     /* In `else' clause */
46    u8 cin__dummy[4];
47 };
48 
49 struct a_ccnd_if_ctx{
50    char const * const *cic_argv_base;
51    char const * const *cic_argv_max;   /* BUT: .cic_argv MUST be terminated! */
52    char const * const *cic_argv;
53 };
54 
55 /* */
56 static void a_ccnd_oif_error(struct a_ccnd_if_ctx const *cicp,
57                char const *msg_or_null, char const *nearby_or_null);
58 
59 /* noop and (1) don't work for real, only syntax-check and
60  * (2) non-error return is ignored */
61 static s8 a_ccnd_oif_test(struct a_ccnd_if_ctx *cicp, boole noop);
62 static s8 a_ccnd_oif_group(struct a_ccnd_if_ctx *cicp, uz level,
63                boole noop);
64 
65 /* Shared `if' / `elif' implementation */
66 static int a_ccnd_if(void *v, boole iselif);
67 
68 static void
a_ccnd_oif_error(struct a_ccnd_if_ctx const * cicp,char const * msg_or_null,char const * nearby_or_null)69 a_ccnd_oif_error(struct a_ccnd_if_ctx const *cicp, char const *msg_or_null,
70       char const *nearby_or_null){
71    struct str s;
72    NYD2_IN;
73 
74    if(msg_or_null == NULL)
75       msg_or_null = _("invalid expression syntax");
76 
77    if(nearby_or_null != NULL)
78       n_err(_("if: %s -- near: %s\n"), msg_or_null, nearby_or_null);
79    else
80       n_err(_("if: %s\n"), msg_or_null);
81 
82    if((n_psonce & n_PSO_INTERACTIVE) || (n_poption & n_PO_D_V)){
83       str_concat_cpa(&s, cicp->cic_argv_base,
84          (*cicp->cic_argv_base != NULL ? " " : n_empty));
85       n_err(_("   Expression: %s\n"), s.s);
86 
87       str_concat_cpa(&s, cicp->cic_argv,
88          (*cicp->cic_argv != NULL ? " " : n_empty));
89       n_err(_("   Stopped at: %s\n"), s.s);
90    }
91    NYD2_OU;
92 }
93 
94 static s8
a_ccnd_oif_test(struct a_ccnd_if_ctx * cicp,boole noop)95 a_ccnd_oif_test(struct a_ccnd_if_ctx *cicp, boole noop){
96    char const *emsg, * const *argv, *cp, *lhv, *op, *rhv;
97    uz argc;
98    char c;
99    s8 rv;
100    NYD2_IN;
101 
102    rv = -1;
103    emsg = NULL;
104    argv = cicp->cic_argv;
105    argc = P2UZ(cicp->cic_argv_max - cicp->cic_argv);
106    cp = argv[0];
107 
108    if(UNLIKELY(argc != 1 && argc != 3 &&
109          (argc != 2 || !(n_pstate & n_PS_ARGMOD_WYSH)))){
110 jesyn:
111       if(emsg != NULL)
112          emsg = V_(emsg);
113 #ifdef mx_HAVE_REGEX
114 jesyn_ntr:
115 #endif
116       a_ccnd_oif_error(cicp, emsg, cp);
117       goto jleave;
118    }
119 
120    if(argc == 1){
121       switch(*cp){
122       case '$': /* v15compat */
123          if(!(n_pstate & n_PS_ARGMOD_WYSH)){
124             /* v15compat (!wysh): $ trigger? */
125             if(cp[1] == '\0')
126                goto jesyn;
127 
128             /* Look up the value in question, we need it anyway */
129             if(*++cp == '{'){
130                uz i = su_cs_len(cp);
131 
132                if(i > 0 && cp[i - 1] == '}')
133                   cp = savestrbuf(++cp, i -= 2);
134                else
135                   goto jesyn;
136             }
137 
138             lhv = noop ? NULL : n_var_vlook(cp, TRU1);
139             rv = (lhv != NULL);
140             break;
141          }
142          /* FALLTHRU */
143 
144       default:
145          switch((rv = n_boolify(cp, UZ_MAX, TRUM1))){
146          case FAL0:
147          case TRU1:
148             break;
149          default:
150             emsg = N_("Expected a boolean");
151             goto jesyn;
152          }
153          break;
154       case 'R': case 'r':
155          rv = ((n_psonce & n_PSO_SENDMODE) == 0);
156          break;
157       case 'S': case 's':
158          rv = ((n_psonce & n_PSO_SENDMODE) != 0);
159          break;
160       case 'T': case 't':
161          if(!su_cs_cmp_case(cp, "true")) /* Beware! */
162             rv = TRU1;
163          else
164             rv = ((n_psonce & n_PSO_INTERACTIVE) != 0);
165          break;
166       }
167    }else if(argc == 2){
168       ASSERT(n_pstate & n_PS_ARGMOD_WYSH);
169       emsg = N_("unrecognized condition");
170       if(cp[0] != '-' || cp[2] != '\0')
171          goto jesyn;
172 
173       switch((c = cp[1])){
174       case 'N':
175       case 'Z':
176          if(noop)
177             rv = TRU1;
178          else{
179             lhv = n_var_vlook(argv[1], TRU1);
180             rv = (c == 'N') ? (lhv != su_NIL) : (lhv == su_NIL);
181          }
182          break;
183       case 'n':
184       case 'z':
185          if(noop)
186             rv = TRU1;
187          else{
188             lhv = argv[1];
189             rv = (c == 'n') ? (*lhv != '\0') : (*lhv == '\0');
190          }
191          break;
192       default:
193          goto jesyn;
194       }
195    }else{
196       enum{
197          a_NONE,
198          a_MOD = 1u<<0,
199          a_ICASE = 1u<<1,
200          a_SATURATED = 1u<<2
201       } flags = a_NONE;
202 
203       if(n_pstate & n_PS_ARGMOD_WYSH)
204          lhv = cp;
205       else{
206          if(*cp == '$'){ /* v15compat (!wysh): $ trigger? */
207             if(cp[1] == '\0')
208                goto jesyn;
209 
210             /* Look up the value in question, we need it anyway */
211             if(*++cp == '{'){
212                uz i = su_cs_len(cp);
213 
214                if(i > 0 && cp[i - 1] == '}')
215                   cp = savestrbuf(++cp, i -= 2);
216                else
217                   goto jesyn;
218             }
219 
220             lhv = noop ? NULL : n_var_vlook(cp, TRU1);
221          }else
222             goto jesyn;
223       }
224 
225       /* Three argument comparison form required, check syntax */
226       emsg = N_("unrecognized condition");
227       op = argv[1];
228       if((c = op[0]) == '\0')
229          goto jesyn;
230 
231       /* May be modifier */
232       if(c == '@'){ /* v15compat */
233          n_OBSOLETE2(_("if/elif: please use ? modifier suffix, "
234                "not @ prefix: %s"),
235                savecatsep(n_shexp_quote_cp(argv[0], FAL0), ' ',
236                   savecatsep(n_shexp_quote_cp(argv[1], FAL0), ' ',
237                      n_shexp_quote_cp(argv[2], FAL0))));
238          for(;;){
239             c = *++op;
240             if(c == 'i')
241                flags |= a_ICASE;
242             else
243                break;
244          }
245          if(flags == a_NONE)
246             flags = a_ICASE;
247       }else
248       if((cp = su_cs_find_c(op, '?')) != su_NIL){
249          if(cp[1] == '\0')
250             flags |= a_MOD;
251          else if(su_cs_starts_with_case("case", &cp[1]))
252             flags |= a_ICASE;
253          else if(su_cs_starts_with_case("saturated", &cp[1]))
254             flags |= a_SATURATED;
255          else{
256             emsg = N_("invalid modifier");
257             goto jesyn;
258          }
259          op = savestrbuf(op, P2UZ(cp - op)); /* v15compat */
260          cp = argv[0];
261       }
262 
263       if(op[1] == '\0'){
264          if(c != '<' && c != '>')
265             goto jesyn;
266       }else if(c != '-' && op[2] != '\0')
267          goto jesyn;
268       else if(c == '<' || c == '>'){
269          if(op[1] != '=')
270             goto jesyn;
271       }else if(c == '=' || c == '!'){
272          if(op[1] != '=' && op[1] != '%' && op[1] != '@'
273 #ifdef mx_HAVE_REGEX
274                && op[1] != '~'
275 #endif
276          )
277             goto jesyn;
278       }else if(c == '-'){
279          if(op[1] == '\0' || op[2] == '\0' || op[3] != '\0')
280             goto jesyn;
281          if(op[1] == 'e'){
282             if(op[2] != 'q')
283                goto jesyn;
284          }else if(op[1] == 'g' || op[1] == 'l'){
285             if(op[2] != 'e' && op[2] != 't')
286                goto jesyn;
287          }else if(op[1] == 'n'){
288             if(op[2] != 'e')
289                goto jesyn;
290          }else
291             goto jesyn;
292       }else
293          goto jesyn;
294 
295       /* The right hand side may also be a variable, more syntax checking */
296       emsg = N_("invalid right hand side");
297       if((rhv = argv[2]) == NULL /* Can't happen */)
298          goto jesyn;
299 
300       if(!(n_pstate & n_PS_ARGMOD_WYSH)){
301          if(*rhv == '$'){/* v15compat */
302             if(*++rhv == '\0')
303                goto jesyn;
304             else if(*rhv == '{'){
305                uz i = su_cs_len(rhv);
306 
307                if(i > 0 && rhv[i - 1] == '}')
308                   rhv = savestrbuf(++rhv, i -= 2);
309                else{
310                   cp = --rhv;
311                   goto jesyn;
312                }
313             }
314             if(noop)
315                rhv = NULL;
316             else
317                rhv = n_var_vlook(cp = rhv, TRU1);
318          }
319       }
320 
321       /* A null value is treated as the empty string */
322       emsg = NULL;
323       if(lhv == NULL)
324          lhv = n_UNCONST(su_empty);
325       if(rhv == NULL)
326          rhv = n_UNCONST(su_empty);
327 
328 #ifdef mx_HAVE_REGEX
329       if(op[1] == '~'){
330          regex_t re;
331          int s;
332 
333          if(flags & a_SATURATED){
334             emsg = N_("invalid modifier for operational mode");
335             goto jesyn;
336          }
337 
338          if((s = regcomp(&re, rhv, REG_EXTENDED | REG_NOSUB |
339                (flags & (a_MOD | a_ICASE) ? REG_ICASE : 0))) != 0){
340             emsg = savecat(_("invalid regular expression: "),
341                   n_regex_err_to_doc(NULL, s));
342             goto jesyn_ntr;
343          }
344          if(!noop)
345             rv = (regexec(&re, lhv, 0,NULL, 0) == REG_NOMATCH) ^ (c == '=');
346          regfree(&re);
347       }else
348 #endif
349             if(noop){
350          ;
351       }else if(op[1] == '%' || op[1] == '@'){
352          if(flags & a_SATURATED){
353             emsg = N_("invalid modifier for operational mode");
354             goto jesyn;
355          }
356 
357          if(op[1] == '@') /* v15compat */
358             n_OBSOLETE("if++: \"=@\" and \"!@\" became \"=%\" and \"!%\"");
359          rv = ((flags & (a_MOD | a_ICASE) ? su_cs_find_case(lhv, rhv)
360                : su_cs_find(lhv, rhv)) == NULL) ^ (c == '=');
361       }else if(c == '-'){
362          u32 lhvis, rhvis;
363          s64 lhvi, rhvi;
364 
365          if(flags & a_ICASE){
366             emsg = N_("invalid modifier for operational mode");
367             goto jesyn;
368          }
369 
370          if(*lhv == '\0')
371             lhv = n_0;
372          if(*rhv == '\0')
373             rhv = n_0;
374          rhvis = lhvis = (flags & (a_MOD | a_SATURATED)
375                   ? su_IDEC_MODE_LIMIT_NOERROR : su_IDEC_MODE_NONE) |
376                su_IDEC_MODE_SIGNED_TYPE;
377          lhvis = su_idec_cp(&lhvi, lhv, 0, lhvis, su_NIL);
378          rhvis = su_idec_cp(&rhvi, rhv, 0, rhvis, su_NIL);
379 
380          if((lhvis & (su_IDEC_STATE_EMASK | su_IDEC_STATE_CONSUMED)
381                   ) != su_IDEC_STATE_CONSUMED ||
382                (rhvis & (su_IDEC_STATE_EMASK | su_IDEC_STATE_CONSUMED)
383                   ) != su_IDEC_STATE_CONSUMED){
384             /* TODO if/elif: should support $! and set ERR-OVERFLOW!! */
385             emsg = N_("invalid integer number");
386             goto jesyn;
387          }
388 
389          lhvi -= rhvi;
390          switch(op[1]){
391          default:
392          case 'e': rv = (lhvi == 0); break;
393          case 'n': rv = (lhvi != 0); break;
394          case 'l': rv = (op[2] == 't') ? lhvi < 0 : lhvi <= 0; break;
395          case 'g': rv = (op[2] == 't') ? lhvi > 0 : lhvi >= 0; break;
396          }
397          break;
398       }else{
399          s32 scmp;
400 
401          if(flags & a_SATURATED){
402             emsg = N_("invalid modifier for operational mode");
403             goto jesyn;
404          }
405 
406          scmp = (flags & (a_MOD | a_ICASE)) ? su_cs_cmp_case(lhv, rhv)
407                : su_cs_cmp(lhv, rhv);
408          switch(c){
409          default:
410          case '=': rv = (scmp == 0); break;
411          case '!': rv = (scmp != 0); break;
412          case '<': rv = (op[1] == '\0') ? scmp < 0 : scmp <= 0; break;
413          case '>': rv = (op[1] == '\0') ? scmp > 0 : scmp >= 0; break;
414          }
415       }
416    }
417 
418    if(noop && rv < 0)
419       rv = TRU1;
420 jleave:
421    NYD2_OU;
422    return rv;
423 }
424 
425 static s8
a_ccnd_oif_group(struct a_ccnd_if_ctx * cicp,uz level,boole noop)426 a_ccnd_oif_group(struct a_ccnd_if_ctx *cicp, uz level, boole noop){
427    char const *emsg, *arg0, * const *argv, * const *argv_max_save;
428    uz i;
429    char unary, c;
430    enum{
431       a_FIRST = 1<<0,
432       a_END_OK = 1<<1,
433       a_NEED_LIST = 1<<2,
434 
435       a_CANNOT_UNARY = a_NEED_LIST,
436       a_CANNOT_OBRACK = a_NEED_LIST,
437       a_CANNOT_CBRACK = a_FIRST,
438       a_CANNOT_LIST = a_FIRST,
439       a_CANNOT_COND = a_NEED_LIST
440    } state;
441    s8 rv, xrv;
442    NYD2_IN;
443 
444    rv = -1;
445    state = a_FIRST;
446    unary = '\0';
447    emsg = NULL;
448 
449    for(;;){
450       arg0 = *(argv = cicp->cic_argv);
451       if(arg0 == NULL){
452          if(!(state & a_END_OK)){
453             emsg = N_("missing expression (premature end)");
454             goto jesyn;
455          }
456          if(noop && rv < 0)
457             rv = TRU1;
458          break; /* goto jleave; */
459       }
460 
461       switch((c = *arg0)){
462       case '!':
463          if(arg0[1] != '\0')
464             goto jneed_cond;
465 
466          if(state & a_CANNOT_UNARY){
467             emsg = N_("cannot use a unary operator here");
468             goto jesyn;
469          }
470 
471          unary = (unary != '\0') ? '\0' : c;
472          state &= ~(a_FIRST | a_END_OK);
473          cicp->cic_argv = ++argv;
474          continue;
475 
476       case '[':
477       case ']':
478          if(arg0[1] != '\0')
479             goto jneed_cond;
480 
481          if(c == '['){
482             if(state & a_CANNOT_OBRACK){
483                emsg = N_("cannot open a group here");
484                goto jesyn;
485             }
486 
487             cicp->cic_argv = ++argv;
488             if((xrv = a_ccnd_oif_group(cicp, level + 1, noop)) < 0){
489                rv = xrv;
490                goto jleave;
491             }else if(!noop)
492                rv = (unary != '\0') ? !xrv : xrv;
493 
494             unary = '\0';
495             state &= ~(a_FIRST | a_END_OK);
496             state |= (level == 0 ? a_END_OK : 0) | a_NEED_LIST;
497             continue;
498          }else{
499             if(state & a_CANNOT_CBRACK){
500                emsg = N_("cannot use closing bracket here");
501                goto jesyn;
502             }
503 
504             if(level == 0){
505                emsg = N_("no open groups to be closed here");
506                goto jesyn;
507             }
508 
509             cicp->cic_argv = ++argv;
510             if(noop && rv < 0)
511                rv = TRU1;
512             goto jleave;/* break;break; */
513          }
514 
515       case '|':
516       case '&':
517          if(c != arg0[1] || arg0[2] != '\0')
518             goto jneed_cond;
519 
520          if(state & a_CANNOT_LIST){
521             emsg = N_("cannot use a AND-OR list here");
522             goto jesyn;
523          }
524 
525          noop = ((c == '&') ^ (rv == TRU1));
526          state &= ~(a_FIRST | a_END_OK | a_NEED_LIST);
527          cicp->cic_argv = ++argv;
528          continue;
529 
530       default:
531 jneed_cond:
532          if(state & a_CANNOT_COND){
533             emsg = N_("cannot use a `if' condition here");
534             goto jesyn;
535          }
536 
537          for(i = 0;; ++i){
538             if((arg0 = argv[i]) == NULL)
539                break;
540             c = *arg0;
541             if(c == '!' && arg0[1] == '\0')
542                break;
543             if((c == '[' || c == ']') && arg0[1] == '\0')
544                break;
545             if((c == '&' || c == '|') && c == arg0[1] && arg0[2] == '\0')
546                break;
547          }
548          if(i == 0){
549             emsg = N_("empty conditional group");
550             goto jesyn;
551          }
552 
553          argv_max_save = cicp->cic_argv_max;
554          cicp->cic_argv_max = argv + i;
555          if((xrv = a_ccnd_oif_test(cicp, noop)) < 0){
556             rv = xrv;
557             goto jleave;
558          }else if(!noop)
559             rv = (unary != '\0') ? !xrv : xrv;
560          cicp->cic_argv_max = argv_max_save;
561 
562          cicp->cic_argv = (argv += i);
563          unary = '\0';
564          state &= ~a_FIRST;
565          state |= a_END_OK | a_NEED_LIST;
566          break;
567       }
568    }
569 
570 jleave:
571    NYD2_OU;
572    return rv;
573 jesyn:
574    if(emsg == NULL)
575       emsg = N_("invalid grouping");
576    a_ccnd_oif_error(cicp, V_(emsg), arg0);
577    rv = -1;
578    goto jleave;
579 }
580 
581 static int
a_ccnd_if(void * v,boole iselif)582 a_ccnd_if(void *v, boole iselif){
583    struct a_ccnd_if_ctx cic;
584    char const * const *argv;
585    uz argc;
586    s8 xrv, rv;
587    struct a_ccnd_if_node *cinp;
588    NYD_IN;
589 
590    if(!iselif){
591       cinp = n_alloc(sizeof *cinp);
592       cinp->cin_outer = n_go_data->gdc_ifcond;
593    }else{
594       cinp = n_go_data->gdc_ifcond;
595       ASSERT(cinp != NULL);
596    }
597    cinp->cin_error = FAL0;
598    cinp->cin_noop = a_CCND_IF_IS_SKIP();
599    cinp->cin_go = TRU1;
600    cinp->cin_else = FAL0;
601    if(!iselif)
602       n_go_data->gdc_ifcond = cinp;
603 
604    if(cinp->cin_noop){
605       rv = 0;
606       goto jleave;
607    }
608 
609    /* For heaven's sake, support comments _today_ TODO wyshlist.. */
610    for(argc = 0, argv = v; argv[argc] != NULL; ++argc)
611       if(argv[argc][0] == '#'){
612          char const **nav = n_autorec_alloc(sizeof(char*) * (argc + 1));
613          uz i;
614 
615          for(i = 0; i < argc; ++i)
616             nav[i] = argv[i];
617          nav[i] = NULL;
618          argv = nav;
619          break;
620       }
621    cic.cic_argv_base = cic.cic_argv = argv;
622    cic.cic_argv_max = &argv[argc];
623    xrv = a_ccnd_oif_group(&cic, 0, FAL0);
624 
625    if(xrv >= 0){
626       cinp->cin_go = (boole)xrv;
627       rv = 0;
628    }else{
629       cinp->cin_error = cinp->cin_noop = TRU1;
630       rv = 1;
631    }
632 jleave:
633    NYD_OU;
634    return rv;
635 }
636 
637 FL int
c_if(void * v)638 c_if(void *v){
639    int rv;
640    NYD_IN;
641 
642    rv = a_ccnd_if(v, FAL0);
643    NYD_OU;
644    return rv;
645 }
646 
647 FL int
c_elif(void * v)648 c_elif(void *v){
649    struct a_ccnd_if_node *cinp;
650    int rv;
651    NYD_IN;
652 
653    if((cinp = n_go_data->gdc_ifcond) == NULL || cinp->cin_else){
654       n_err(_("elif: no matching `if'\n"));
655       rv = 1;
656    }else if(!cinp->cin_error){
657       cinp->cin_go = !cinp->cin_go; /* Cause right _IF_IS_SKIP() result */
658       rv = a_ccnd_if(v, TRU1);
659    }else
660       rv = 0;
661    NYD_OU;
662    return rv;
663 }
664 
665 FL int
c_else(void * v)666 c_else(void *v){
667    int rv;
668    struct a_ccnd_if_node *cinp;
669    NYD_IN;
670    UNUSED(v);
671 
672    if((cinp = n_go_data->gdc_ifcond) == NULL || cinp->cin_else){
673       n_err(_("else: no matching `if'\n"));
674       rv = 1;
675    }else{
676       cinp->cin_else = TRU1;
677       cinp->cin_go = !cinp->cin_go;
678       rv = 0;
679    }
680    NYD_OU;
681    return rv;
682 }
683 
684 FL int
c_endif(void * v)685 c_endif(void *v){
686    int rv;
687    struct a_ccnd_if_node *cinp;
688    NYD_IN;
689    UNUSED(v);
690 
691    if((cinp = n_go_data->gdc_ifcond) == NULL){
692       n_err(_("endif: no matching `if'\n"));
693       rv = 1;
694    }else{
695       n_go_data->gdc_ifcond = cinp->cin_outer;
696       n_free(cinp);
697       rv = 0;
698    }
699    NYD_OU;
700    return rv;
701 }
702 
703 FL boole
n_cnd_if_exists(void)704 n_cnd_if_exists(void){
705    boole rv;
706    NYD2_IN;
707 
708    if((rv = a_CCND_IF_IS_ACTIVE()) && a_CCND_IF_IS_SKIP())
709       rv = TRUM1;
710 
711    NYD2_OU;
712    return rv;
713 }
714 
715 FL void
n_cnd_if_stack_del(struct n_go_data_ctx * gdcp)716 n_cnd_if_stack_del(struct n_go_data_ctx *gdcp){
717    struct a_ccnd_if_node *vp, *cinp;
718    NYD2_IN;
719 
720    vp = gdcp->gdc_ifcond;
721    gdcp->gdc_ifcond = NULL;
722 
723    while((cinp = vp) != NULL){
724       vp = cinp->cin_outer;
725       n_free(cinp);
726    }
727    NYD2_OU;
728 }
729 
730 #include "su/code-ou.h"
731 /* s-it-mode */
732