source: trunk/athena/bin/just/just.c @ 12350

Revision 12350, 6.1 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 *      $Id: just.c,v 1.4 1999-01-22 23:10:32 ghudson Exp $
3 */
4
5#ifndef lint
6static char *rcsid_just_c = "$Id: just.c,v 1.4 1999-01-22 23:10:32 ghudson Exp $";
7#endif  lint
8
9/*
10 * fill/just filter
11 *
12 * Initial Coding 7 Feb 80, bbn:yba.
13 * Version of 21 Sep 83, fsi:yba
14 * Rehashed 18 Mar 85, mit:yba
15 *
16 *
17 * Use: fill [line_length]      (1 <= line_length <= 510.)
18 *      just [line_length]
19 *
20 * Will fill lines or fill and justify lines to line_length (default
21 * LINESIZE, below).
22 *
23 * Word longer than line_length are truncated!
24 * Tabs are converted on input; double space at end of sentence is
25 *     preserved.  Indentation for first line of paragraph preserved;
26 *     subsequent lines have indentation of second line (if present).
27 */
28
29/* Next Page */
30/* Globals */
31
32/* Macros to convert Version 6 cc and BBN library to 4.2bsd and V7 */
33
34#define seq(a,b)        (strcmp (a,b) == 0)
35#define scopy(a,b,c)    (strchr (strcpy (b,a), '\0'))
36#define slength         strlen
37#define errmsg          perror
38
39#include <stdio.h>
40#include <string.h>
41
42#define MAXLINE 512
43#define LINESIZE        65      /* default line_length */
44
45#define min(x,y)        ((x) < (y) ? (x) : (y))
46#define max(x,y)        ((x) > (y) ? (x) : (y))
47
48int     just;                   /* bool: fill (false) or just (true)? */
49int     nwords = 0;
50int     line_width = LINESIZE;
51int     inval = 0;              /* indentation from left margin */
52
53char    inbuf[MAXLINE],
54        outbuf[MAXLINE],
55        wordbuf[MAXLINE];
56
57char   *inptr = inbuf,
58       *outptr = outbuf,
59       *wordptr = wordbuf;
60
61char   *me;
62
63
64/* Next Page */
65
66main (argc, argv)
67int     argc;
68char   *argv[];
69{
70    char   *fgets ();
71
72
73    int     nlp = 0;            /* # lines in current paragraph */
74    int     i;
75    char    c;
76
77    me = strrchr (argv[0], '/');        /* fill or just? */
78    if (me == NULL)             /* No prefix to strip? */
79        me = argv[0];
80
81    if (argc > 2)
82        arg_err ();
83
84    if (argc > 1)
85        line_width = max (min (MAXLINE - 2, atoi (argv[1])), 1);
86
87    just = seq (me, "just");
88
89    outbuf[0] = '\0';
90    while (fgets (inbuf, MAXLINE, stdin) != NULL) {
91        inptr = inbuf;
92
93        /* Check for blank lines and breaks (last line of paragraph, etc.) */
94
95        while (*inptr == '\n')
96            if (nwords > 0) {   /* break? */
97                puts (outbuf);  /* never justify this line */
98                outptr = outbuf;
99                outbuf[0] = '\0';
100                nwords = 0;
101                nlp = 0;
102                }
103            else
104                putchar (*inptr++);/* blank line */
105
106        if (nlp == 0 && (*inptr != '\0')) {     /* 1st line of paragraph */
107            while (*inptr == ' ' || *inptr == '\t')
108                if (*inptr == ' ')
109                    *outptr++ = *inptr++;
110                else {          /* convert tabs */
111                    inptr++;
112                    i = (*outptr = '\0', slength (outbuf));
113                    do
114                        *outptr++ = ' ';
115                        while (++i % 8 != 0 && (outptr < &outbuf[line_width - 1]));
116                    }
117            *outptr = '\0';
118            /*
119             * Above we read from the buffered 1st line of the paragraph;
120             * below note that we are looking at stdin again,
121             * reading the second line (if any) of that paragraph
122             */
123            for (inval = 0; (c = getchar ()) == ' ' || (c == '\t');)
124                if (c == '\t')
125                    while (++inval % 8 != 0 && (inval < (line_width - 1)));
126                else
127                    inval++;
128
129            if (!feof (stdin))
130                ungetc (c, stdin);
131            nlp++;
132            }
133
134        while (getword ())
135            putword ();
136        }
137
138    if (outptr != outbuf)
139        puts (outbuf);
140    exit (0);
141}
142
143/* Next Page */
144
145/*
146 * getword -- returns true if it got a word; copies a word from inptr to outptr
147 */
148
149getword ()
150{
151    wordptr = wordbuf;
152    while (*inptr == ' ' || *inptr == '\t')
153        inptr++;
154    while (*inptr != ' ' && *inptr != '\t' && *inptr != '\n' && *inptr != '\0')
155        *wordptr++ = *inptr++;
156
157 /* add an extra space after end of sentence if it was present in source, *
158    or if at the end of a line */
159
160    if (wordptr != wordbuf && isbreak (*(inptr - 1)) && (*(inptr + 1) == ' ' || *inptr == '\n'))
161        *wordptr++ = ' ';
162
163    *wordptr = '\0';
164    return slength (wordbuf);
165}
166
167/* Next Page */
168
169/*
170 * putword -- write a word into outbuf if it fits, pads and writes the
171 *      buffer as appropriate
172 */
173
174putword ()
175{
176    char   *strcpy ();
177    register int    i = inval,
178                    sl = slength (wordbuf) + slength (outbuf);
179
180    if (*(wordptr - 1) == ' ' && sl == line_width) {
181        *--wordptr = '\0';      /* get rid of space at end of line */
182        sl--;                   /* if it would put us over by one */
183        }
184    if (sl >= line_width) {
185        while (*(outptr - 1) == ' ')/* no spaces at end of line */
186            *--outptr = '\0';
187        if (just)
188            spread ();
189        *outptr = '\n';
190        *++outptr = '\0';
191        fputs (outbuf, stdout);
192        outptr = outbuf;
193        nwords = 0;
194        while (i--)
195            *outptr++ = ' ';
196        }
197    else
198        if (outptr != outbuf && nwords)
199            *outptr++ = ' ';
200
201 /* the scopy below places a null ('\0') at the end of the string * in
202    outbuf */
203    outptr = scopy (wordbuf, outptr, &outbuf[line_width]);
204    nwords++;
205}
206
207/* Next Page */
208
209/* spread -- spread out lines using the justification algorithm of
210 *      Kernighan and Plauger, "Software Tools", Chap. 7, pg. 241
211 *      (1976 edition)
212 */
213
214spread ()
215{
216    static int  dir = 0;
217    int     nextra = line_width - slength (outbuf),
218            ne,
219            nholes,
220            nb;
221    char   *ip,
222           *jp;
223
224    if (nextra > 0 && nwords > 1) {
225        dir = 1 - dir;          /* alternate side to put extra space on */
226        ne = nextra;
227        nholes = nwords - 1;
228        ip = outptr - 1;
229        jp = min (&outbuf[line_width], (ip + ne));
230        outptr = jp + 1;
231        while (ip < jp) {
232            *jp = *ip;
233            if (*ip == ' ') {
234                if (dir == 0)
235                    nb = (ne - 1) / nholes + 1;
236                else
237                    nb = ne / nholes;
238                ne -= nb;
239                nholes--;
240                for (; nb > 0; nb--)
241                    *--jp = ' ';
242                while (*(ip - 1) == ' ')
243                    *--jp = *--ip;/* protected space */
244                }
245            ip--;
246            jp--;
247            }
248        }
249}
250
251/* Next Page */
252
253/*
254 * arg_err -- usage message; because this is used as an editor filter,
255 *      copy the input to the output if being misued -- this prevents
256 *      the user's entire input from disappearing in vi, pen, etc.
257 */
258
259arg_err ()
260{
261    int     c;
262
263    fprintf (stderr, "%s: Usage is %s [line width].\n", me, me);
264
265    while ((c = getchar ()) != EOF)
266        putchar (c);
267
268    exit (1);
269}
270
271/* Next Page */
272/*
273 * isbreak -- is a character a member of the "ends a sentence" set?
274 */
275
276isbreak (c)
277    register char   c;
278{
279    switch (c) {
280        case '.':
281        case '!':
282        case '?':
283        case ':':
284            return (c);         /* true */
285            break;              /* pro forma */
286        default:
287            return (0);         /* false */
288        }
289}
Note: See TracBrowser for help on using the repository browser.