1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1992-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * * 20*4887Schin ***********************************************************************/ 21*4887Schin #pragma prototyped 22*4887Schin 23*4887Schin static const char usage[] = 24*4887Schin "[-?\n@(#)$Id: fmt (AT&T Research) 2007-01-02 $\n]" 25*4887Schin USAGE_LICENSE 26*4887Schin "[+NAME?fmt - simple text formatter]" 27*4887Schin "[+DESCRIPTION?\bfmt\b reads the input files and left justifies space " 28*4887Schin "separated words into lines \awidth\a characters or less in length and " 29*4887Schin "writes the lines to the standard output. The standard input is read if " 30*4887Schin "\b-\b or no files are specified. Blank lines and interword spacing are " 31*4887Schin "preserved in the output. Indentation is preserved, and lines with " 32*4887Schin "identical indentation are joined and justified.]" 33*4887Schin "[+?\bfmt\b is meant to format mail messages prior to sending, but may " 34*4887Schin "also be useful for other simple tasks. For example, in \bvi\b(1) the " 35*4887Schin "command \b:!}fmt\b will justify the lines in the current paragraph.]" 36*4887Schin "[c:crown-margin?Preserve the indentation of the first two lines within " 37*4887Schin "a paragraph, and align the left margin of each subsequent line with " 38*4887Schin "that of the second line.]" 39*4887Schin "[o:optget?Format concatenated \boptget\b(3) usage strings.]" 40*4887Schin "[s:split-only?Split lines only; do not join short lines to form longer " 41*4887Schin "ones.]" 42*4887Schin "[u:uniform-spacing?One space between words, two after sentences.]" 43*4887Schin "[w:width?Set the output line width to \acolumns\a.]#[columns:=72]" 44*4887Schin "\n\n" 45*4887Schin "[ file ... ]" 46*4887Schin "\n\n" 47*4887Schin "[+SEE ALSO?\bmailx\b(1), \bnroff\b(1), \btroff\b(1), \bvi\b(1), " 48*4887Schin "\boptget\b(3)]" 49*4887Schin ; 50*4887Schin 51*4887Schin #include <cmd.h> 52*4887Schin #include <ctype.h> 53*4887Schin 54*4887Schin typedef struct Fmt_s 55*4887Schin { 56*4887Schin long flags; 57*4887Schin char* outp; 58*4887Schin char* outbuf; 59*4887Schin char* endbuf; 60*4887Schin Sfio_t* in; 61*4887Schin Sfio_t* out; 62*4887Schin int indent; 63*4887Schin int nextdent; 64*4887Schin int nwords; 65*4887Schin int prefix; 66*4887Schin int quote; 67*4887Schin int retain; 68*4887Schin int section; 69*4887Schin } Fmt_t; 70*4887Schin 71*4887Schin #define INDENT 4 72*4887Schin #define TABSZ 8 73*4887Schin 74*4887Schin #define isoption(fp,c) ((fp)->flags&(1L<<((c)-'a'))) 75*4887Schin #define setoption(fp,c) ((fp)->flags|=(1L<<((c)-'a'))) 76*4887Schin #define clroption(fp,c) ((fp)->flags&=~(1L<<((c)-'a'))) 77*4887Schin 78*4887Schin static void 79*4887Schin outline(Fmt_t* fp) 80*4887Schin { 81*4887Schin register char* cp = fp->outbuf; 82*4887Schin int n = 0; 83*4887Schin int c; 84*4887Schin int d; 85*4887Schin 86*4887Schin if (!fp->outp) 87*4887Schin return; 88*4887Schin while (fp->outp[-1] == ' ') 89*4887Schin fp->outp--; 90*4887Schin *fp->outp = 0; 91*4887Schin while (*cp++ == ' ') 92*4887Schin n++; 93*4887Schin if (n >= TABSZ) 94*4887Schin { 95*4887Schin n /= TABSZ; 96*4887Schin cp = &fp->outbuf[TABSZ*n]; 97*4887Schin while (n--) 98*4887Schin *--cp = '\t'; 99*4887Schin } 100*4887Schin else 101*4887Schin cp = fp->outbuf; 102*4887Schin fp->nwords = 0; 103*4887Schin if (!isoption(fp, 'o')) 104*4887Schin sfputr(fp->out, cp, '\n'); 105*4887Schin else if (*cp) 106*4887Schin { 107*4887Schin n = fp->indent; 108*4887Schin if (*cp != '[') 109*4887Schin { 110*4887Schin if (*cp == ' ') 111*4887Schin cp++; 112*4887Schin n += INDENT; 113*4887Schin } 114*4887Schin while (n--) 115*4887Schin sfputc(fp->out, ' '); 116*4887Schin if (fp->quote) 117*4887Schin { 118*4887Schin if ((d = (fp->outp - cp)) <= 0) 119*4887Schin c = 0; 120*4887Schin else if ((c = fp->outp[-1]) == 'n' && d > 1 && fp->outp[-2] == '\\') 121*4887Schin c = '}'; 122*4887Schin sfprintf(fp->out, "\"%s%s\"\n", cp, c == ']' || c == '{' || c == '}' ? "" : " "); 123*4887Schin } 124*4887Schin else 125*4887Schin sfputr(fp->out, cp, '\n'); 126*4887Schin if (fp->nextdent) 127*4887Schin { 128*4887Schin fp->indent += fp->nextdent; 129*4887Schin fp->endbuf -= fp->nextdent; 130*4887Schin fp->nextdent = 0; 131*4887Schin } 132*4887Schin } 133*4887Schin fp->outp = 0; 134*4887Schin } 135*4887Schin 136*4887Schin static void 137*4887Schin split(Fmt_t* fp, char* buf, int splice) 138*4887Schin { 139*4887Schin register char* cp; 140*4887Schin register char* ep; 141*4887Schin register char* qp; 142*4887Schin register int c = 1; 143*4887Schin register int q = 0; 144*4887Schin register int n; 145*4887Schin int prefix; 146*4887Schin 147*4887Schin for (ep = buf; *ep == ' '; ep++); 148*4887Schin prefix = ep - buf; 149*4887Schin 150*4887Schin /* 151*4887Schin * preserve blank lines 152*4887Schin */ 153*4887Schin 154*4887Schin if ((*ep == 0 || *buf == '.') && !isoption(fp, 'o')) 155*4887Schin { 156*4887Schin if (*ep) 157*4887Schin prefix = strlen(buf); 158*4887Schin outline(fp); 159*4887Schin strcpy(fp->outbuf, buf); 160*4887Schin fp->outp = fp->outbuf+prefix; 161*4887Schin outline(fp); 162*4887Schin return; 163*4887Schin } 164*4887Schin if (fp->prefix < prefix && !isoption(fp, 'c')) 165*4887Schin outline(fp); 166*4887Schin if (!fp->outp || prefix < fp->prefix) 167*4887Schin fp->prefix = prefix; 168*4887Schin while (c) 169*4887Schin { 170*4887Schin cp = ep; 171*4887Schin while (*ep == ' ') 172*4887Schin ep++; 173*4887Schin if (cp != ep && isoption(fp, 'u')) 174*4887Schin cp = ep-1; 175*4887Schin while (c = *ep) 176*4887Schin { 177*4887Schin if (c == ' ') 178*4887Schin break; 179*4887Schin ep++; 180*4887Schin 181*4887Schin /* 182*4887Schin * skip over \space 183*4887Schin */ 184*4887Schin 185*4887Schin if (c == '\\' && *ep) 186*4887Schin ep++; 187*4887Schin } 188*4887Schin n = (ep-cp); 189*4887Schin if (n && isoption(fp, 'o')) 190*4887Schin { 191*4887Schin for (qp = cp; qp < ep; qp++) 192*4887Schin if (*qp == '\\') 193*4887Schin qp++; 194*4887Schin else if (*qp == '"') 195*4887Schin q = !q; 196*4887Schin if (*(ep-1) == '"') 197*4887Schin goto skip; 198*4887Schin } 199*4887Schin if (fp->nwords > 0 && &fp->outp[n] >= fp->endbuf && !fp->retain && !q) 200*4887Schin outline(fp); 201*4887Schin skip: 202*4887Schin if (fp->nwords == 0) 203*4887Schin { 204*4887Schin if (fp->prefix) 205*4887Schin memset(fp->outbuf, ' ', fp->prefix); 206*4887Schin fp->outp = &fp->outbuf[fp->prefix]; 207*4887Schin while (*cp == ' ') 208*4887Schin cp++; 209*4887Schin n = (ep-cp); 210*4887Schin } 211*4887Schin memcpy(fp->outp, cp, n); 212*4887Schin fp->outp += n; 213*4887Schin fp->nwords++; 214*4887Schin } 215*4887Schin if (isoption(fp, 's') || *buf == 0) 216*4887Schin outline(fp); 217*4887Schin else if (fp->outp) 218*4887Schin { 219*4887Schin /* 220*4887Schin * two spaces at ends of sentences 221*4887Schin */ 222*4887Schin 223*4887Schin if (!isoption(fp, 'o') && strchr(".:!?", fp->outp[-1])) 224*4887Schin *fp->outp++ = ' '; 225*4887Schin if (!splice && !fp->retain && (!fp->quote || (fp->outp - fp->outbuf) < 2 || fp->outp[-2] != '\\' || fp->outp[-1] != 'n' && fp->outp[-1] != 't' && fp->outp[-1] != ' ')) 226*4887Schin *fp->outp++ = ' '; 227*4887Schin } 228*4887Schin } 229*4887Schin 230*4887Schin static int 231*4887Schin dofmt(Fmt_t* fp) 232*4887Schin { 233*4887Schin register int c; 234*4887Schin int b; 235*4887Schin int x; 236*4887Schin int splice; 237*4887Schin char* cp; 238*4887Schin char* dp; 239*4887Schin char* ep; 240*4887Schin char* lp; 241*4887Schin char* tp; 242*4887Schin char buf[8192]; 243*4887Schin 244*4887Schin cp = 0; 245*4887Schin while (cp || (cp = sfgetr(fp->in, '\n', 0)) && !(splice = 0) && (lp = cp + sfvalue(fp->in) - 1) || (cp = sfgetr(fp->in, '\n', SF_LASTR)) && (splice = 1) && (lp = cp + sfvalue(fp->in))) 246*4887Schin { 247*4887Schin if (isoption(fp, 'o')) 248*4887Schin { 249*4887Schin if (!isoption(fp, 'i')) 250*4887Schin { 251*4887Schin setoption(fp, 'i'); 252*4887Schin b = 0; 253*4887Schin while (cp < lp) 254*4887Schin { 255*4887Schin if (*cp == ' ') 256*4887Schin b += 1; 257*4887Schin else if (*cp == '\t') 258*4887Schin b += INDENT; 259*4887Schin else 260*4887Schin break; 261*4887Schin cp++; 262*4887Schin } 263*4887Schin fp->indent = roundof(b, INDENT); 264*4887Schin } 265*4887Schin else 266*4887Schin while (cp < lp && (*cp == ' ' || *cp == '\t')) 267*4887Schin cp++; 268*4887Schin if (!isoption(fp, 'q') && cp < lp) 269*4887Schin { 270*4887Schin setoption(fp, 'q'); 271*4887Schin if (*cp == '"') 272*4887Schin { 273*4887Schin ep = lp; 274*4887Schin while (--ep > cp) 275*4887Schin if (*ep == '"') 276*4887Schin { 277*4887Schin fp->quote = 1; 278*4887Schin break; 279*4887Schin } 280*4887Schin else if (*ep != ' ' && *ep != '\t') 281*4887Schin break; 282*4887Schin } 283*4887Schin } 284*4887Schin } 285*4887Schin again: 286*4887Schin dp = buf; 287*4887Schin ep = 0; 288*4887Schin for (b = 1;; b = 0) 289*4887Schin { 290*4887Schin if (cp >= lp) 291*4887Schin { 292*4887Schin cp = 0; 293*4887Schin break; 294*4887Schin } 295*4887Schin c = *cp++; 296*4887Schin if (isoption(fp, 'o')) 297*4887Schin { 298*4887Schin if (c == '\\') 299*4887Schin { 300*4887Schin x = 0; 301*4887Schin c = ' '; 302*4887Schin cp--; 303*4887Schin while (cp < lp) 304*4887Schin { 305*4887Schin if (*cp == '\\') 306*4887Schin { 307*4887Schin cp++; 308*4887Schin if ((lp - cp) < 1) 309*4887Schin { 310*4887Schin c = '\\'; 311*4887Schin break; 312*4887Schin } 313*4887Schin if (*cp == 'n') 314*4887Schin { 315*4887Schin cp++; 316*4887Schin c = '\n'; 317*4887Schin if ((lp - cp) > 2) 318*4887Schin { 319*4887Schin if (*cp == ']' || *cp == '@' && *(cp + 1) == '(') 320*4887Schin { 321*4887Schin *dp++ = '\\'; 322*4887Schin *dp++ = 'n'; 323*4887Schin c = *cp++; 324*4887Schin break; 325*4887Schin } 326*4887Schin if (*cp == '\\' && *(cp + 1) == 'n') 327*4887Schin { 328*4887Schin cp += 2; 329*4887Schin *dp++ = '\n'; 330*4887Schin break; 331*4887Schin } 332*4887Schin } 333*4887Schin } 334*4887Schin else if (*cp == 't' || *cp == ' ') 335*4887Schin { 336*4887Schin cp++; 337*4887Schin x = 1; 338*4887Schin c = ' '; 339*4887Schin } 340*4887Schin else 341*4887Schin { 342*4887Schin if (x && dp != buf && *(dp - 1) != ' ') 343*4887Schin *dp++ = ' '; 344*4887Schin *dp++ = '\\'; 345*4887Schin c = *cp++; 346*4887Schin break; 347*4887Schin } 348*4887Schin } 349*4887Schin else if (*cp == ' ' || *cp == '\t') 350*4887Schin { 351*4887Schin cp++; 352*4887Schin c = ' '; 353*4887Schin x = 1; 354*4887Schin } 355*4887Schin else 356*4887Schin { 357*4887Schin if (x && c != '\n' && dp != buf && *(dp - 1) != ' ') 358*4887Schin *dp++ = ' '; 359*4887Schin break; 360*4887Schin } 361*4887Schin } 362*4887Schin if (c == '\n') 363*4887Schin { 364*4887Schin c = 0; 365*4887Schin goto flush; 366*4887Schin } 367*4887Schin if (c == ' ' && (dp == buf || *(dp - 1) == ' ')) 368*4887Schin continue; 369*4887Schin } 370*4887Schin else if (c == '"') 371*4887Schin { 372*4887Schin if (b || cp >= lp) 373*4887Schin { 374*4887Schin if (fp->quote) 375*4887Schin continue; 376*4887Schin fp->section = 0; 377*4887Schin } 378*4887Schin } 379*4887Schin else if (c == '\a') 380*4887Schin { 381*4887Schin *dp++ = '\\'; 382*4887Schin c = 'a'; 383*4887Schin } 384*4887Schin else if (c == '\b') 385*4887Schin { 386*4887Schin *dp++ = '\\'; 387*4887Schin c = 'b'; 388*4887Schin } 389*4887Schin else if (c == '\f') 390*4887Schin { 391*4887Schin *dp++ = '\\'; 392*4887Schin c = 'f'; 393*4887Schin } 394*4887Schin else if (c == '\v') 395*4887Schin { 396*4887Schin *dp++ = '\\'; 397*4887Schin c = 'v'; 398*4887Schin } 399*4887Schin else if (c == ']' && (cp >= lp || *cp != ':' && *cp != '#' && *cp != '!')) 400*4887Schin { 401*4887Schin if (cp < lp && *cp == ']') 402*4887Schin { 403*4887Schin cp++; 404*4887Schin *dp++ = c; 405*4887Schin } 406*4887Schin else 407*4887Schin { 408*4887Schin fp->section = 1; 409*4887Schin fp->retain = 0; 410*4887Schin flush: 411*4887Schin *dp++ = c; 412*4887Schin *dp = 0; 413*4887Schin split(fp, buf, 0); 414*4887Schin outline(fp); 415*4887Schin goto again; 416*4887Schin } 417*4887Schin } 418*4887Schin else if (fp->section) 419*4887Schin { 420*4887Schin if (c == '[') 421*4887Schin { 422*4887Schin if (b) 423*4887Schin fp->retain = 1; 424*4887Schin else 425*4887Schin { 426*4887Schin cp--; 427*4887Schin c = 0; 428*4887Schin goto flush; 429*4887Schin } 430*4887Schin fp->section = 0; 431*4887Schin } 432*4887Schin else if (c == '{') 433*4887Schin { 434*4887Schin x = 1; 435*4887Schin for (tp = cp; tp < lp; tp++) 436*4887Schin { 437*4887Schin if (*tp == '[' || *tp == '\n') 438*4887Schin break; 439*4887Schin if (*tp == ' ' || *tp == '\t' || *tp == '"') 440*4887Schin continue; 441*4887Schin if (*tp == '\\' && (lp - tp) > 1) 442*4887Schin { 443*4887Schin if (*++tp == 'n') 444*4887Schin break; 445*4887Schin if (*tp == 't' || *tp == '\n') 446*4887Schin continue; 447*4887Schin } 448*4887Schin x = 0; 449*4887Schin break; 450*4887Schin } 451*4887Schin if (x) 452*4887Schin { 453*4887Schin if (fp->endbuf > (fp->outbuf + fp->indent + 2*INDENT)) 454*4887Schin fp->nextdent = 2*INDENT; 455*4887Schin goto flush; 456*4887Schin } 457*4887Schin else 458*4887Schin fp->section = 0; 459*4887Schin } 460*4887Schin else if (c == '}') 461*4887Schin { 462*4887Schin if (fp->indent && (b || *(cp - 2) != 'f')) 463*4887Schin { 464*4887Schin if (b) 465*4887Schin { 466*4887Schin fp->indent -= 2*INDENT; 467*4887Schin fp->endbuf += 2*INDENT; 468*4887Schin } 469*4887Schin else 470*4887Schin { 471*4887Schin cp--; 472*4887Schin c = 0; 473*4887Schin } 474*4887Schin goto flush; 475*4887Schin } 476*4887Schin else 477*4887Schin fp->section = 0; 478*4887Schin } 479*4887Schin else if (c == ' ' || c == '\t') 480*4887Schin continue; 481*4887Schin else 482*4887Schin fp->section = 0; 483*4887Schin } 484*4887Schin else if (c == '?' && (cp >= lp || *cp != '?')) 485*4887Schin { 486*4887Schin if (fp->retain) 487*4887Schin { 488*4887Schin cp--; 489*4887Schin while (cp < lp && *cp != ' ' && *cp != '\t' && *cp != ']' && dp < &buf[sizeof(buf)-3]) 490*4887Schin *dp++ = *cp++; 491*4887Schin if (cp < lp && (*cp == ' ' || *cp == '\t')) 492*4887Schin *dp++ = *cp++; 493*4887Schin *dp = 0; 494*4887Schin split(fp, buf, 0); 495*4887Schin dp = buf; 496*4887Schin ep = 0; 497*4887Schin fp->retain = 0; 498*4887Schin if (fp->outp >= fp->endbuf) 499*4887Schin outline(fp); 500*4887Schin continue; 501*4887Schin } 502*4887Schin } 503*4887Schin else if (c == ' ' || c == '\t') 504*4887Schin for (c = ' '; *cp == ' ' || *cp == '\t'; cp++); 505*4887Schin } 506*4887Schin else if (c == '\b') 507*4887Schin { 508*4887Schin if (dp > buf) 509*4887Schin { 510*4887Schin dp--; 511*4887Schin if (ep) 512*4887Schin ep--; 513*4887Schin } 514*4887Schin continue; 515*4887Schin } 516*4887Schin else if (c == '\t') 517*4887Schin { 518*4887Schin /* 519*4887Schin * expand tabs 520*4887Schin */ 521*4887Schin 522*4887Schin if (!ep) 523*4887Schin ep = dp; 524*4887Schin c = isoption(fp, 'o') ? 1 : TABSZ - (dp - buf) % TABSZ; 525*4887Schin if (dp >= &buf[sizeof(buf) - c - 3]) 526*4887Schin { 527*4887Schin cp--; 528*4887Schin break; 529*4887Schin } 530*4887Schin while (c-- > 0) 531*4887Schin *dp++ = ' '; 532*4887Schin continue; 533*4887Schin } 534*4887Schin else if (!isprint(c)) 535*4887Schin continue; 536*4887Schin if (dp >= &buf[sizeof(buf) - 3]) 537*4887Schin { 538*4887Schin tp = dp; 539*4887Schin while (--tp > buf) 540*4887Schin if (isspace(*tp)) 541*4887Schin { 542*4887Schin cp -= dp - tp; 543*4887Schin dp = tp; 544*4887Schin break; 545*4887Schin } 546*4887Schin ep = 0; 547*4887Schin break; 548*4887Schin } 549*4887Schin if (c != ' ') 550*4887Schin ep = 0; 551*4887Schin else if (!ep) 552*4887Schin ep = dp; 553*4887Schin *dp++ = c; 554*4887Schin } 555*4887Schin if (ep) 556*4887Schin *ep = 0; 557*4887Schin else 558*4887Schin *dp = 0; 559*4887Schin split(fp, buf, splice); 560*4887Schin } 561*4887Schin return 0; 562*4887Schin } 563*4887Schin 564*4887Schin int 565*4887Schin b_fmt(int argc, char** argv, void *context) 566*4887Schin { 567*4887Schin register int n; 568*4887Schin char* cp; 569*4887Schin Fmt_t fmt; 570*4887Schin char outbuf[8 * 1024]; 571*4887Schin 572*4887Schin fmt.flags = 0; 573*4887Schin fmt.out = sfstdout; 574*4887Schin fmt.outbuf = outbuf; 575*4887Schin fmt.outp = 0; 576*4887Schin fmt.endbuf = &outbuf[72]; 577*4887Schin fmt.indent = 0; 578*4887Schin fmt.nextdent = 0; 579*4887Schin fmt.nwords = 0; 580*4887Schin fmt.prefix = 0; 581*4887Schin fmt.quote = 0; 582*4887Schin fmt.retain = 0; 583*4887Schin fmt.section = 1; 584*4887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 585*4887Schin while (n = optget(argv, usage)) 586*4887Schin switch (n) 587*4887Schin { 588*4887Schin case 'c': 589*4887Schin case 'o': 590*4887Schin case 's': 591*4887Schin case 'u': 592*4887Schin setoption(&fmt, n); 593*4887Schin break; 594*4887Schin case 'w': 595*4887Schin if (opt_info.num < TABSZ || opt_info.num>= sizeof(outbuf)) 596*4887Schin error(2, "width out of range"); 597*4887Schin fmt.endbuf = &outbuf[opt_info.num]; 598*4887Schin break; 599*4887Schin case ':': 600*4887Schin error(2, "%s", opt_info.arg); 601*4887Schin break; 602*4887Schin case '?': 603*4887Schin error(ERROR_usage(2), "%s", opt_info.arg); 604*4887Schin break; 605*4887Schin } 606*4887Schin argv += opt_info.index; 607*4887Schin if (error_info.errors) 608*4887Schin error(ERROR_usage(2), "%s", optusage(NiL)); 609*4887Schin if (isoption(&fmt, 'o')) 610*4887Schin setoption(&fmt, 'c'); 611*4887Schin if (isoption(&fmt, 's')) 612*4887Schin clroption(&fmt, 'u'); 613*4887Schin if (cp = *argv) 614*4887Schin argv++; 615*4887Schin do { 616*4887Schin if (!cp || streq(cp, "-")) 617*4887Schin fmt.in = sfstdin; 618*4887Schin else if (!(fmt.in = sfopen(NiL, cp, "r"))) 619*4887Schin { 620*4887Schin error(ERROR_system(0), "%s: cannot open", cp); 621*4887Schin error_info.errors = 1; 622*4887Schin continue; 623*4887Schin } 624*4887Schin dofmt(&fmt); 625*4887Schin if (fmt.in != sfstdin) 626*4887Schin sfclose(fmt.in); 627*4887Schin } while (cp = *argv++); 628*4887Schin outline(&fmt); 629*4887Schin if (sfsync(sfstdout)) 630*4887Schin error(ERROR_system(0), "write error"); 631*4887Schin return error_info.errors != 0; 632*4887Schin } 633