1 1.33 christos /* $NetBSD: fmt.c,v 1.33 2017/10/13 00:11:56 christos Exp $ */ 2 1.4 jtc 3 1.1 cgd /* 4 1.4 jtc * Copyright (c) 1980, 1993 5 1.4 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.17 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.6 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.31 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 35 1.31 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.4 jtc #if 0 40 1.4 jtc static char sccsid[] = "@(#)fmt.c 8.1 (Berkeley) 7/20/93"; 41 1.4 jtc #endif 42 1.33 christos __RCSID("$NetBSD: fmt.c,v 1.33 2017/10/13 00:11:56 christos Exp $"); 43 1.1 cgd #endif /* not lint */ 44 1.1 cgd 45 1.33 christos #include <wctype.h> 46 1.16 wiz #include <locale.h> 47 1.1 cgd #include <stdio.h> 48 1.3 cgd #include <stdlib.h> 49 1.26 christos #include <unistd.h> 50 1.26 christos #include <errno.h> 51 1.26 christos #include <err.h> 52 1.26 christos #include <limits.h> 53 1.3 cgd #include <string.h> 54 1.33 christos #include <locale.h> 55 1.19 christos #include "buffer.h" 56 1.1 cgd 57 1.1 cgd /* 58 1.1 cgd * fmt -- format the concatenation of input files or standard input 59 1.1 cgd * onto standard output. Designed for use with Mail ~| 60 1.1 cgd * 61 1.1 cgd * Syntax : fmt [ goal [ max ] ] [ name ... ] 62 1.1 cgd * Authors: Kurt Shoens (UCB) 12/7/78; 63 1.1 cgd * Liz Allen (UMCP) 2/24/83 [Addition of goal length concept]. 64 1.1 cgd */ 65 1.1 cgd 66 1.1 cgd /* LIZ@UOM 6/18/85 --New variables goal_length and max_length */ 67 1.1 cgd #define GOAL_LENGTH 65 68 1.1 cgd #define MAX_LENGTH 75 69 1.19 christos static size_t goal_length; /* Target or goal line length in output */ 70 1.19 christos static size_t max_length; /* Max line length in output */ 71 1.19 christos static size_t pfx; /* Current leading blank count */ 72 1.26 christos static int raw; /* Don't treat mail specially */ 73 1.24 christos static int lineno; /* Current input line */ 74 1.24 christos static int mark; /* Last place we saw a head line */ 75 1.19 christos static int center; 76 1.19 christos static struct buffer outbuf; 77 1.1 cgd 78 1.33 christos static const wchar_t *headnames[] = { L"To", L"Subject", L"Cc", NULL }; 79 1.1 cgd 80 1.28 perry static void usage(void) __dead; 81 1.26 christos static int getnum(const char *, const char *, size_t *, int); 82 1.16 wiz static void fmt(FILE *); 83 1.33 christos static int ispref(const wchar_t *, const wchar_t *); 84 1.16 wiz static void leadin(void); 85 1.16 wiz static void oflush(void); 86 1.33 christos static void pack(const wchar_t *, size_t); 87 1.19 christos static void prefix(const struct buffer *, int); 88 1.33 christos static void split(const wchar_t *, int); 89 1.19 christos static void tabulate(struct buffer *); 90 1.10 jdolecek 91 1.19 christos 92 1.33 christos int ishead(const wchar_t *); 93 1.6 lukem 94 1.1 cgd /* 95 1.1 cgd * Drive the whole formatter by managing input files. Also, 96 1.1 cgd * cause initialization of the output stuff and flush it out 97 1.1 cgd * at the end. 98 1.1 cgd */ 99 1.1 cgd 100 1.6 lukem int 101 1.16 wiz main(int argc, char **argv) 102 1.1 cgd { 103 1.6 lukem FILE *fi; 104 1.6 lukem int errs = 0; 105 1.26 christos int compat = 1; 106 1.26 christos int c; 107 1.1 cgd 108 1.1 cgd goal_length = GOAL_LENGTH; 109 1.1 cgd max_length = MAX_LENGTH; 110 1.19 christos buf_init(&outbuf); 111 1.1 cgd lineno = 1; 112 1.24 christos mark = -10; 113 1.5 kleink 114 1.19 christos setprogname(*argv); 115 1.23 christos (void)setlocale(LC_ALL, ""); 116 1.5 kleink 117 1.32 christos while ((c = getopt(argc, argv, "Cg:m:rw:")) != -1) 118 1.26 christos switch (c) { 119 1.26 christos case 'C': 120 1.26 christos center++; 121 1.26 christos break; 122 1.26 christos case 'g': 123 1.26 christos (void)getnum(optarg, "goal", &goal_length, 1); 124 1.26 christos compat = 0; 125 1.26 christos break; 126 1.26 christos case 'm': 127 1.32 christos case 'w': 128 1.26 christos (void)getnum(optarg, "max", &max_length, 1); 129 1.26 christos compat = 0; 130 1.26 christos break; 131 1.26 christos case 'r': 132 1.26 christos raw++; 133 1.26 christos break; 134 1.26 christos default: 135 1.26 christos usage(); 136 1.26 christos } 137 1.26 christos 138 1.26 christos argc -= optind; 139 1.26 christos argv += optind; 140 1.26 christos 141 1.1 cgd /* 142 1.26 christos * compatibility with old usage. 143 1.1 cgd */ 144 1.27 christos if (compat && argc > 0 && getnum(*argv, "goal", &goal_length, 0)) { 145 1.1 cgd argv++; 146 1.1 cgd argc--; 147 1.27 christos if (argc > 0 && getnum(*argv, "max", &max_length, 0)) { 148 1.1 cgd argv++; 149 1.1 cgd argc--; 150 1.1 cgd } 151 1.1 cgd } 152 1.26 christos 153 1.1 cgd if (max_length <= goal_length) { 154 1.19 christos errx(1, "Max length (%zu) must be greater than goal " 155 1.19 christos "length (%zu)", max_length, goal_length); 156 1.1 cgd } 157 1.26 christos if (argc == 0) { 158 1.1 cgd fmt(stdin); 159 1.1 cgd oflush(); 160 1.19 christos return 0; 161 1.1 cgd } 162 1.29 christos for (;argc; argc--, argv++) { 163 1.29 christos if ((fi = fopen(*argv, "r")) == NULL) { 164 1.19 christos warn("Cannot open `%s'", *argv); 165 1.1 cgd errs++; 166 1.1 cgd continue; 167 1.1 cgd } 168 1.1 cgd fmt(fi); 169 1.23 christos (void)fclose(fi); 170 1.1 cgd } 171 1.1 cgd oflush(); 172 1.19 christos buf_end(&outbuf); 173 1.19 christos return errs; 174 1.1 cgd } 175 1.1 cgd 176 1.26 christos static void 177 1.26 christos usage(void) 178 1.26 christos { 179 1.26 christos (void)fprintf(stderr, 180 1.32 christos "Usage: %s [-Cr] [-g <goal>] [-m|w <max>] [<files>..]\n" 181 1.26 christos "\t %s [-Cr] [<goal>] [<max>] [<files>]\n", 182 1.26 christos getprogname(), getprogname()); 183 1.26 christos exit(1); 184 1.26 christos } 185 1.26 christos 186 1.26 christos static int 187 1.26 christos getnum(const char *str, const char *what, size_t *res, int badnum) 188 1.26 christos { 189 1.26 christos unsigned long ul; 190 1.26 christos char *ep; 191 1.26 christos 192 1.26 christos errno = 0; 193 1.26 christos ul = strtoul(str, &ep, 0); 194 1.26 christos if (*str != '\0' && *ep == '\0') { 195 1.26 christos if ((errno == ERANGE && ul == ULONG_MAX) || ul > SIZE_T_MAX) 196 1.26 christos errx(1, "%s number `%s' too big", what, str); 197 1.26 christos *res = (size_t)ul; 198 1.26 christos return 1; 199 1.26 christos } else if (badnum) 200 1.26 christos errx(1, "Bad %s number `%s'", what, str); 201 1.26 christos 202 1.26 christos return 0; 203 1.26 christos } 204 1.26 christos 205 1.1 cgd /* 206 1.1 cgd * Read up characters from the passed input file, forming lines, 207 1.1 cgd * doing ^H processing, expanding tabs, stripping trailing blanks, 208 1.1 cgd * and sending each line down for analysis. 209 1.1 cgd */ 210 1.10 jdolecek static void 211 1.16 wiz fmt(FILE *fi) 212 1.1 cgd { 213 1.19 christos struct buffer lbuf, cbuf; 214 1.33 christos wchar_t *cp, *cp2; 215 1.33 christos wint_t c; 216 1.33 christos int add_space; 217 1.30 dholland size_t len, col, i; 218 1.1 cgd 219 1.12 abs if (center) { 220 1.19 christos for (;;) { 221 1.33 christos cp = fgetwln(fi, &len); 222 1.12 abs if (!cp) 223 1.12 abs return; 224 1.30 dholland 225 1.30 dholland /* skip over leading space */ 226 1.30 dholland while (len > 0) { 227 1.33 christos if (!iswspace(*cp)) 228 1.30 dholland break; 229 1.12 abs cp++; 230 1.30 dholland len--; 231 1.30 dholland } 232 1.30 dholland 233 1.30 dholland /* clear trailing space */ 234 1.30 dholland while (len > 0) { 235 1.33 christos if (!iswspace((unsigned char)cp[len-1])) 236 1.30 dholland break; 237 1.30 dholland len--; 238 1.30 dholland } 239 1.30 dholland 240 1.30 dholland if (len == 0) { 241 1.30 dholland /* blank line */ 242 1.33 christos (void)putwchar(L'\n'); 243 1.30 dholland continue; 244 1.30 dholland } 245 1.30 dholland 246 1.30 dholland if (goal_length > len) { 247 1.30 dholland for (i = 0; i < (goal_length - len) / 2; i++) { 248 1.33 christos (void)putwchar(L' '); 249 1.30 dholland } 250 1.30 dholland } 251 1.30 dholland for (i = 0; i < len; i++) { 252 1.33 christos (void)putwchar(cp[i]); 253 1.30 dholland } 254 1.33 christos (void)putwchar(L'\n'); 255 1.12 abs } 256 1.12 abs } 257 1.19 christos 258 1.19 christos buf_init(&lbuf); 259 1.19 christos buf_init(&cbuf); 260 1.33 christos c = getwc(fi); 261 1.19 christos 262 1.33 christos while (c != WEOF) { 263 1.1 cgd /* 264 1.1 cgd * Collect a line, doing ^H processing. 265 1.1 cgd * Leave tabs for now. 266 1.1 cgd */ 267 1.19 christos buf_reset(&lbuf); 268 1.33 christos while (c != '\n' && c != WEOF) { 269 1.1 cgd if (c == '\b') { 270 1.23 christos (void)buf_unputc(&lbuf); 271 1.33 christos c = getwc(fi); 272 1.1 cgd continue; 273 1.1 cgd } 274 1.33 christos if(!(iswprint(c) || c == '\t' || c >= 160)) { 275 1.33 christos c = getwc(fi); 276 1.1 cgd continue; 277 1.1 cgd } 278 1.19 christos buf_putc(&lbuf, c); 279 1.33 christos c = getwc(fi); 280 1.1 cgd } 281 1.19 christos buf_putc(&lbuf, '\0'); 282 1.23 christos (void)buf_unputc(&lbuf); 283 1.33 christos add_space = c != WEOF; 284 1.10 jdolecek 285 1.10 jdolecek /* 286 1.19 christos * Expand tabs on the way. 287 1.1 cgd */ 288 1.1 cgd col = 0; 289 1.19 christos cp = lbuf.bptr; 290 1.19 christos buf_reset(&cbuf); 291 1.19 christos while ((c = *cp++) != '\0') { 292 1.1 cgd if (c != '\t') { 293 1.1 cgd col++; 294 1.19 christos buf_putc(&cbuf, c); 295 1.1 cgd continue; 296 1.1 cgd } 297 1.1 cgd do { 298 1.19 christos buf_putc(&cbuf, ' '); 299 1.1 cgd col++; 300 1.1 cgd } while ((col & 07) != 0); 301 1.1 cgd } 302 1.1 cgd 303 1.1 cgd /* 304 1.1 cgd * Swipe trailing blanks from the line. 305 1.1 cgd */ 306 1.19 christos for (cp2 = cbuf.ptr - 1; cp2 >= cbuf.bptr && *cp2 == ' '; cp2--) 307 1.19 christos continue; 308 1.19 christos cbuf.ptr = cp2 + 1; 309 1.19 christos buf_putc(&cbuf, '\0'); 310 1.23 christos (void)buf_unputc(&cbuf); 311 1.19 christos prefix(&cbuf, add_space); 312 1.33 christos if (c != WEOF) 313 1.33 christos c = getwc(fi); 314 1.1 cgd } 315 1.19 christos buf_end(&cbuf); 316 1.19 christos buf_end(&lbuf); 317 1.1 cgd } 318 1.1 cgd 319 1.1 cgd /* 320 1.1 cgd * Take a line devoid of tabs and other garbage and determine its 321 1.1 cgd * blank prefix. If the indent changes, call for a linebreak. 322 1.1 cgd * If the input line is blank, echo the blank line on the output. 323 1.1 cgd * Finally, if the line minus the prefix is a mail header, try to keep 324 1.1 cgd * it on a line by itself. 325 1.1 cgd */ 326 1.10 jdolecek static void 327 1.19 christos prefix(const struct buffer *buf, int add_space) 328 1.1 cgd { 329 1.33 christos const wchar_t *cp; 330 1.33 christos const wchar_t **hp; 331 1.19 christos size_t np; 332 1.19 christos int h; 333 1.1 cgd 334 1.19 christos if (buf->ptr == buf->bptr) { 335 1.1 cgd oflush(); 336 1.33 christos (void)putwchar(L'\n'); 337 1.1 cgd return; 338 1.1 cgd } 339 1.19 christos for (cp = buf->bptr; *cp == ' '; cp++) 340 1.19 christos continue; 341 1.19 christos np = cp - buf->bptr; 342 1.1 cgd 343 1.1 cgd /* 344 1.1 cgd * The following horrible expression attempts to avoid linebreaks 345 1.1 cgd * when the indent changes due to a paragraph. 346 1.1 cgd */ 347 1.19 christos if (np != pfx && (np > pfx || abs((int)(pfx - np)) > 8)) 348 1.19 christos oflush(); 349 1.26 christos if (!raw) { 350 1.26 christos if ((h = ishead(cp)) != 0) { 351 1.26 christos oflush(); 352 1.26 christos mark = lineno; 353 1.26 christos } 354 1.26 christos if (lineno - mark < 3 && lineno - mark > 0) 355 1.26 christos for (hp = &headnames[0]; *hp != NULL; hp++) 356 1.26 christos if (ispref(*hp, cp)) { 357 1.26 christos h = 1; 358 1.26 christos oflush(); 359 1.26 christos break; 360 1.26 christos } 361 1.26 christos if (!h && (h = (*cp == '.'))) 362 1.26 christos oflush(); 363 1.26 christos } else 364 1.26 christos h = 0; 365 1.1 cgd pfx = np; 366 1.10 jdolecek if (h) { 367 1.19 christos pack(cp, (size_t)(buf->ptr - cp)); 368 1.1 cgd oflush(); 369 1.10 jdolecek } else 370 1.10 jdolecek split(cp, add_space); 371 1.1 cgd lineno++; 372 1.1 cgd } 373 1.1 cgd 374 1.1 cgd /* 375 1.1 cgd * Split up the passed line into output "words" which are 376 1.1 cgd * maximal strings of non-blanks with the blank separation 377 1.1 cgd * attached at the end. Pass these words along to the output 378 1.1 cgd * line packer. 379 1.1 cgd */ 380 1.10 jdolecek static void 381 1.33 christos split(const wchar_t line[], int add_space) 382 1.1 cgd { 383 1.33 christos const wchar_t *cp; 384 1.19 christos struct buffer word; 385 1.19 christos size_t wlen; 386 1.1 cgd 387 1.19 christos buf_init(&word); 388 1.1 cgd cp = line; 389 1.1 cgd while (*cp) { 390 1.19 christos buf_reset(&word); 391 1.19 christos wlen = 0; 392 1.1 cgd 393 1.1 cgd /* 394 1.1 cgd * Collect a 'word,' allowing it to contain escaped white 395 1.1 cgd * space. 396 1.1 cgd */ 397 1.1 cgd while (*cp && *cp != ' ') { 398 1.33 christos if (*cp == '\\' && iswspace(cp[1])) 399 1.19 christos buf_putc(&word, *cp++); 400 1.19 christos buf_putc(&word, *cp++); 401 1.19 christos wlen++; 402 1.1 cgd } 403 1.1 cgd 404 1.1 cgd /* 405 1.1 cgd * Guarantee a space at end of line. Two spaces after end of 406 1.1 cgd * sentence punctuation. 407 1.1 cgd */ 408 1.10 jdolecek if (*cp == '\0' && add_space) { 409 1.19 christos buf_putc(&word, ' '); 410 1.7 lukem if (strchr(".:!", cp[-1])) 411 1.19 christos buf_putc(&word, ' '); 412 1.1 cgd } 413 1.1 cgd while (*cp == ' ') 414 1.19 christos buf_putc(&word, *cp++); 415 1.19 christos 416 1.19 christos buf_putc(&word, '\0'); 417 1.23 christos (void)buf_unputc(&word); 418 1.19 christos 419 1.19 christos pack(word.bptr, wlen); 420 1.1 cgd } 421 1.19 christos buf_end(&word); 422 1.1 cgd } 423 1.1 cgd 424 1.1 cgd /* 425 1.1 cgd * Output section. 426 1.1 cgd * Build up line images from the words passed in. Prefix 427 1.20 christos * each line with correct number of blanks. 428 1.20 christos * 429 1.20 christos * At the bottom of this whole mess, leading tabs are reinserted. 430 1.1 cgd */ 431 1.1 cgd 432 1.1 cgd /* 433 1.1 cgd * Pack a word onto the output line. If this is the beginning of 434 1.1 cgd * the line, push on the appropriately-sized string of blanks first. 435 1.1 cgd * If the word won't fit on the current line, flush and begin a new 436 1.1 cgd * line. If the word is too long to fit all by itself on a line, 437 1.1 cgd * just give it its own and hope for the best. 438 1.1 cgd * 439 1.1 cgd * LIZ@UOM 6/18/85 -- If the new word will fit in at less than the 440 1.1 cgd * goal length, take it. If not, then check to see if the line 441 1.1 cgd * will be over the max length; if so put the word on the next 442 1.1 cgd * line. If not, check to see if the line will be closer to the 443 1.1 cgd * goal length with or without the word and take it or put it on 444 1.1 cgd * the next line accordingly. 445 1.1 cgd */ 446 1.1 cgd 447 1.10 jdolecek static void 448 1.33 christos pack(const wchar_t *word, size_t wlen) 449 1.1 cgd { 450 1.33 christos const wchar_t *cp; 451 1.19 christos size_t s, t; 452 1.1 cgd 453 1.19 christos if (outbuf.bptr == outbuf.ptr) 454 1.1 cgd leadin(); 455 1.1 cgd /* 456 1.1 cgd * LIZ@UOM 6/18/85 -- change condition to check goal_length; s is the 457 1.1 cgd * length of the line before the word is added; t is now the length 458 1.1 cgd * of the line after the word is added 459 1.1 cgd */ 460 1.19 christos s = outbuf.ptr - outbuf.bptr; 461 1.19 christos t = wlen + s; 462 1.22 christos if ((t <= goal_length) || ((t <= max_length) && 463 1.22 christos (s <= goal_length) && (t - goal_length <= goal_length - s))) { 464 1.1 cgd /* 465 1.1 cgd * In like flint! 466 1.1 cgd */ 467 1.19 christos for (cp = word; *cp;) 468 1.19 christos buf_putc(&outbuf, *cp++); 469 1.1 cgd return; 470 1.1 cgd } 471 1.1 cgd if (s > pfx) { 472 1.1 cgd oflush(); 473 1.1 cgd leadin(); 474 1.1 cgd } 475 1.19 christos for (cp = word; *cp;) 476 1.19 christos buf_putc(&outbuf, *cp++); 477 1.1 cgd } 478 1.1 cgd 479 1.1 cgd /* 480 1.1 cgd * If there is anything on the current output line, send it on 481 1.20 christos * its way. Reset outbuf. 482 1.1 cgd */ 483 1.10 jdolecek static void 484 1.16 wiz oflush(void) 485 1.1 cgd { 486 1.19 christos if (outbuf.bptr == outbuf.ptr) 487 1.1 cgd return; 488 1.19 christos buf_putc(&outbuf, '\0'); 489 1.23 christos (void)buf_unputc(&outbuf); 490 1.19 christos tabulate(&outbuf); 491 1.19 christos buf_reset(&outbuf); 492 1.1 cgd } 493 1.1 cgd 494 1.1 cgd /* 495 1.1 cgd * Take the passed line buffer, insert leading tabs where possible, and 496 1.1 cgd * output on standard output (finally). 497 1.1 cgd */ 498 1.10 jdolecek static void 499 1.19 christos tabulate(struct buffer *buf) 500 1.1 cgd { 501 1.33 christos wchar_t *cp; 502 1.19 christos size_t b, t; 503 1.1 cgd 504 1.1 cgd /* 505 1.1 cgd * Toss trailing blanks in the output line. 506 1.1 cgd */ 507 1.25 christos for (cp = buf->ptr - 1; cp >= buf->bptr && *cp == ' '; cp--) 508 1.19 christos continue; 509 1.25 christos *++cp = '\0'; 510 1.1 cgd 511 1.1 cgd /* 512 1.1 cgd * Count the leading blank space and tabulate. 513 1.1 cgd */ 514 1.19 christos for (cp = buf->bptr; *cp == ' '; cp++) 515 1.19 christos continue; 516 1.19 christos b = cp - buf->bptr; 517 1.20 christos t = b / 8; 518 1.20 christos b = b % 8; 519 1.1 cgd if (t > 0) 520 1.1 cgd do 521 1.33 christos (void)putwchar(L'\t'); 522 1.1 cgd while (--t); 523 1.1 cgd if (b > 0) 524 1.1 cgd do 525 1.33 christos (void)putwchar(L' '); 526 1.1 cgd while (--b); 527 1.1 cgd while (*cp) 528 1.33 christos (void)putwchar(*cp++); 529 1.33 christos (void)putwchar(L'\n'); 530 1.1 cgd } 531 1.1 cgd 532 1.1 cgd /* 533 1.1 cgd * Initialize the output line with the appropriate number of 534 1.1 cgd * leading blanks. 535 1.1 cgd */ 536 1.10 jdolecek static void 537 1.16 wiz leadin(void) 538 1.1 cgd { 539 1.19 christos size_t b; 540 1.19 christos 541 1.19 christos buf_reset(&outbuf); 542 1.1 cgd 543 1.19 christos for (b = 0; b < pfx; b++) 544 1.19 christos buf_putc(&outbuf, ' '); 545 1.1 cgd } 546 1.1 cgd 547 1.1 cgd /* 548 1.1 cgd * Is s1 a prefix of s2?? 549 1.1 cgd */ 550 1.10 jdolecek static int 551 1.33 christos ispref(const wchar_t *s1, const wchar_t *s2) 552 1.1 cgd { 553 1.1 cgd 554 1.1 cgd while (*s1++ == *s2) 555 1.19 christos continue; 556 1.19 christos return *s1 == '\0'; 557 1.1 cgd } 558