11590Srgrimes/*- 2252231Spfg * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson. 31590Srgrimes * Copyright (c) 1992 Diomidis Spinellis. 41590Srgrimes * Copyright (c) 1992, 1993 51590Srgrimes * The Regents of the University of California. All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Diomidis Spinellis of Imperial College, University of London. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 4. Neither the name of the University nor the names of its contributors 191590Srgrimes * may be used to endorse or promote products derived from this software 201590Srgrimes * without specific prior written permission. 211590Srgrimes * 221590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321590Srgrimes * SUCH DAMAGE. 331590Srgrimes */ 341590Srgrimes 3587766Smarkm#include <sys/cdefs.h> 3687766Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/sed/main.c 362688 2020-06-27 14:31:33Z 0mp $"); 3787766Smarkm 381590Srgrimes#ifndef lint 3928066Scharnierstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1992, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4287766Smarkm#endif 431590Srgrimes 441590Srgrimes#ifndef lint 4587766Smarkmstatic const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; 4628066Scharnier#endif 471590Srgrimes 4898200Ssobomax#include <sys/types.h> 4998200Ssobomax#include <sys/mman.h> 5096175Sjmallett#include <sys/param.h> 5196175Sjmallett#include <sys/stat.h> 521590Srgrimes 5328066Scharnier#include <err.h> 541590Srgrimes#include <errno.h> 55200462Sdelphij#include <fcntl.h> 56141563Sstefanf#include <libgen.h> 57132145Stjr#include <limits.h> 5817522Sache#include <locale.h> 591590Srgrimes#include <regex.h> 60200462Sdelphij#include <stddef.h> 61252231Spfg#define _WITH_GETLINE 621590Srgrimes#include <stdio.h> 631590Srgrimes#include <stdlib.h> 641590Srgrimes#include <string.h> 651590Srgrimes#include <unistd.h> 661590Srgrimes 671590Srgrimes#include "defs.h" 681590Srgrimes#include "extern.h" 691590Srgrimes 701590Srgrimes/* 711590Srgrimes * Linked list of units (strings and files) to be compiled 721590Srgrimes */ 731590Srgrimesstruct s_compunit { 741590Srgrimes struct s_compunit *next; 751590Srgrimes enum e_cut {CU_FILE, CU_STRING} type; 761590Srgrimes char *s; /* Pointer to string or fname */ 771590Srgrimes}; 781590Srgrimes 791590Srgrimes/* 801590Srgrimes * Linked list pointer to compilation units and pointer to current 811590Srgrimes * next pointer. 821590Srgrimes */ 831590Srgrimesstatic struct s_compunit *script, **cu_nextp = &script; 841590Srgrimes 851590Srgrimes/* 861590Srgrimes * Linked list of files to be processed 871590Srgrimes */ 881590Srgrimesstruct s_flist { 891590Srgrimes char *fname; 901590Srgrimes struct s_flist *next; 911590Srgrimes}; 921590Srgrimes 931590Srgrimes/* 941590Srgrimes * Linked list pointer to files and pointer to current 951590Srgrimes * next pointer. 961590Srgrimes */ 971590Srgrimesstatic struct s_flist *files, **fl_nextp = &files; 981590Srgrimes 99122049SdesFILE *infile; /* Current input file */ 100122049SdesFILE *outfile; /* Current output file */ 10199352Stjr 1021590Srgrimesint aflag, eflag, nflag; 10358309Sgreenint rflags = 0; 104338462Smarkjint quit = 0; 10597238Stjrstatic int rval; /* Exit status */ 1061590Srgrimes 107168921Syarstatic int ispan; /* Whether inplace editing spans across files */ 108168921Syar 1091590Srgrimes/* 1101590Srgrimes * Current file and line number; line numbers restart across compilation 111168921Syar * units, but span across input files. The latter is optional if editing 112168921Syar * in place. 1131590Srgrimes */ 11487766Smarkmconst char *fname; /* File name. */ 115122049Sdesconst char *outfname; /* Output file name */ 116122049Sdesstatic char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ 117122049Sdesstatic char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ 118338462Smarkjconst char *inplace; /* Inplace edit file extension. */ 1191590Srgrimesu_long linenum; 1201590Srgrimes 12192922Simpstatic void add_compunit(enum e_cut, char *); 12292922Simpstatic void add_file(char *); 12392922Simpstatic void usage(void); 1241590Srgrimes 1251590Srgrimesint 126122044Sdesmain(int argc, char *argv[]) 1271590Srgrimes{ 128362688S0mp int c, fflag, fflagstdin; 129299294Spfg char *temp_arg; 1301590Srgrimes 13117522Sache (void) setlocale(LC_ALL, ""); 13217522Sache 1331590Srgrimes fflag = 0; 134362688S0mp fflagstdin = 0; 13596175Sjmallett inplace = NULL; 13696175Sjmallett 137267692Spfg while ((c = getopt(argc, argv, "EI:ae:f:i:lnru")) != -1) 1381590Srgrimes switch (c) { 139205992Simp case 'r': /* Gnu sed compat */ 14058309Sgreen case 'E': 14158309Sgreen rflags = REG_EXTENDED; 14258309Sgreen break; 143168921Syar case 'I': 144168921Syar inplace = optarg; 145168921Syar ispan = 1; /* span across input files */ 146168921Syar break; 1471590Srgrimes case 'a': 1481590Srgrimes aflag = 1; 1491590Srgrimes break; 1501590Srgrimes case 'e': 1511590Srgrimes eflag = 1; 152299294Spfg if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL) 153299294Spfg err(1, "malloc"); 154299294Spfg strcpy(temp_arg, optarg); 155299294Spfg strcat(temp_arg, "\n"); 156299294Spfg add_compunit(CU_STRING, temp_arg); 1571590Srgrimes break; 1581590Srgrimes case 'f': 1591590Srgrimes fflag = 1; 160362688S0mp if (strcmp(optarg, "-") == 0) 161362688S0mp fflagstdin = 1; 1621590Srgrimes add_compunit(CU_FILE, optarg); 1631590Srgrimes break; 16496175Sjmallett case 'i': 16596175Sjmallett inplace = optarg; 166168921Syar ispan = 0; /* don't span across input files */ 16796175Sjmallett break; 168146055Sglebius case 'l': 169267703Spfg if(setvbuf(stdout, NULL, _IOLBF, 0) != 0) 170267703Spfg warnx("setting line buffered output failed"); 171146055Sglebius break; 1721590Srgrimes case 'n': 1731590Srgrimes nflag = 1; 1741590Srgrimes break; 175267692Spfg case 'u': 176267703Spfg if(setvbuf(stdout, NULL, _IONBF, 0) != 0) 177267692Spfg warnx("setting unbuffered output failed"); 178267692Spfg break; 1791590Srgrimes default: 1801590Srgrimes case '?': 18128066Scharnier usage(); 1821590Srgrimes } 1831590Srgrimes argc -= optind; 1841590Srgrimes argv += optind; 1851590Srgrimes 1861590Srgrimes /* First usage case; script is the first arg */ 1871590Srgrimes if (!eflag && !fflag && *argv) { 1881590Srgrimes add_compunit(CU_STRING, *argv); 1891590Srgrimes argv++; 1901590Srgrimes } 1911590Srgrimes 1921590Srgrimes compile(); 1931590Srgrimes 1941590Srgrimes /* Continue with first and start second usage */ 1951590Srgrimes if (*argv) 1961590Srgrimes for (; *argv; argv++) 1971590Srgrimes add_file(*argv); 198362688S0mp else if (fflagstdin) 199362688S0mp exit(rval); 2001590Srgrimes else 2011590Srgrimes add_file(NULL); 2021590Srgrimes process(); 2031590Srgrimes cfclose(prog, NULL); 2041590Srgrimes if (fclose(stdout)) 20528066Scharnier err(1, "stdout"); 20697238Stjr exit(rval); 2071590Srgrimes} 2081590Srgrimes 20928066Scharnierstatic void 210122044Sdesusage(void) 21128066Scharnier{ 212267692Spfg (void)fprintf(stderr, 213268203Spfg "usage: %s script [-Ealnru] [-i extension] [file ...]\n" 214268193Spfg "\t%s [-Ealnu] [-i extension] [-e script] ... [-f script_file]" 215267692Spfg " ... [file ...]\n", getprogname(), getprogname()); 21628066Scharnier exit(1); 21728066Scharnier} 21828066Scharnier 2191590Srgrimes/* 2201590Srgrimes * Like fgets, but go through the chain of compilation units chaining them 2211590Srgrimes * together. Empty strings and files are ignored. 2221590Srgrimes */ 2231590Srgrimeschar * 224122044Sdescu_fgets(char *buf, int n, int *more) 2251590Srgrimes{ 2261590Srgrimes static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 2271590Srgrimes static FILE *f; /* Current open file */ 2281590Srgrimes static char *s; /* Current pointer inside string */ 2291590Srgrimes static char string_ident[30]; 2301590Srgrimes char *p; 2311590Srgrimes 2321590Srgrimesagain: 2331590Srgrimes switch (state) { 2341590Srgrimes case ST_EOF: 23541602Sarchie if (script == NULL) { 23641602Sarchie if (more != NULL) 23741602Sarchie *more = 0; 2381590Srgrimes return (NULL); 23941602Sarchie } 2401590Srgrimes linenum = 0; 2411590Srgrimes switch (script->type) { 2421590Srgrimes case CU_FILE: 243362688S0mp if (strcmp(script->s, "-") == 0) { 244362688S0mp f = stdin; 245362688S0mp fname = "stdin"; 246362688S0mp } else { 247362688S0mp if ((f = fopen(script->s, "r")) == NULL) 248362688S0mp err(1, "%s", script->s); 249362688S0mp fname = script->s; 250362688S0mp } 2511590Srgrimes state = ST_FILE; 2521590Srgrimes goto again; 2531590Srgrimes case CU_STRING: 254176126Sdwmalone if (((size_t)snprintf(string_ident, 2551590Srgrimes sizeof(string_ident), "\"%s\"", script->s)) >= 2561590Srgrimes sizeof(string_ident) - 1) 2571590Srgrimes (void)strcpy(string_ident + 2581590Srgrimes sizeof(string_ident) - 6, " ...\""); 2591590Srgrimes fname = string_ident; 2601590Srgrimes s = script->s; 2611590Srgrimes state = ST_STRING; 2621590Srgrimes goto again; 2631590Srgrimes } 2641590Srgrimes case ST_FILE: 2651590Srgrimes if ((p = fgets(buf, n, f)) != NULL) { 2661590Srgrimes linenum++; 2671590Srgrimes if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 2681590Srgrimes nflag = 1; 26941602Sarchie if (more != NULL) 27041602Sarchie *more = !feof(f); 2711590Srgrimes return (p); 2721590Srgrimes } 2731590Srgrimes script = script->next; 2741590Srgrimes (void)fclose(f); 2751590Srgrimes state = ST_EOF; 2761590Srgrimes goto again; 2771590Srgrimes case ST_STRING: 2781590Srgrimes if (linenum == 0 && s[0] == '#' && s[1] == 'n') 2791590Srgrimes nflag = 1; 2801590Srgrimes p = buf; 2811590Srgrimes for (;;) { 2821590Srgrimes if (n-- <= 1) { 2831590Srgrimes *p = '\0'; 2841590Srgrimes linenum++; 28541602Sarchie if (more != NULL) 28641602Sarchie *more = 1; 2871590Srgrimes return (buf); 2881590Srgrimes } 2891590Srgrimes switch (*s) { 2901590Srgrimes case '\0': 2911590Srgrimes state = ST_EOF; 2921590Srgrimes if (s == script->s) { 2931590Srgrimes script = script->next; 2941590Srgrimes goto again; 2951590Srgrimes } else { 2961590Srgrimes script = script->next; 2971590Srgrimes *p = '\0'; 2981590Srgrimes linenum++; 29941602Sarchie if (more != NULL) 30041602Sarchie *more = 0; 3011590Srgrimes return (buf); 3021590Srgrimes } 3031590Srgrimes case '\n': 3041590Srgrimes *p++ = '\n'; 3051590Srgrimes *p = '\0'; 3061590Srgrimes s++; 3071590Srgrimes linenum++; 30841602Sarchie if (more != NULL) 30941602Sarchie *more = 0; 3101590Srgrimes return (buf); 3111590Srgrimes default: 3121590Srgrimes *p++ = *s++; 3131590Srgrimes } 3141590Srgrimes } 3151590Srgrimes } 3161590Srgrimes /* NOTREACHED */ 31728066Scharnier return (NULL); 3181590Srgrimes} 3191590Srgrimes 3201590Srgrimes/* 3211590Srgrimes * Like fgets, but go through the list of files chaining them together. 3221590Srgrimes * Set len to the length of the line. 3231590Srgrimes */ 3241590Srgrimesint 325122044Sdesmf_fgets(SPACE *sp, enum e_spflag spflag) 3261590Srgrimes{ 327122049Sdes struct stat sb; 328252231Spfg ssize_t len; 329252231Spfg static char *p = NULL; 330252231Spfg static size_t plen = 0; 33119829Swosch int c; 33298200Ssobomax static int firstfile; 3331590Srgrimes 334122049Sdes if (infile == NULL) { 33598200Ssobomax /* stdin? */ 33698200Ssobomax if (files->fname == NULL) { 33798200Ssobomax if (inplace != NULL) 338168921Syar errx(1, "-I or -i may not be used with stdin"); 339122049Sdes infile = stdin; 34098200Ssobomax fname = "stdin"; 341122049Sdes outfile = stdout; 342122049Sdes outfname = "stdout"; 34398200Ssobomax } 34498200Ssobomax firstfile = 1; 34598200Ssobomax } 34698200Ssobomax 34798200Ssobomax for (;;) { 348338462Smarkj if (infile != NULL && (c = getc(infile)) != EOF && !quit) { 349122049Sdes (void)ungetc(c, infile); 35098200Ssobomax break; 35198200Ssobomax } 35298200Ssobomax /* If we are here then either eof or no files are open yet */ 353122049Sdes if (infile == stdin) { 35498294Stjr sp->len = 0; 35598200Ssobomax return (0); 35698200Ssobomax } 357122049Sdes if (infile != NULL) { 358122049Sdes fclose(infile); 359130039Sbrian if (*oldfname != '\0') { 360217133Sjilles /* if there was a backup file, remove it */ 361217133Sjilles unlink(oldfname); 362217133Sjilles /* 363217133Sjilles * Backup the original. Note that hard links 364217133Sjilles * are not supported on all filesystems. 365217133Sjilles */ 366217133Sjilles if ((link(fname, oldfname) != 0) && 367217133Sjilles (rename(fname, oldfname) != 0)) { 368130039Sbrian warn("rename()"); 369217133Sjilles if (*tmpfname) 370217133Sjilles unlink(tmpfname); 371130039Sbrian exit(1); 372130039Sbrian } 373130039Sbrian *oldfname = '\0'; 374122049Sdes } 375130039Sbrian if (*tmpfname != '\0') { 376130039Sbrian if (outfile != NULL && outfile != stdout) 377217133Sjilles if (fclose(outfile) != 0) { 378217133Sjilles warn("fclose()"); 379217133Sjilles unlink(tmpfname); 380217133Sjilles exit(1); 381217133Sjilles } 382130039Sbrian outfile = NULL; 383217133Sjilles if (rename(tmpfname, fname) != 0) { 384217133Sjilles /* this should not happen really! */ 385217133Sjilles warn("rename()"); 386217133Sjilles unlink(tmpfname); 387217133Sjilles exit(1); 388217133Sjilles } 389130039Sbrian *tmpfname = '\0'; 390130039Sbrian } 391122049Sdes outfname = NULL; 39298200Ssobomax } 393122049Sdes if (firstfile == 0) 3941590Srgrimes files = files->next; 395122049Sdes else 39698200Ssobomax firstfile = 0; 39798200Ssobomax if (files == NULL) { 39898294Stjr sp->len = 0; 39998200Ssobomax return (0); 4001590Srgrimes } 401122049Sdes fname = files->fname; 40298200Ssobomax if (inplace != NULL) { 403122049Sdes if (lstat(fname, &sb) != 0) 404122049Sdes err(1, "%s", fname); 405316441Sdelphij if (!S_ISREG(sb.st_mode)) 406122049Sdes errx(1, "%s: %s %s", fname, 407122049Sdes "in-place editing only", 408122049Sdes "works for regular files"); 409122049Sdes if (*inplace != '\0') { 410122049Sdes strlcpy(oldfname, fname, 411122049Sdes sizeof(oldfname)); 412122049Sdes len = strlcat(oldfname, inplace, 413122049Sdes sizeof(oldfname)); 414276832Spfg if (len > (ssize_t)sizeof(oldfname)) 415122049Sdes errx(1, "%s: name too long", fname); 416122049Sdes } 417122049Sdes len = snprintf(tmpfname, sizeof(tmpfname), 418122084Sdes "%s/.!%ld!%s", dirname(fname), (long)getpid(), 419122084Sdes basename(fname)); 420276832Spfg if (len >= (ssize_t)sizeof(tmpfname)) 421122049Sdes errx(1, "%s: name too long", fname); 422122049Sdes unlink(tmpfname); 423277811Spfg if (outfile != NULL && outfile != stdout) 424277811Spfg fclose(outfile); 425122049Sdes if ((outfile = fopen(tmpfname, "w")) == NULL) 426122049Sdes err(1, "%s", fname); 427122049Sdes fchown(fileno(outfile), sb.st_uid, sb.st_gid); 428122049Sdes fchmod(fileno(outfile), sb.st_mode & ALLPERMS); 429122049Sdes outfname = tmpfname; 430168921Syar if (!ispan) { 431168921Syar linenum = 0; 432170608Syar resetstate(); 433168921Syar } 434122049Sdes } else { 435122049Sdes outfile = stdout; 436122049Sdes outfname = "stdout"; 43798200Ssobomax } 438122049Sdes if ((infile = fopen(fname, "r")) == NULL) { 43998200Ssobomax warn("%s", fname); 44098201Stjr rval = 1; 44198200Ssobomax continue; 44298200Ssobomax } 4431590Srgrimes } 4441590Srgrimes /* 445122049Sdes * We are here only when infile is open and we still have something 44699352Stjr * to read from it. 44798200Ssobomax * 448252231Spfg * Use getline() so that we can handle essentially infinite input 449252231Spfg * data. The p and plen are static so each invocation gives 450252231Spfg * getline() the same buffer which is expanded as needed. 4511590Srgrimes */ 452252231Spfg len = getline(&p, &plen, infile); 453252231Spfg if (len == -1) 454252231Spfg err(1, "%s", fname); 455269729Sdumbbell if (len != 0 && p[len - 1] == '\n') { 456269729Sdumbbell sp->append_newline = 1; 45798601Stjr len--; 458269729Sdumbbell } else if (!lastline()) { 459269729Sdumbbell sp->append_newline = 1; 460269729Sdumbbell } else { 461269729Sdumbbell sp->append_newline = 0; 462269729Sdumbbell } 4631590Srgrimes cspace(sp, p, len, spflag); 4641590Srgrimes 4651590Srgrimes linenum++; 46698200Ssobomax 4671590Srgrimes return (1); 4681590Srgrimes} 4691590Srgrimes 4701590Srgrimes/* 4711590Srgrimes * Add a compilation unit to the linked list 4721590Srgrimes */ 4731590Srgrimesstatic void 474122044Sdesadd_compunit(enum e_cut type, char *s) 4751590Srgrimes{ 4761590Srgrimes struct s_compunit *cu; 4771590Srgrimes 47880286Sobrien if ((cu = malloc(sizeof(struct s_compunit))) == NULL) 47980286Sobrien err(1, "malloc"); 4801590Srgrimes cu->type = type; 4811590Srgrimes cu->s = s; 4821590Srgrimes cu->next = NULL; 4831590Srgrimes *cu_nextp = cu; 4841590Srgrimes cu_nextp = &cu->next; 4851590Srgrimes} 4861590Srgrimes 4871590Srgrimes/* 4881590Srgrimes * Add a file to the linked list 4891590Srgrimes */ 4901590Srgrimesstatic void 491122044Sdesadd_file(char *s) 4921590Srgrimes{ 4931590Srgrimes struct s_flist *fp; 4941590Srgrimes 49580286Sobrien if ((fp = malloc(sizeof(struct s_flist))) == NULL) 49680286Sobrien err(1, "malloc"); 4971590Srgrimes fp->next = NULL; 4981590Srgrimes *fl_nextp = fp; 4991590Srgrimes fp->fname = s; 5001590Srgrimes fl_nextp = &fp->next; 5011590Srgrimes} 50296175Sjmallett 503269729Sdumbbellstatic int 504276832Spfgnext_files_have_lines(void) 505269729Sdumbbell{ 506269729Sdumbbell struct s_flist *file; 507269729Sdumbbell FILE *file_fd; 508269729Sdumbbell int ch; 509269729Sdumbbell 510269729Sdumbbell file = files; 511269729Sdumbbell while ((file = file->next) != NULL) { 512269729Sdumbbell if ((file_fd = fopen(file->fname, "r")) == NULL) 513269729Sdumbbell continue; 514269729Sdumbbell 515269729Sdumbbell if ((ch = getc(file_fd)) != EOF) { 516269729Sdumbbell /* 517269729Sdumbbell * This next file has content, therefore current 518269729Sdumbbell * file doesn't contains the last line. 519269729Sdumbbell */ 520269729Sdumbbell ungetc(ch, file_fd); 521269729Sdumbbell fclose(file_fd); 522269729Sdumbbell return (1); 523269729Sdumbbell } 524269729Sdumbbell 525269729Sdumbbell fclose(file_fd); 526269729Sdumbbell } 527269729Sdumbbell 528269729Sdumbbell return (0); 529269729Sdumbbell} 530269729Sdumbbell 53199352Stjrint 53299352Stjrlastline(void) 53399352Stjr{ 53499352Stjr int ch; 53599352Stjr 536269729Sdumbbell if (feof(infile)) { 537269729Sdumbbell return !( 538269729Sdumbbell (inplace == NULL || ispan) && 539269729Sdumbbell next_files_have_lines()); 540269729Sdumbbell } 541269729Sdumbbell if ((ch = getc(infile)) == EOF) { 542269729Sdumbbell return !( 543269729Sdumbbell (inplace == NULL || ispan) && 544269729Sdumbbell next_files_have_lines()); 545269729Sdumbbell } 546122049Sdes ungetc(ch, infile); 54799352Stjr return (0); 54899352Stjr} 549