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