]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/fixwhite/fixwhite.c
zfs: merge openzfs/zfs@8a7407012
[FreeBSD/FreeBSD.git] / tools / tools / fixwhite / fixwhite.c
1 /*-
2  * Copyright (c) 2012 Ed Schouten <ed@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 #include <ctype.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 static char *queue = NULL;
34 static size_t queuelen = 0, queuesize = 0;
35 static off_t column = 0;
36
37 static void
38 savebyte(char c)
39 {
40
41         if (queuelen >= queuesize) {
42                 queuesize += 128;
43                 queue = realloc(queue, queuesize);
44                 if (queue == NULL) {
45                         perror("malloc");
46                         exit(1);
47                 }
48         }
49         queue[queuelen++] = c;
50
51         switch (c) {
52         case '\n':
53                 column = 0;
54                 break;
55         case ' ':
56                 column++;
57                 break;
58         case '\t':
59                 column = (column / 8 + 1) * 8;
60                 break;
61         }
62 }
63
64 static bool
65 peekbyte(size_t back, char c)
66 {
67
68         return (queuelen >= back && queue[queuelen - back] == c);
69 }
70
71 static void
72 savewhite(char c, bool leading)
73 {
74         off_t ncolumn;
75
76         switch (c) {
77         case '\n':
78                 if (leading) {
79                         /* Remove empty lines before input. */
80                         queuelen = 0;
81                         column = 0;
82                 } else {
83                         /* Remove trailing whitespace. */
84                         while (peekbyte(1, ' ') || peekbyte(1, '\t'))
85                                 queuelen--;
86                         /* Remove redundant empty lines. */
87                         if (peekbyte(2, '\n') && peekbyte(1, '\n'))
88                                 return;
89                         savebyte('\n');
90                 }
91                 break;
92         case ' ':
93                 savebyte(' ');
94                 break;
95         case '\t':
96                 /* Convert preceding spaces to tabs. */
97                 ncolumn = (column / 8 + 1) * 8;
98                 while (peekbyte(1, ' ')) {
99                         queuelen--;
100                         column--;
101                 }
102                 while (column < ncolumn)
103                         savebyte('\t');
104                 break;
105         }
106 }
107
108 static void
109 printwhite(void)
110 {
111         off_t i;
112
113         /* Merge spaces at the start of a sentence to tabs if possible. */
114         if ((column % 8) == 0) {
115                 for (i = 0; i < column; i++)
116                         if (!peekbyte(i + 1, ' '))
117                                 break;
118                 if (i == column) {
119                         queuelen -= column;
120                         for (i = 0; i < column; i += 8)
121                                 queue[queuelen++] = '\t';
122                 }
123         }
124
125         if (fwrite(queue, 1, queuelen, stdout) != queuelen) {
126                 perror("write");
127                 exit(1);
128         }
129         queuelen = 0;
130 }
131
132 static char
133 readchar(void)
134 {
135         int c;
136
137         c = getchar();
138         if (c == EOF && ferror(stdin)) {
139                 perror("read");
140                 exit(1);
141         }
142         return (c);
143 }
144
145 static void
146 writechar(char c)
147 {
148
149         if (putchar(c) == EOF) {
150                 perror("write");
151                 exit(1);
152         }
153         /* XXX: Multi-byte characters. */
154         column++;
155 }
156
157 int
158 main(void)
159 {
160         int c;
161         bool leading = true;
162
163         while ((c = readchar()) != EOF) {
164                 if (isspace(c))
165                         /* Save whitespace. */
166                         savewhite(c, leading);
167                 else {
168                         /* Reprint whitespace and print regular character. */
169                         printwhite();
170                         writechar(c);
171                         leading = false;
172                 }
173         }
174         /* Terminate non-empty files with a newline. */
175         if (!leading)
176                 writechar('\n');
177         return (0);
178 }