Move message related code to new message.c
[s-mailx.git] / fio.c
blobe302b6a3fd6ae424b805c31a8b913f801508ad2d
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ File operations.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 #undef n_FILE
36 #define n_FILE fio
38 #ifndef HAVE_AMALGAMATION
39 # include "nail.h"
40 #endif
43 struct fio_stack {
44 FILE *s_file; /* File we were in. */
45 void *s_cond; /* Saved state of conditional stack */
46 ui32_t s_pstate; /* Copy of ::pstate */
49 /* */
50 static struct fio_stack _fio_stack[FIO_STACK_SIZE];
51 static size_t _fio_stack_size;
52 static FILE * _fio_input;
54 /* line is a buffer with the result of fgets(). Returns the first newline or
55 * the last character read */
56 static size_t _length_of_line(char const *line, size_t linesize);
58 /* Read a line, one character at a time */
59 static char * _fgetline_byone(char **line, size_t *linesize, size_t *llen,
60 FILE *fp, int appendnl, size_t n SMALLOC_DEBUG_ARGS);
62 /* Workhorse */
63 static bool_t a_file_lock(int fd, enum n_file_lock_type ft, off_t off, off_t len);
65 /* `source' and `source_if' (if silent_error: no pipes allowed, then) */
66 static bool_t _source_file(char const *file, bool_t silent_error);
68 static size_t
69 _length_of_line(char const *line, size_t linesize)
71 size_t i;
72 NYD2_ENTER;
74 /* Last character is always '\0' and was added by fgets() */
75 for (--linesize, i = 0; i < linesize; i++)
76 if (line[i] == '\n')
77 break;
78 i = (i < linesize) ? i + 1 : linesize;
79 NYD2_LEAVE;
80 return i;
83 static char *
84 _fgetline_byone(char **line, size_t *linesize, size_t *llen, FILE *fp,
85 int appendnl, size_t n SMALLOC_DEBUG_ARGS)
87 char *rv;
88 int c;
89 NYD2_ENTER;
91 assert(*linesize == 0 || *line != NULL);
92 for (rv = *line;;) {
93 if (*linesize <= LINESIZE || n >= *linesize - 128) {
94 *linesize += ((rv == NULL) ? LINESIZE + n + 1 : 256);
95 *line = rv = (srealloc)(rv, *linesize SMALLOC_DEBUG_ARGSCALL);
97 c = getc(fp);
98 if (c != EOF) {
99 rv[n++] = c;
100 rv[n] = '\0';
101 if (c == '\n')
102 break;
103 } else {
104 if (n > 0) {
105 if (appendnl) {
106 rv[n++] = '\n';
107 rv[n] = '\0';
109 break;
110 } else {
111 rv = NULL;
112 goto jleave;
116 if (llen)
117 *llen = n;
118 jleave:
119 NYD2_LEAVE;
120 return rv;
123 static bool_t
124 a_file_lock(int fd, enum n_file_lock_type flt, off_t off, off_t len)
126 struct flock flp;
127 bool_t rv;
128 NYD2_ENTER;
130 memset(&flp, 0, sizeof flp);
132 switch (flt) {
133 default:
134 case FLT_READ: rv = F_RDLCK; break;
135 case FLT_WRITE: rv = F_WRLCK; break;
137 flp.l_type = rv;
138 flp.l_start = off;
139 flp.l_whence = SEEK_SET;
140 flp.l_len = len;
142 rv = (fcntl(fd, F_SETLK, &flp) != -1);
143 NYD2_LEAVE;
144 return rv;
147 static bool_t
148 _source_file(char const *file, bool_t silent_error)
150 char *cp;
151 bool_t ispipe;
152 FILE *fi;
153 NYD_ENTER;
155 fi = NULL;
157 if ((ispipe = !silent_error)) {
158 size_t i = strlen(file);
160 while (i > 0 && spacechar(file[i - 1]))
161 --i;
162 if (i > 0 && file[i - 1] == '|')
163 cp = savestrbuf(file, --i);
164 else
165 ispipe = FAL0;
168 if (ispipe) {
169 char const *sh;
171 if ((sh = ok_vlook(SHELL)) == NULL)
172 sh = XSHELL;
173 if ((fi = Popen(cp, "r", sh, NULL, COMMAND_FD_NULL)) == NULL) {
174 n_perr(cp, 0);
175 goto jleave;
177 } else if ((cp = fexpand(file, FEXP_LOCAL)) == NULL)
178 goto jleave;
179 else if ((fi = Fopen(cp, "r")) == NULL) {
180 if (!silent_error || (options & OPT_D_V))
181 n_perr(cp, 0);
182 goto jleave;
185 if (temporary_localopts_store != NULL) {
186 n_err(_("Before v15 you cannot `source' from within macros, sorry\n"));
187 goto jeclose;
189 if (_fio_stack_size >= NELEM(_fio_stack)) {
190 n_err(_("Too many `source' recursions\n"));
191 jeclose:
192 if (ispipe)
193 Pclose(fi, TRU1);
194 else
195 Fclose(fi);
196 fi = NULL;
197 goto jleave;
200 _fio_stack[_fio_stack_size].s_file = _fio_input;
201 _fio_stack[_fio_stack_size].s_cond = condstack_release();
202 _fio_stack[_fio_stack_size].s_pstate = pstate;
203 ++_fio_stack_size;
204 pstate &= ~(PS_LOADING | PS_PIPING);
205 pstate |= PS_SOURCING | (ispipe ? PS_PIPING : PS_NONE);
206 _fio_input = fi;
207 jleave:
208 NYD_LEAVE;
209 return (fi != NULL);
212 FL char *
213 (fgetline)(char **line, size_t *linesize, size_t *cnt, size_t *llen, FILE *fp,
214 int appendnl SMALLOC_DEBUG_ARGS)
216 size_t i_llen, sz;
217 char *rv;
218 NYD2_ENTER;
220 if (cnt == NULL) {
221 /* Without count, we can't determine where the chars returned by fgets()
222 * end if there's no newline. We have to read one character by one */
223 rv = _fgetline_byone(line, linesize, llen, fp, appendnl, 0
224 SMALLOC_DEBUG_ARGSCALL);
225 goto jleave;
228 if ((rv = *line) == NULL || *linesize < LINESIZE)
229 *line = rv = (srealloc)(rv, *linesize = LINESIZE SMALLOC_DEBUG_ARGSCALL);
230 sz = (*linesize <= *cnt) ? *linesize : *cnt + 1;
231 if (sz <= 1 || fgets(rv, sz, fp) == NULL) {
232 /* Leave llen untouched; it is used to determine whether the last line
233 * was \n-terminated in some callers */
234 rv = NULL;
235 goto jleave;
238 i_llen = _length_of_line(rv, sz);
239 *cnt -= i_llen;
240 while (rv[i_llen - 1] != '\n') {
241 *line = rv = (srealloc)(rv, *linesize += 256 SMALLOC_DEBUG_ARGSCALL);
242 sz = *linesize - i_llen;
243 sz = (sz <= *cnt) ? sz : *cnt + 1;
244 if (sz <= 1 || fgets(rv + i_llen, sz, fp) == NULL) {
245 if (appendnl) {
246 rv[i_llen++] = '\n';
247 rv[i_llen] = '\0';
249 break;
251 sz = _length_of_line(rv + i_llen, sz);
252 i_llen += sz;
253 *cnt -= sz;
255 if (llen)
256 *llen = i_llen;
257 jleave:
258 NYD2_LEAVE;
259 return rv;
262 FL int
263 (readline_restart)(FILE *ibuf, char **linebuf, size_t *linesize, size_t n
264 SMALLOC_DEBUG_ARGS)
266 /* TODO readline_restart(): always *appends* LF just to strip it again;
267 * TODO should be configurable just as for fgetline(); ..or whatever.. */
268 int rv = -1;
269 long sz;
270 NYD2_ENTER;
272 clearerr(ibuf);
274 /* Interrupts will cause trouble if we are inside a stdio call. As this is
275 * only relevant if input is from tty, bypass it by read(), then */
276 if (fileno(ibuf) == 0 && (options & OPT_TTYIN)) {
277 assert(*linesize == 0 || *linebuf != NULL);
278 for (;;) {
279 if (*linesize <= LINESIZE || n >= *linesize - 128) {
280 *linesize += ((*linebuf == NULL) ? LINESIZE + n + 1 : 256);
281 *linebuf = (srealloc)(*linebuf, *linesize SMALLOC_DEBUG_ARGSCALL);
283 jagain:
284 sz = read(0, *linebuf + n, *linesize - n - 1);
285 if (sz > 0) {
286 n += sz;
287 (*linebuf)[n] = '\0';
288 if (n > 0 && (*linebuf)[n - 1] == '\n')
289 break;
290 } else {
291 if (sz < 0 && errno == EINTR)
292 goto jagain;
293 if (n > 0) {
294 if ((*linebuf)[n - 1] != '\n') {
295 (*linebuf)[n++] = '\n';
296 (*linebuf)[n] = '\0';
298 break;
299 } else
300 goto jleave;
303 } else {
304 /* Not reading from standard input or standard input not a terminal. We
305 * read one char at a time as it is the only way to get lines with
306 * embedded NUL characters in standard stdio */
307 if (_fgetline_byone(linebuf, linesize, &n, ibuf, 1, n
308 SMALLOC_DEBUG_ARGSCALL) == NULL)
309 goto jleave;
311 if (n > 0 && (*linebuf)[n - 1] == '\n')
312 (*linebuf)[--n] = '\0';
313 rv = (int)n;
314 jleave:
315 NYD2_LEAVE;
316 return rv;
319 FL int
320 (readline_input)(char const *prompt, bool_t nl_escape, char **linebuf,
321 size_t *linesize, char const *string SMALLOC_DEBUG_ARGS)
323 /* TODO readline: linebuf pool! */
324 FILE *ifile = (_fio_input != NULL) ? _fio_input : stdin;
325 bool_t doprompt, dotty;
326 int n, nold;
327 NYD2_ENTER;
329 doprompt = (!(pstate & PS_SOURCING) && (options & OPT_INTERACTIVE));
330 dotty = (doprompt && !ok_blook(line_editor_disable));
331 if (!doprompt)
332 prompt = NULL;
333 else if (prompt == NULL)
334 prompt = getprompt();
336 /* Ensure stdout is flushed first anyway */
337 if (!dotty && prompt == NULL)
338 fflush(stdout);
340 for (nold = n = 0;;) {
341 if (dotty) {
342 assert(ifile == stdin);
343 if (string != NULL && (n = (int)strlen(string)) > 0) {
344 if (*linesize > 0)
345 *linesize += n +1;
346 else
347 *linesize = (size_t)n + LINESIZE +1;
348 *linebuf = (srealloc)(*linebuf, *linesize SMALLOC_DEBUG_ARGSCALL);
349 memcpy(*linebuf, string, (size_t)n +1);
351 string = NULL;
352 /* TODO if nold>0, don't redisplay the entire line!
353 * TODO needs complete redesign ... */
354 n = (n_tty_readline)(prompt, linebuf, linesize, n
355 SMALLOC_DEBUG_ARGSCALL);
356 } else {
357 if (prompt != NULL) {
358 if (*prompt != '\0')
359 fputs(prompt, stdout);
360 fflush(stdout);
362 n = (readline_restart)(ifile, linebuf, linesize, n
363 SMALLOC_DEBUG_ARGSCALL);
365 if (n > 0 && nold > 0) {
366 int i = 0;
367 char const *cp = *linebuf + nold;
369 while (blankspacechar(*cp) && nold + i < n)
370 ++cp, ++i;
371 if (i > 0) {
372 memmove(*linebuf + nold, cp, n - nold - i);
373 n -= i;
374 (*linebuf)[n] = '\0';
378 if (n <= 0)
379 break;
381 /* POSIX says:
382 * An unquoted <backslash> at the end of a command line shall
383 * be discarded and the next line shall continue the command */
384 if (!nl_escape || n == 0 || (*linebuf)[n - 1] != '\\')
385 break;
386 (*linebuf)[nold = --n] = '\0';
387 if (prompt != NULL && *prompt != '\0')
388 prompt = ".. "; /* XXX PS2 .. */
391 if (n >= 0 && (options & OPT_D_VV))
392 n_err(_("%s %d bytes <%.*s>\n"),
393 ((pstate & PS_LOADING) ? "LOAD"
394 : (pstate & PS_SOURCING) ? "SOURCE" : "READ"),
395 n, n, *linebuf);
396 NYD2_LEAVE;
397 return n;
400 FL char *
401 n_input_cp_addhist(char const *prompt, char const *string, bool_t isgabby)
403 /* FIXME n_input_cp_addhist(): leaks on sigjmp without linepool */
404 size_t linesize = 0;
405 char *linebuf = NULL, *rv = NULL;
406 int n;
407 NYD2_ENTER;
409 n = readline_input(prompt, FAL0, &linebuf, &linesize, string);
410 if (n > 0 && *(rv = savestrbuf(linebuf, (size_t)n)) != '\0' &&
411 (options & OPT_INTERACTIVE))
412 n_tty_addhist(rv, isgabby);
414 if (linebuf != NULL)
415 free(linebuf);
416 NYD2_LEAVE;
417 return rv;
420 FL void
421 setptr(FILE *ibuf, off_t offset)
423 struct message self;
424 char *cp, *linebuf = NULL;
425 char const *cp2;
426 int c, maybe = 1, inhead = 0, selfcnt = 0;
427 size_t linesize = 0, filesize, cnt;
428 NYD_ENTER;
430 memset(&self, 0, sizeof self);
431 self.m_flag = MUSED | MNEW | MNEWEST;
432 filesize = mailsize - offset;
433 offset = ftell(mb.mb_otf);
435 for (;;) {
436 if (fgetline(&linebuf, &linesize, &filesize, &cnt, ibuf, 0) == NULL) {
437 self.m_xsize = self.m_size;
438 self.m_xlines = self.m_lines;
439 self.m_have = HAVE_HEADER | HAVE_BODY;
440 if (selfcnt > 0)
441 message_append(&self);
442 message_append_null();
443 if (linebuf != NULL)
444 free(linebuf);
445 break;
448 #ifdef notdef
449 if (linebuf[0] == '\0')
450 linebuf[0] = '.';
451 #endif
452 /* XXX Convert CRLF to LF; this should be rethought in that
453 * XXX CRLF input should possibly end as CRLF output? */
454 if (cnt >= 2 && linebuf[cnt - 1] == '\n' && linebuf[cnt - 2] == '\r')
455 linebuf[--cnt - 1] = '\n';
456 fwrite(linebuf, sizeof *linebuf, cnt, mb.mb_otf);
457 if (ferror(mb.mb_otf)) {
458 n_perr(_("/tmp"), 0);
459 exit(EXIT_ERR);
461 if (linebuf[cnt - 1] == '\n')
462 linebuf[cnt - 1] = '\0';
463 if (maybe && linebuf[0] == 'F' && is_head(linebuf, cnt, FAL0)) {
464 /* TODO char date[FROM_DATEBUF];
465 * TODO extract_date_from_from_(linebuf, cnt, date);
466 * TODO self.m_time = 10000; */
467 self.m_xsize = self.m_size;
468 self.m_xlines = self.m_lines;
469 self.m_have = HAVE_HEADER | HAVE_BODY;
470 if (selfcnt++ > 0)
471 message_append(&self);
472 msgCount++;
473 self.m_flag = MUSED | MNEW | MNEWEST;
474 self.m_size = 0;
475 self.m_lines = 0;
476 self.m_block = mailx_blockof(offset);
477 self.m_offset = mailx_offsetof(offset);
478 inhead = 1;
479 } else if (linebuf[0] == 0) {
480 inhead = 0;
481 } else if (inhead) {
482 for (cp = linebuf, cp2 = "status";; ++cp) {
483 if ((c = *cp2++) == 0) {
484 while (c = *cp++, whitechar(c))
486 if (cp[-1] != ':')
487 break;
488 while ((c = *cp++) != '\0')
489 if (c == 'R')
490 self.m_flag |= MREAD;
491 else if (c == 'O')
492 self.m_flag &= ~MNEW;
493 break;
495 if (*cp != c && *cp != upperconv(c))
496 break;
498 for (cp = linebuf, cp2 = "x-status";; ++cp) {
499 if ((c = *cp2++) == 0) {
500 while ((c = *cp++, whitechar(c)))
502 if (cp[-1] != ':')
503 break;
504 while ((c = *cp++) != '\0')
505 if (c == 'F')
506 self.m_flag |= MFLAGGED;
507 else if (c == 'A')
508 self.m_flag |= MANSWERED;
509 else if (c == 'T')
510 self.m_flag |= MDRAFTED;
511 break;
513 if (*cp != c && *cp != upperconv(c))
514 break;
517 offset += cnt;
518 self.m_size += cnt;
519 ++self.m_lines;
520 maybe = linebuf[0] == 0;
522 NYD_LEAVE;
525 FL int
526 putline(FILE *obuf, char *linebuf, size_t cnt)
528 int rv = -1;
529 NYD_ENTER;
531 fwrite(linebuf, sizeof *linebuf, cnt, obuf);
532 putc('\n', obuf);
533 if (!ferror(obuf))
534 rv = (int)(cnt + 1);
535 NYD_LEAVE;
536 return rv;
539 FL off_t
540 fsize(FILE *iob)
542 struct stat sbuf;
543 off_t rv;
544 NYD_ENTER;
546 rv = (fstat(fileno(iob), &sbuf) == -1) ? 0 : sbuf.st_size;
547 NYD_LEAVE;
548 return rv;
551 FL bool_t
552 var_folder_updated(char const *name, char **store)
554 char rv = TRU1;
555 char *folder, *unres = NULL, *res = NULL;
556 NYD_ENTER;
558 if ((folder = UNCONST(name)) == NULL)
559 goto jleave;
561 /* Expand the *folder*; skip %: prefix for simplicity of use */
562 /* XXX This *only* works because we do NOT
563 * XXX update environment variables via the "set" mechanism */
564 if (folder[0] == '%' && folder[1] == ':')
565 folder += 2;
566 if ((folder = fexpand(folder, FEXP_FULL)) == NULL) /* XXX error? */
567 goto jleave;
569 switch (which_protocol(folder)) {
570 case PROTO_POP3:
571 n_err(_("*folder* cannot be set to a flat, readonly POP3 account\n"));
572 rv = FAL0;
573 goto jleave;
574 default:
575 /* Further expansion desired */
576 break;
579 /* All non-absolute paths are relative to our home directory */
580 if (*folder != '/') {
581 size_t l1 = strlen(homedir), l2 = strlen(folder);
582 unres = ac_alloc(l1 + l2 + 1 +1);
583 memcpy(unres, homedir, l1);
584 unres[l1] = '/';
585 memcpy(unres + l1 + 1, folder, l2);
586 unres[l1 + 1 + l2] = '\0';
587 folder = unres;
590 /* Since lex.c:_update_mailname() uses realpath(3) if available to
591 * avoid that we loose track of our currently open folder in case we
592 * chdir away, but still checks the leading path portion against
593 * getfold() to be able to abbreviate to the +FOLDER syntax if
594 * possible, we need to realpath(3) the folder, too */
595 #ifdef HAVE_REALPATH
596 res = ac_alloc(PATH_MAX +1);
597 if (realpath(folder, res) == NULL)
598 n_err(_("Can't canonicalize \"%s\"\n"), folder);
599 else
600 folder = res;
601 #endif
603 *store = sstrdup(folder);
605 if (res != NULL)
606 ac_free(res);
607 if (unres != NULL)
608 ac_free(unres);
609 jleave:
610 NYD_LEAVE;
611 return rv;
614 FL char const *
615 getdeadletter(void) /* XXX should that be in auxlily.c? */
617 char const *cp;
618 NYD_ENTER;
620 if ((cp = ok_vlook(DEAD)) == NULL || (cp = fexpand(cp, FEXP_LOCAL)) == NULL)
621 cp = fexpand("~/dead.letter", FEXP_LOCAL | FEXP_SHELL);
622 else if (*cp != '/') {
623 size_t sz = strlen(cp) + 2 +1;
624 char *buf = ac_alloc(sz);
626 snprintf(buf, sz, "~/%s", cp);
627 cp = fexpand(buf, FEXP_LOCAL | FEXP_SHELL);
628 ac_free(buf);
631 if (cp == NULL)
632 cp = "dead.letter"; /* XXX magic -> nail.h (POSIX thing though) */
633 NYD_LEAVE;
634 return cp;
637 FL bool_t
638 n_file_lock(int fd, enum n_file_lock_type flt, off_t off, off_t len,
639 size_t pollmsecs)
641 size_t tries;
642 bool_t rv;
643 NYD_ENTER;
645 for (tries = 0; tries <= FILE_LOCK_TRIES; ++tries)
646 if ((rv = a_file_lock(fd, flt, off, len)) || pollmsecs == 0)
647 break;
648 else
649 n_msleep(pollmsecs, FAL0);
650 NYD_LEAVE;
651 return rv;
654 FL void
655 load(char const *name)
657 struct str n;
658 void *cond;
659 FILE *in, *oldin;
660 NYD_ENTER;
662 if (name == NULL || *name == '\0' || (in = Fopen(name, "r")) == NULL)
663 goto jleave;
665 oldin = _fio_input;
666 _fio_input = in;
667 pstate |= PS_IN_LOAD;
668 /* commands() may sreset(), copy over file name */
669 n.l = strlen(name);
670 n.s = ac_alloc(n.l +1);
671 memcpy(n.s, name, n.l +1);
673 cond = condstack_release();
674 if (!commands())
675 n_err(_("Stopped loading \"%s\" due to errors "
676 "(enable *debug* for trace)\n"), n.s);
677 condstack_take(cond);
679 ac_free(n.s);
680 pstate &= ~PS_IN_LOAD;
681 _fio_input = oldin;
682 Fclose(in);
683 jleave:
684 NYD_LEAVE;
687 FL int
688 c_source(void *v)
690 int rv;
691 NYD_ENTER;
693 rv = _source_file(*(char**)v, FAL0) ? 0 : 1;
694 NYD_LEAVE;
695 return rv;
698 FL int
699 c_source_if(void *v) /* XXX obsolete?, support file tests in `if' etc.! */
701 int rv;
702 NYD_ENTER;
704 rv = _source_file(*(char**)v, TRU1) ? 0 : 1;
705 rv = 0;
706 NYD_LEAVE;
707 return rv;
710 FL int
711 unstack(void)
713 int rv = 1;
714 NYD_ENTER;
716 if (_fio_stack_size == 0) {
717 n_err(_("`source' stack over-pop\n"));
718 pstate &= ~PS_SOURCING;
719 goto jleave;
722 if (pstate & PS_PIPING)
723 Pclose(_fio_input, TRU1);
724 else
725 Fclose(_fio_input);
727 --_fio_stack_size;
728 if (!condstack_take(_fio_stack[_fio_stack_size].s_cond))
729 n_err(_("Unmatched \"if\"\n"));
730 pstate &= ~(PS_LOADING | PS_PIPING);
731 pstate |= _fio_stack[_fio_stack_size].s_pstate & (PS_LOADING | PS_PIPING);
732 _fio_input = _fio_stack[_fio_stack_size].s_file;
733 if (_fio_stack_size == 0) {
734 if (pstate & PS_LOADING)
735 pstate |= PS_SOURCING;
736 else
737 pstate &= ~PS_SOURCING;
739 rv = 0;
740 jleave:
741 NYD_LEAVE;
742 return rv;
745 /* s-it-mode */