17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5e1ab4a07SJohn Sonnenschein * Common Development and Distribution License (the "License"). 6e1ab4a07SJohn Sonnenschein * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e1ab4a07SJohn Sonnenschein * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <ctype.h> 337c478bd9Sstevel@tonic-gate #include <wctype.h> 347c478bd9Sstevel@tonic-gate #include <widec.h> 357c478bd9Sstevel@tonic-gate #include <dlfcn.h> 367c478bd9Sstevel@tonic-gate #include <locale.h> 377c478bd9Sstevel@tonic-gate #include <sys/param.h> 387c478bd9Sstevel@tonic-gate #include <string.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate * fmt -- format the concatenation of input files or standard input 427c478bd9Sstevel@tonic-gate * onto standard output. Designed for use with Mail ~| 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * Syntax: fmt [ -width | -w width ] [ -cs ] [ name ... ] 457c478bd9Sstevel@tonic-gate * Author: Kurt Shoens (UCB) 12/7/78 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #define NOSTR ((wchar_t *)0) /* Null string pointer for lint */ 497c478bd9Sstevel@tonic-gate #define MAXLINES 100 /* maximum mail header lines to verify */ 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate wchar_t outbuf[BUFSIZ]; /* Sandbagged output line image */ 527c478bd9Sstevel@tonic-gate wchar_t *outp; /* Pointer in above */ 537c478bd9Sstevel@tonic-gate int filler; /* Filler amount in outbuf */ 54e1ab4a07SJohn Sonnenschein char sobuf[BUFSIZ]; /* Global buffer */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate int pfx; /* Current leading blank count */ 577c478bd9Sstevel@tonic-gate int width = 72; /* Width that we will not exceed */ 587c478bd9Sstevel@tonic-gate int nojoin = 0; /* split lines only, don't join short ones */ 597c478bd9Sstevel@tonic-gate int errs = 0; /* Current number of errors */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate enum crown_type {c_none, c_reset, c_head, c_lead, c_fixup, c_body}; 627c478bd9Sstevel@tonic-gate enum crown_type crown_state; /* Crown margin state */ 637c478bd9Sstevel@tonic-gate int crown_head; /* The header offset */ 647c478bd9Sstevel@tonic-gate int crown_body; /* The body offset */ 657c478bd9Sstevel@tonic-gate /* currently-known initial strings found in mail headers */ 667c478bd9Sstevel@tonic-gate wchar_t *headnames[] = { 677c478bd9Sstevel@tonic-gate L"Apparently-To", L"Bcc", L"bcc", L"Cc", L"cc", L"Confirmed-By", 687c478bd9Sstevel@tonic-gate L"Content", L"content-length", L"From", L"Date", L"id", 697c478bd9Sstevel@tonic-gate L"Message-I", L"MIME-Version", L"Precedence", L"Return-Path", 707c478bd9Sstevel@tonic-gate L"Received", L"Reply-To", L"Status", L"Subject", L"To", L"X-IMAP", 717c478bd9Sstevel@tonic-gate L"X-Lines", L"X-Sender", L"X-Sun", L"X-Status", L"X-UID", 727c478bd9Sstevel@tonic-gate 0}; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate enum hdr_type { 757c478bd9Sstevel@tonic-gate off, /* mail header processing is off */ 767c478bd9Sstevel@tonic-gate not_in_hdr, /* not currently processing a mail header */ 777c478bd9Sstevel@tonic-gate in_hdr, /* currently filling hdrbuf with potential hdr lines */ 787c478bd9Sstevel@tonic-gate flush_hdr, /* flush hdrbuf; not a header, no special processing */ 797c478bd9Sstevel@tonic-gate do_hdr /* process hdrbuf as a mail header */ 807c478bd9Sstevel@tonic-gate }; 817c478bd9Sstevel@tonic-gate /* current state of hdrbuf */ 827c478bd9Sstevel@tonic-gate enum hdr_type hdr_state = not_in_hdr; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate wchar_t *hdrbuf[MAXLINES]; /* buffer to hold potential mail header lines */ 857c478bd9Sstevel@tonic-gate int h_lines; /* index into lines of hdrbuf */ 867c478bd9Sstevel@tonic-gate 87b7d62af5Sceastha void (*(split))(wchar_t []); 887c478bd9Sstevel@tonic-gate extern int scrwidth(wchar_t); 89*196c7f05SJoshua M. Clulow extern boolean_t is_headline(const char *); 907c478bd9Sstevel@tonic-gate 91b7d62af5Sceastha 92b7d62af5Sceastha static void fill_hdrbuf(wchar_t []); 937c478bd9Sstevel@tonic-gate static void header_chk(void); 947c478bd9Sstevel@tonic-gate static void process_hdrbuf(void); 95b7d62af5Sceastha static void leadin(void); 96b7d62af5Sceastha static void tabulate(wchar_t []); 97b7d62af5Sceastha static void oflush(void); 98b7d62af5Sceastha static void pack(wchar_t []); 99b7d62af5Sceastha static void msplit(wchar_t []); 100b7d62af5Sceastha static void csplit(wchar_t []); 101b7d62af5Sceastha static void _wckind_init(void); 102b7d62af5Sceastha static void prefix(wchar_t []); 103b7d62af5Sceastha static void fmt(FILE *); 104b7d62af5Sceastha static int setopt(char *); 105b7d62af5Sceastha int _wckind(wchar_t); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Drive the whole formatter by managing input files. Also, 1097c478bd9Sstevel@tonic-gate * cause initialization of the output stuff and flush it out 1107c478bd9Sstevel@tonic-gate * at the end. 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate 113b7d62af5Sceastha int 1147c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1157c478bd9Sstevel@tonic-gate { 116b7d62af5Sceastha FILE *fi; 117b7d62af5Sceastha char *cp; 1187c478bd9Sstevel@tonic-gate int nofile; 1197c478bd9Sstevel@tonic-gate char *locale; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate outp = NOSTR; 1227c478bd9Sstevel@tonic-gate setbuf(stdout, sobuf); 1237c478bd9Sstevel@tonic-gate setlocale(LC_ALL, ""); 1247c478bd9Sstevel@tonic-gate locale = setlocale(LC_CTYPE, ""); 1257c478bd9Sstevel@tonic-gate if (strcmp(locale, "C") == 0) { 1267c478bd9Sstevel@tonic-gate split = csplit; 1277c478bd9Sstevel@tonic-gate } else { 1287c478bd9Sstevel@tonic-gate split = msplit; 129b7d62af5Sceastha _wckind_init(); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate if (argc < 2) { 1327c478bd9Sstevel@tonic-gate single: 1337c478bd9Sstevel@tonic-gate fmt(stdin); 1347c478bd9Sstevel@tonic-gate oflush(); 1357c478bd9Sstevel@tonic-gate exit(0); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate nofile = 1; 1387c478bd9Sstevel@tonic-gate while (--argc) { 1397c478bd9Sstevel@tonic-gate cp = *++argv; 1407c478bd9Sstevel@tonic-gate if (setopt(cp)) 1417c478bd9Sstevel@tonic-gate continue; 1427c478bd9Sstevel@tonic-gate nofile = 0; 1437c478bd9Sstevel@tonic-gate if ((fi = fopen(cp, "r")) == NULL) { 1447c478bd9Sstevel@tonic-gate perror(cp); 1457c478bd9Sstevel@tonic-gate errs++; 1467c478bd9Sstevel@tonic-gate continue; 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate fmt(fi); 1497c478bd9Sstevel@tonic-gate fclose(fi); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate if (nofile) 1527c478bd9Sstevel@tonic-gate goto single; 1537c478bd9Sstevel@tonic-gate oflush(); 1547c98f3e0Sakaplan fclose(stdout); 155b7d62af5Sceastha return (errs); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * Read up characters from the passed input file, forming lines, 1607c478bd9Sstevel@tonic-gate * doing ^H processing, expanding tabs, stripping trailing blanks, 1617c478bd9Sstevel@tonic-gate * and sending each line down for analysis. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate 164b7d62af5Sceastha static void 1657c478bd9Sstevel@tonic-gate fmt(FILE *fi) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate wchar_t linebuf[BUFSIZ], canonb[BUFSIZ]; 168b7d62af5Sceastha wchar_t *cp, *cp2; 169b7d62af5Sceastha int col; 1707c478bd9Sstevel@tonic-gate wchar_t c; 1717c478bd9Sstevel@tonic-gate char cbuf[BUFSIZ]; /* stores wchar_t string as char string */ 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate c = getwc(fi); 1747c478bd9Sstevel@tonic-gate while (c != EOF) { 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * Collect a line, doing ^H processing. 1777c478bd9Sstevel@tonic-gate * Leave tabs for now. 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate cp = linebuf; 1817c478bd9Sstevel@tonic-gate while (c != L'\n' && c != EOF && cp-linebuf < BUFSIZ-1) { 1827c478bd9Sstevel@tonic-gate if (c == L'\b') { 1837c478bd9Sstevel@tonic-gate if (cp > linebuf) 1847c478bd9Sstevel@tonic-gate cp--; 1857c478bd9Sstevel@tonic-gate c = getwc(fi); 1867c478bd9Sstevel@tonic-gate continue; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate if (!(iswprint(c)) && c != L'\t') { 1897c478bd9Sstevel@tonic-gate c = getwc(fi); 1907c478bd9Sstevel@tonic-gate continue; 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate *cp++ = c; 1937c478bd9Sstevel@tonic-gate c = getwc(fi); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate *cp = L'\0'; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Toss anything remaining on the input line. 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate while (c != L'\n' && c != EOF) 2027c478bd9Sstevel@tonic-gate c = getwc(fi); 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Expand tabs on the way to canonb. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate col = 0; 2087c478bd9Sstevel@tonic-gate cp = linebuf; 2097c478bd9Sstevel@tonic-gate cp2 = canonb; 2107c478bd9Sstevel@tonic-gate while (c = *cp++) { 2117c478bd9Sstevel@tonic-gate if (c != L'\t') { 2127c478bd9Sstevel@tonic-gate col += scrwidth(c); 2137c478bd9Sstevel@tonic-gate if (cp2-canonb < BUFSIZ-1) 2147c478bd9Sstevel@tonic-gate *cp2++ = c; 2157c478bd9Sstevel@tonic-gate continue; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate do { 2187c478bd9Sstevel@tonic-gate if (cp2-canonb < BUFSIZ-1) 2197c478bd9Sstevel@tonic-gate *cp2++ = L' '; 2207c478bd9Sstevel@tonic-gate col++; 2217c478bd9Sstevel@tonic-gate } while ((col & 07) != 0); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Swipe trailing blanks from the line. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate 228e1ab4a07SJohn Sonnenschein for (cp2--; cp2 >= canonb && *cp2 == L' '; cp2--) { 229e1ab4a07SJohn Sonnenschein } 2307c478bd9Sstevel@tonic-gate *++cp2 = '\0'; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* special processing to look for mail header lines */ 2337c478bd9Sstevel@tonic-gate switch (hdr_state) { 2347c478bd9Sstevel@tonic-gate case off: 2357c478bd9Sstevel@tonic-gate prefix(canonb); 2367c478bd9Sstevel@tonic-gate case not_in_hdr: 2377c478bd9Sstevel@tonic-gate /* look for an initial mail header line */ 2387c478bd9Sstevel@tonic-gate /* skip initial blanks */ 239e1ab4a07SJohn Sonnenschein for (cp = canonb; *cp == L' '; cp++) { 240e1ab4a07SJohn Sonnenschein } 2417c478bd9Sstevel@tonic-gate /* 2427c478bd9Sstevel@tonic-gate * Need to convert string from wchar_t to char, 243*196c7f05SJoshua M. Clulow * since this is what is_headline() expects. Since we 2447c478bd9Sstevel@tonic-gate * only want to make sure cp points to a "From" line 2457c478bd9Sstevel@tonic-gate * of the email, we don't have to alloc 2467c478bd9Sstevel@tonic-gate * BUFSIZ * MB_LEN_MAX to cbuf. 2477c478bd9Sstevel@tonic-gate */ 2487c478bd9Sstevel@tonic-gate wcstombs(cbuf, cp, (BUFSIZ - 1)); 249*196c7f05SJoshua M. Clulow if (is_headline(cbuf) == B_TRUE) { 2507c478bd9Sstevel@tonic-gate hdr_state = in_hdr; 2517c478bd9Sstevel@tonic-gate fill_hdrbuf(canonb); 2527c478bd9Sstevel@tonic-gate } else { 2537c478bd9Sstevel@tonic-gate /* no mail header line; process normally */ 2547c478bd9Sstevel@tonic-gate prefix(canonb); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate break; 2577c478bd9Sstevel@tonic-gate case in_hdr: 2587c478bd9Sstevel@tonic-gate /* already saw 1st mail header line; look for more */ 2597c478bd9Sstevel@tonic-gate if (canonb[0] == L'\0') { 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * blank line means end of mail header; 2627c478bd9Sstevel@tonic-gate * verify current mail header buffer 2637c478bd9Sstevel@tonic-gate * then process it accordingly 2647c478bd9Sstevel@tonic-gate */ 2657c478bd9Sstevel@tonic-gate header_chk(); 2667c478bd9Sstevel@tonic-gate process_hdrbuf(); 2677c478bd9Sstevel@tonic-gate /* now process the current blank line */ 2687c478bd9Sstevel@tonic-gate prefix(canonb); 2697c478bd9Sstevel@tonic-gate } else 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * not a blank line--save this line as 2727c478bd9Sstevel@tonic-gate * a potential mail header line 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate fill_hdrbuf(canonb); 2757c478bd9Sstevel@tonic-gate break; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate if (c != EOF) 2787c478bd9Sstevel@tonic-gate c = getwc(fi); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * end of this file--make sure we process the stuff in 2827c478bd9Sstevel@tonic-gate * hdrbuf before we're finished 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate if (hdr_state == in_hdr) { 2857c478bd9Sstevel@tonic-gate header_chk(); 2867c478bd9Sstevel@tonic-gate process_hdrbuf(); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * Take a line devoid of tabs and other garbage and determine its 2927c478bd9Sstevel@tonic-gate * blank prefix. If the indent changes, call for a linebreak. 2937c478bd9Sstevel@tonic-gate * If the input line is blank, echo the blank line on the output. 2947c478bd9Sstevel@tonic-gate * Finally, if the line minus the prefix is a mail header, try to keep 2957c478bd9Sstevel@tonic-gate * it on a line by itself. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate 298b7d62af5Sceastha static void 2997c478bd9Sstevel@tonic-gate prefix(wchar_t line[]) 3007c478bd9Sstevel@tonic-gate { 301b7d62af5Sceastha wchar_t *cp; 302b7d62af5Sceastha int np; 3037c478bd9Sstevel@tonic-gate int nosplit = 0; /* flag set if line should not be split */ 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate if (line[0] == L'\0') { 3067c478bd9Sstevel@tonic-gate oflush(); 3077c478bd9Sstevel@tonic-gate putchar('\n'); 3087c478bd9Sstevel@tonic-gate if (crown_state != c_none) 3097c478bd9Sstevel@tonic-gate crown_state = c_reset; 3107c478bd9Sstevel@tonic-gate return; 3117c478bd9Sstevel@tonic-gate } 312e1ab4a07SJohn Sonnenschein for (cp = line; *cp == L' '; cp++) { 313e1ab4a07SJohn Sonnenschein } 3147c478bd9Sstevel@tonic-gate np = cp - line; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * The following horrible expression attempts to avoid linebreaks 3187c478bd9Sstevel@tonic-gate * when the indent changes due to a paragraph. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate if (crown_state == c_none && np != pfx && (np > pfx || abs(pfx-np) > 8)) 3227c478bd9Sstevel@tonic-gate oflush(); 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * if this is a mail header line, don't split it; flush previous 3257c478bd9Sstevel@tonic-gate * line, if any, so we don't join this line to it 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate if (hdr_state == do_hdr) { 3287c478bd9Sstevel@tonic-gate nosplit = 1; 3297c478bd9Sstevel@tonic-gate oflush(); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate /* flush previous line so we don't join this one to it */ 3327c478bd9Sstevel@tonic-gate if (nojoin) 3337c478bd9Sstevel@tonic-gate oflush(); 3347c478bd9Sstevel@tonic-gate /* nroff-type lines starting with '.' are not split nor joined */ 3357c478bd9Sstevel@tonic-gate if (!nosplit && (nosplit = (*cp == L'.'))) 3367c478bd9Sstevel@tonic-gate oflush(); 3377c478bd9Sstevel@tonic-gate pfx = np; 3387c478bd9Sstevel@tonic-gate switch (crown_state) { 3397c478bd9Sstevel@tonic-gate case c_reset: 3407c478bd9Sstevel@tonic-gate crown_head = pfx; 3417c478bd9Sstevel@tonic-gate crown_state = c_head; 3427c478bd9Sstevel@tonic-gate break; 3437c478bd9Sstevel@tonic-gate case c_lead: 3447c478bd9Sstevel@tonic-gate crown_body = pfx; 3457c478bd9Sstevel@tonic-gate crown_state = c_body; 3467c478bd9Sstevel@tonic-gate break; 3477c478bd9Sstevel@tonic-gate case c_fixup: 3487c478bd9Sstevel@tonic-gate crown_body = pfx; 3497c478bd9Sstevel@tonic-gate crown_state = c_body; 3507c478bd9Sstevel@tonic-gate if (outp) { 3517c478bd9Sstevel@tonic-gate wchar_t s[BUFSIZ]; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate *outp = L'\0'; 3547c478bd9Sstevel@tonic-gate wscpy(s, &outbuf[crown_head]); 3557c478bd9Sstevel@tonic-gate outp = NOSTR; 3567c478bd9Sstevel@tonic-gate split(s); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate break; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate if (nosplit) { 3617c478bd9Sstevel@tonic-gate /* put whole input line onto outbuf and print it out */ 3627c478bd9Sstevel@tonic-gate pack(cp); 3637c478bd9Sstevel@tonic-gate oflush(); 3647c478bd9Sstevel@tonic-gate } else 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * split puts current line onto outbuf, but splits it 3677c478bd9Sstevel@tonic-gate * at word boundaries, if it exceeds desired length 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate split(cp); 3707c478bd9Sstevel@tonic-gate if (nojoin) 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * flush current line so next lines, if any, 3737c478bd9Sstevel@tonic-gate * won't join to this one 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate oflush(); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Split up the passed line into output "words" which are 3807c478bd9Sstevel@tonic-gate * maximal strings of non-blanks with the blank separation 3817c478bd9Sstevel@tonic-gate * attached at the end. Pass these words along to the output 3827c478bd9Sstevel@tonic-gate * line packer. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate 385b7d62af5Sceastha static void 3867c478bd9Sstevel@tonic-gate csplit(wchar_t line[]) 3877c478bd9Sstevel@tonic-gate { 388b7d62af5Sceastha wchar_t *cp, *cp2; 3897c478bd9Sstevel@tonic-gate wchar_t word[BUFSIZ]; 3907c478bd9Sstevel@tonic-gate static const wchar_t *srchlist = (const wchar_t *) L".:!?"; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate cp = line; 3937c478bd9Sstevel@tonic-gate while (*cp) { 3947c478bd9Sstevel@tonic-gate cp2 = word; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Collect a 'word,' allowing it to contain escaped 3987c478bd9Sstevel@tonic-gate * white space. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate while (*cp && !(iswspace(*cp))) { 4027c478bd9Sstevel@tonic-gate if (*cp == '\\' && iswspace(cp[1])) 4037c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 4047c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * Guarantee a space at end of line. 4097c478bd9Sstevel@tonic-gate * Two spaces after end of sentence punctuation. 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate if (*cp == L'\0') { 4137c478bd9Sstevel@tonic-gate *cp2++ = L' '; 4147c478bd9Sstevel@tonic-gate if (wschr(srchlist, cp[-1]) != NULL) 4157c478bd9Sstevel@tonic-gate *cp2++ = L' '; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate while (iswspace(*cp)) 4187c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 4197c478bd9Sstevel@tonic-gate *cp2 = L'\0'; 4207c478bd9Sstevel@tonic-gate pack(word); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 424b7d62af5Sceastha static void 4257c478bd9Sstevel@tonic-gate msplit(wchar_t line[]) 4267c478bd9Sstevel@tonic-gate { 427b7d62af5Sceastha wchar_t *cp, *cp2, prev; 4287c478bd9Sstevel@tonic-gate wchar_t word[BUFSIZ]; 4297c478bd9Sstevel@tonic-gate static const wchar_t *srchlist = (const wchar_t *) L".:!?"; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate cp = line; 4327c478bd9Sstevel@tonic-gate while (*cp) { 4337c478bd9Sstevel@tonic-gate cp2 = word; 4347c478bd9Sstevel@tonic-gate prev = *cp; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * Collect a 'word,' allowing it to contain escaped 4387c478bd9Sstevel@tonic-gate * white space. 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate while (*cp) { 4427c478bd9Sstevel@tonic-gate if (iswspace(*cp)) 4437c478bd9Sstevel@tonic-gate break; 4447c478bd9Sstevel@tonic-gate if (_wckind(*cp) != _wckind(prev)) 4457c478bd9Sstevel@tonic-gate if (wcsetno(*cp) != 0 || wcsetno(prev) != 0) 4467c478bd9Sstevel@tonic-gate break; 4477c478bd9Sstevel@tonic-gate if (*cp == '\\' && iswspace(cp[1])) 4487c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 4497c478bd9Sstevel@tonic-gate prev = *cp; 4507c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate /* 4547c478bd9Sstevel@tonic-gate * Guarantee a space at end of line. 4557c478bd9Sstevel@tonic-gate * Two spaces after end of sentence punctuation. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate if (*cp == L'\0') { 4597c478bd9Sstevel@tonic-gate *cp2++ = L' '; 4607c478bd9Sstevel@tonic-gate if (wschr(srchlist, cp[-1]) != NULL) 4617c478bd9Sstevel@tonic-gate *cp2++ = L' '; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate while (iswspace(*cp)) 4647c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 4657c478bd9Sstevel@tonic-gate *cp2 = L'\0'; 4667c478bd9Sstevel@tonic-gate pack(word); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate /* 4717c478bd9Sstevel@tonic-gate * Output section. 4727c478bd9Sstevel@tonic-gate * Build up line images from the words passed in. Prefix 4737c478bd9Sstevel@tonic-gate * each line with correct number of blanks. The buffer "outbuf" 4747c478bd9Sstevel@tonic-gate * contains the current partial line image, including prefixed blanks. 4757c478bd9Sstevel@tonic-gate * "outp" points to the next available space therein. When outp is NOSTR, 4767c478bd9Sstevel@tonic-gate * there ain't nothing in there yet. At the bottom of this whole mess, 4777c478bd9Sstevel@tonic-gate * leading tabs are reinserted. 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * Pack a word onto the output line. If this is the beginning of 4827c478bd9Sstevel@tonic-gate * the line, push on the appropriately-sized string of blanks first. 4837c478bd9Sstevel@tonic-gate * If the word won't fit on the current line, flush and begin a new 4847c478bd9Sstevel@tonic-gate * line. If the word is too long to fit all by itself on a line, 4857c478bd9Sstevel@tonic-gate * just give it its own and hope for the best. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate 488b7d62af5Sceastha static void 4897c478bd9Sstevel@tonic-gate pack(wchar_t word[]) 4907c478bd9Sstevel@tonic-gate { 491b7d62af5Sceastha wchar_t *cp; 492b7d62af5Sceastha int s, t; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate if (outp == NOSTR) 4957c478bd9Sstevel@tonic-gate leadin(); 4967c478bd9Sstevel@tonic-gate t = wscol(word); 4977c478bd9Sstevel@tonic-gate *outp = L'\0'; 4987c478bd9Sstevel@tonic-gate s = wscol(outbuf); 4997c478bd9Sstevel@tonic-gate if (t+s <= width) { 500e1ab4a07SJohn Sonnenschein for (cp = word; *cp; *outp++ = *cp++) { 501e1ab4a07SJohn Sonnenschein } 5027c478bd9Sstevel@tonic-gate return; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate if (s > filler) { 5057c478bd9Sstevel@tonic-gate oflush(); 5067c478bd9Sstevel@tonic-gate leadin(); 5077c478bd9Sstevel@tonic-gate } 508e1ab4a07SJohn Sonnenschein for (cp = word; *cp; *outp++ = *cp++) { 509e1ab4a07SJohn Sonnenschein } 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * If there is anything on the current output line, send it on 5147c478bd9Sstevel@tonic-gate * its way. Set outp to NOSTR to indicate the absence of the current 5157c478bd9Sstevel@tonic-gate * line prefix. 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate 518b7d62af5Sceastha static void 5197c478bd9Sstevel@tonic-gate oflush(void) 5207c478bd9Sstevel@tonic-gate { 5217c478bd9Sstevel@tonic-gate if (outp == NOSTR) 5227c478bd9Sstevel@tonic-gate return; 5237c478bd9Sstevel@tonic-gate *outp = L'\0'; 5247c478bd9Sstevel@tonic-gate tabulate(outbuf); 5257c478bd9Sstevel@tonic-gate outp = NOSTR; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * Take the passed line buffer, insert leading tabs where possible, and 5307c478bd9Sstevel@tonic-gate * output on standard output (finally). 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate 533b7d62af5Sceastha static void 5347c478bd9Sstevel@tonic-gate tabulate(wchar_t line[]) 5357c478bd9Sstevel@tonic-gate { 536b7d62af5Sceastha wchar_t *cp; 537b7d62af5Sceastha int b, t; 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* Toss trailing blanks in the output line */ 5417c478bd9Sstevel@tonic-gate cp = line + wslen(line) - 1; 5427c478bd9Sstevel@tonic-gate while (cp >= line && *cp == L' ') 5437c478bd9Sstevel@tonic-gate cp--; 5447c478bd9Sstevel@tonic-gate *++cp = L'\0'; 5457c478bd9Sstevel@tonic-gate /* Count the leading blank space and tabulate */ 546e1ab4a07SJohn Sonnenschein for (cp = line; *cp == L' '; cp++) { 547e1ab4a07SJohn Sonnenschein } 5487c478bd9Sstevel@tonic-gate b = cp - line; 5497c478bd9Sstevel@tonic-gate t = b >> 3; 5507c478bd9Sstevel@tonic-gate b &= 07; 5517c478bd9Sstevel@tonic-gate if (t > 0) 5525e924907SJohn Sonnenschein do { 5537c478bd9Sstevel@tonic-gate putc('\t', stdout); 5545e924907SJohn Sonnenschein } while (--t); 5557c478bd9Sstevel@tonic-gate if (b > 0) 5565e924907SJohn Sonnenschein do { 5577c478bd9Sstevel@tonic-gate putc(' ', stdout); 5585e924907SJohn Sonnenschein } while (--b); 5597c478bd9Sstevel@tonic-gate while (*cp) 5607c478bd9Sstevel@tonic-gate putwc(*cp++, stdout); 5617c478bd9Sstevel@tonic-gate putc('\n', stdout); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * Initialize the output line with the appropriate number of 5667c478bd9Sstevel@tonic-gate * leading blanks. 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate 569b7d62af5Sceastha static void 570b7d62af5Sceastha leadin(void) 5717c478bd9Sstevel@tonic-gate { 572b7d62af5Sceastha int b; 573b7d62af5Sceastha wchar_t *cp; 574b7d62af5Sceastha int l; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate switch (crown_state) { 5777c478bd9Sstevel@tonic-gate case c_head: 5787c478bd9Sstevel@tonic-gate l = crown_head; 5797c478bd9Sstevel@tonic-gate crown_state = c_lead; 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate case c_lead: 5837c478bd9Sstevel@tonic-gate case c_fixup: 5847c478bd9Sstevel@tonic-gate l = crown_head; 5857c478bd9Sstevel@tonic-gate crown_state = c_fixup; 5867c478bd9Sstevel@tonic-gate break; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate case c_body: 5897c478bd9Sstevel@tonic-gate l = crown_body; 5907c478bd9Sstevel@tonic-gate break; 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate default: 5937c478bd9Sstevel@tonic-gate l = pfx; 5947c478bd9Sstevel@tonic-gate break; 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate filler = l; 5977c478bd9Sstevel@tonic-gate for (b = 0, cp = outbuf; b < l; b++) 5987c478bd9Sstevel@tonic-gate *cp++ = L' '; 5997c478bd9Sstevel@tonic-gate outp = cp; 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * Is s1 a prefix of s2?? 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate 606b7d62af5Sceastha static int 6077c478bd9Sstevel@tonic-gate ispref(wchar_t *s1, wchar_t *s2) 6087c478bd9Sstevel@tonic-gate { 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate while (*s1 != L'\0' && *s2 != L'\0') 6117c478bd9Sstevel@tonic-gate if (*s1++ != *s2++) 6127c478bd9Sstevel@tonic-gate return (0); 6137c478bd9Sstevel@tonic-gate return (1); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * Set an input option 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate 620b7d62af5Sceastha static int 621b7d62af5Sceastha setopt(char *cp) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate static int ws = 0; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate if (*cp == '-') { 6267c478bd9Sstevel@tonic-gate if (cp[1] == 'c' && cp[2] == '\0') { 6277c478bd9Sstevel@tonic-gate crown_state = c_reset; 6287c478bd9Sstevel@tonic-gate return (1); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate if (cp[1] == 's' && cp[2] == '\0') { 6317c478bd9Sstevel@tonic-gate nojoin = 1; 6327c478bd9Sstevel@tonic-gate return (1); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate if (cp[1] == 'w' && cp[2] == '\0') { 6357c478bd9Sstevel@tonic-gate ws++; 6367c478bd9Sstevel@tonic-gate return (1); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate width = atoi(cp+1); 6397c478bd9Sstevel@tonic-gate } else if (ws) { 6407c478bd9Sstevel@tonic-gate width = atoi(cp); 6417c478bd9Sstevel@tonic-gate ws = 0; 6427c478bd9Sstevel@tonic-gate } else 6437c478bd9Sstevel@tonic-gate return (0); 6447c478bd9Sstevel@tonic-gate if (width <= 0 || width >= BUFSIZ-2) { 6457c478bd9Sstevel@tonic-gate fprintf(stderr, "fmt: bad width: %d\n", width); 6467c478bd9Sstevel@tonic-gate exit(1); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate return (1); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate #define LIB_WDRESOLVE "/usr/lib/locale/%s/LC_CTYPE/wdresolve.so" 6537c478bd9Sstevel@tonic-gate #define WCHKIND "_wdchkind_" 6547c478bd9Sstevel@tonic-gate 655b7d62af5Sceastha static int _wckind_c_locale(wchar_t); 6567c478bd9Sstevel@tonic-gate 657b7d62af5Sceastha static int (*__wckind)(wchar_t) = _wckind_c_locale; 6587c478bd9Sstevel@tonic-gate static void *dlhandle = NULL; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate 661b7d62af5Sceastha static void 662b7d62af5Sceastha _wckind_init(void) 6637c478bd9Sstevel@tonic-gate { 6647c478bd9Sstevel@tonic-gate char *locale; 6657c478bd9Sstevel@tonic-gate char path[MAXPATHLEN + 1]; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate if (dlhandle != NULL) { 6697c478bd9Sstevel@tonic-gate (void) dlclose(dlhandle); 6707c478bd9Sstevel@tonic-gate dlhandle = NULL; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate locale = setlocale(LC_CTYPE, NULL); 6747c478bd9Sstevel@tonic-gate if (strcmp(locale, "C") == 0) 6757c478bd9Sstevel@tonic-gate goto c_locale; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate (void) sprintf(path, LIB_WDRESOLVE, locale); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate if ((dlhandle = dlopen(path, RTLD_LAZY)) != NULL) { 680b7d62af5Sceastha __wckind = (int (*)(wchar_t))dlsym(dlhandle, WCHKIND); 6817c478bd9Sstevel@tonic-gate if (__wckind != NULL) 6827c478bd9Sstevel@tonic-gate return; 6837c478bd9Sstevel@tonic-gate (void) dlclose(dlhandle); 6847c478bd9Sstevel@tonic-gate dlhandle = NULL; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate c_locale: 6887c478bd9Sstevel@tonic-gate __wckind = _wckind_c_locale; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate int 693b7d62af5Sceastha _wckind(wchar_t wc) 6947c478bd9Sstevel@tonic-gate { 6957c478bd9Sstevel@tonic-gate return (*__wckind) (wc); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate static int 700b7d62af5Sceastha _wckind_c_locale(wchar_t wc) 7017c478bd9Sstevel@tonic-gate { 7027c478bd9Sstevel@tonic-gate int ret; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* 7057c478bd9Sstevel@tonic-gate * DEPEND_ON_ANSIC: L notion for the character is new in 7067c478bd9Sstevel@tonic-gate * ANSI-C, k&r compiler won't work. 7077c478bd9Sstevel@tonic-gate */ 7087c478bd9Sstevel@tonic-gate if (iswascii(wc)) 7097c478bd9Sstevel@tonic-gate ret = (iswalnum(wc) || wc == L'_') ? 0 : 1; 7107c478bd9Sstevel@tonic-gate else 7117c478bd9Sstevel@tonic-gate ret = wcsetno(wc) + 1; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate return (ret); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate /* 7177c478bd9Sstevel@tonic-gate * header_chk - 7187c478bd9Sstevel@tonic-gate * Called when done looking for a set mail header lines. 7197c478bd9Sstevel@tonic-gate * Either a blank line was seen, or EOF was reached. 7207c478bd9Sstevel@tonic-gate * 7217c478bd9Sstevel@tonic-gate * Verifies if current hdrbuf of potential mail header lines 7227c478bd9Sstevel@tonic-gate * is really a mail header. A mail header must be at least 2 7237c478bd9Sstevel@tonic-gate * lines and more than half of them must start with one of the 7247c478bd9Sstevel@tonic-gate * known mail header strings in headnames. 7257c478bd9Sstevel@tonic-gate * 7267c478bd9Sstevel@tonic-gate * header_chk sets hdr_state to do_hdr if hdrbuf contained a valid 7277c478bd9Sstevel@tonic-gate * mail header. Otherwise, it sets hdr_state to flush_hdr. 7287c478bd9Sstevel@tonic-gate * 7297c478bd9Sstevel@tonic-gate * h_lines = hdrbuf index for next line to be saved; 7307c478bd9Sstevel@tonic-gate * also indicates current # of lines in potential header 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate static void 7337c478bd9Sstevel@tonic-gate header_chk(void) 7347c478bd9Sstevel@tonic-gate { 7357c478bd9Sstevel@tonic-gate wchar_t *cp; /* ptr to current char of line */ 7367c478bd9Sstevel@tonic-gate wchar_t **hp; /* ptr to current char of a valid */ 7377c478bd9Sstevel@tonic-gate /* mail header string */ 7387c478bd9Sstevel@tonic-gate int l; /* index */ 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * number of lines in hdrbuf that look 7417c478bd9Sstevel@tonic-gate * like mail header lines (start with 7427c478bd9Sstevel@tonic-gate * a known mail header prefix) 7437c478bd9Sstevel@tonic-gate */ 7447c478bd9Sstevel@tonic-gate int hdrcount = 0; 7457c478bd9Sstevel@tonic-gate /* header must have at least 2 lines (h_lines > 1) */ 7467c478bd9Sstevel@tonic-gate if (h_lines < 2) { 7477c478bd9Sstevel@tonic-gate hdr_state = flush_hdr; 7487c478bd9Sstevel@tonic-gate return; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * go through each line in hdrbuf and see how many 7527c478bd9Sstevel@tonic-gate * look like mail header lines 7537c478bd9Sstevel@tonic-gate */ 7547c478bd9Sstevel@tonic-gate for (l = 0; l < h_lines; l++) { 7557c478bd9Sstevel@tonic-gate /* skip initial blanks */ 756e1ab4a07SJohn Sonnenschein for (cp = hdrbuf[l]; *cp == L' '; cp++) { 757e1ab4a07SJohn Sonnenschein } 7587c478bd9Sstevel@tonic-gate for (hp = &headnames[0]; *hp != (wchar_t *)0; hp++) 7597c478bd9Sstevel@tonic-gate if (ispref(*hp, cp)) { 7607c478bd9Sstevel@tonic-gate hdrcount++; 7617c478bd9Sstevel@tonic-gate break; 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate /* 7657c478bd9Sstevel@tonic-gate * if over half match, we'll assume this is a header; 7667c478bd9Sstevel@tonic-gate * set hdr_state to indicate whether to treat 7677c478bd9Sstevel@tonic-gate * these lines as mail header (do_hdr) or not (flush_hdr) 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate if (hdrcount > h_lines / 2) 7707c478bd9Sstevel@tonic-gate hdr_state = do_hdr; 7717c478bd9Sstevel@tonic-gate else 7727c478bd9Sstevel@tonic-gate hdr_state = flush_hdr; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* 7767c478bd9Sstevel@tonic-gate * fill_hdrbuf - 7777c478bd9Sstevel@tonic-gate * Save given input line into next element of hdrbuf, 7787c478bd9Sstevel@tonic-gate * as a potential mail header line, to be processed later 7797c478bd9Sstevel@tonic-gate * once we decide whether or not the contents of hdrbuf is 7807c478bd9Sstevel@tonic-gate * really a mail header, via header_chk(). 7817c478bd9Sstevel@tonic-gate * 7827c478bd9Sstevel@tonic-gate * Does not allow hdrbuf to exceed MAXLINES lines. 7837c478bd9Sstevel@tonic-gate * Dynamically allocates space for each line. If we are unable 7847c478bd9Sstevel@tonic-gate * to allocate space for the current string, stop special mail 7857c478bd9Sstevel@tonic-gate * header preservation at this point and continue formatting 7867c478bd9Sstevel@tonic-gate * without it. 7877c478bd9Sstevel@tonic-gate */ 7887c478bd9Sstevel@tonic-gate static void 7897c478bd9Sstevel@tonic-gate fill_hdrbuf(wchar_t line[]) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate wchar_t *cp; /* pointer to characters in input line */ 7927c478bd9Sstevel@tonic-gate int i; /* index into characters a hdrbuf line */ 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate if (h_lines >= MAXLINES) { 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * if we run over MAXLINES potential mail header 7977c478bd9Sstevel@tonic-gate * lines, stop checking--this is most likely NOT a 7987c478bd9Sstevel@tonic-gate * mail header; flush out the hdrbuf, then process 7997c478bd9Sstevel@tonic-gate * the current 'line' normally. 8007c478bd9Sstevel@tonic-gate */ 8017c478bd9Sstevel@tonic-gate hdr_state = flush_hdr; 8027c478bd9Sstevel@tonic-gate process_hdrbuf(); 8037c478bd9Sstevel@tonic-gate prefix(line); 8047c478bd9Sstevel@tonic-gate return; 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate hdrbuf[h_lines] = (wchar_t *)malloc(sizeof (wchar_t) * 8077c478bd9Sstevel@tonic-gate (wslen(line) + 1)); 8087c478bd9Sstevel@tonic-gate if (hdrbuf[h_lines] == NULL) { 8097c478bd9Sstevel@tonic-gate perror("malloc"); 8107c478bd9Sstevel@tonic-gate fprintf(stderr, "fmt: unable to do mail header preservation\n"); 8117c478bd9Sstevel@tonic-gate errs++; 8127c478bd9Sstevel@tonic-gate /* 8137c478bd9Sstevel@tonic-gate * Can't process mail header; flush current contents 8147c478bd9Sstevel@tonic-gate * of mail header and continue with no more mail 8157c478bd9Sstevel@tonic-gate * header processing 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate if (h_lines == 0) 8187c478bd9Sstevel@tonic-gate /* hdrbuf is empty; process this line normally */ 8197c478bd9Sstevel@tonic-gate prefix(line); 8207c478bd9Sstevel@tonic-gate else { 8217c478bd9Sstevel@tonic-gate hdr_state = flush_hdr; 8227c478bd9Sstevel@tonic-gate for (i = 0; i < h_lines; i++) { 8237c478bd9Sstevel@tonic-gate prefix(hdrbuf[i]); 8247c478bd9Sstevel@tonic-gate free(hdrbuf[i]); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate h_lines = 0; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate hdr_state = off; 8297c478bd9Sstevel@tonic-gate return; 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate /* save this line as a potential mail header line */ 832e1ab4a07SJohn Sonnenschein for (i = 0, cp = line; (hdrbuf[h_lines][i] = *cp) != L'\0'; i++, cp++) { 833e1ab4a07SJohn Sonnenschein } 8347c478bd9Sstevel@tonic-gate h_lines++; 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate /* 8387c478bd9Sstevel@tonic-gate * process_hdrbuf - 8397c478bd9Sstevel@tonic-gate * Outputs the lines currently stored in hdrbuf, according 8407c478bd9Sstevel@tonic-gate * to the current hdr_state value, assumed to be either do_hdr 8417c478bd9Sstevel@tonic-gate * or flush_hdr. 8427c478bd9Sstevel@tonic-gate * This should be called after doing a header_chk() to verify 8437c478bd9Sstevel@tonic-gate * the hdrbuf and set the hdr_state flag. 8447c478bd9Sstevel@tonic-gate */ 8457c478bd9Sstevel@tonic-gate static void 8467c478bd9Sstevel@tonic-gate process_hdrbuf(void) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate int i; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate for (i = 0; i < h_lines; i++) { 8517c478bd9Sstevel@tonic-gate prefix(hdrbuf[i]); 8527c478bd9Sstevel@tonic-gate free(hdrbuf[i]); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate hdr_state = not_in_hdr; 8557c478bd9Sstevel@tonic-gate h_lines = 0; 8567c478bd9Sstevel@tonic-gate } 857