Tue Jan 7 02:07:09 2014 UTC ()
Annotate functions using format strings.


(joerg)
diff -r1.8 -r1.9 src/usr.bin/flock/flock.c
diff -r1.1 -r1.2 src/usr.bin/ftp/ssl.h
diff -r1.24 -r1.25 src/usr.bin/units/units.c

cvs diff -r1.8 -r1.9 src/usr.bin/flock/flock.c (switch to unified diff)

--- src/usr.bin/flock/flock.c 2013/10/29 16:02:15 1.8
+++ src/usr.bin/flock/flock.c 2014/01/07 02:07:08 1.9
@@ -1,303 +1,303 @@ @@ -1,303 +1,303 @@
1/* $NetBSD: flock.c,v 1.8 2013/10/29 16:02:15 christos Exp $ */ 1/* $NetBSD: flock.c,v 1.9 2014/01/07 02:07:08 joerg Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas. 8 * by Christos Zoulas.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * from this software without specific prior written permission. 18 * from this software without specific prior written permission.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__RCSID("$NetBSD: flock.c,v 1.8 2013/10/29 16:02:15 christos Exp $"); 34__RCSID("$NetBSD: flock.c,v 1.9 2014/01/07 02:07:08 joerg Exp $");
35 35
36#include <stdio.h> 36#include <stdio.h>
37#include <string.h> 37#include <string.h>
38#include <fcntl.h> 38#include <fcntl.h>
39#include <stdlib.h> 39#include <stdlib.h>
40#include <signal.h> 40#include <signal.h>
41#include <unistd.h> 41#include <unistd.h>
42#include <err.h> 42#include <err.h>
43#include <errno.h> 43#include <errno.h>
44#include <getopt.h> 44#include <getopt.h>
45#include <paths.h> 45#include <paths.h>
46#include <time.h> 46#include <time.h>
47 47
48static struct option flock_longopts[] = { 48static struct option flock_longopts[] = {
49 { "debug", no_argument, 0, 'd' }, 49 { "debug", no_argument, 0, 'd' },
50 { "help", no_argument, 0, 'h' }, 50 { "help", no_argument, 0, 'h' },
51 { "nonblock", no_argument, 0, 'n' }, 51 { "nonblock", no_argument, 0, 'n' },
52 { "nb", no_argument, 0, 'n' }, 52 { "nb", no_argument, 0, 'n' },
53 { "close", no_argument, 0, 'o' }, 53 { "close", no_argument, 0, 'o' },
54 { "shared", no_argument, 0, 's' }, 54 { "shared", no_argument, 0, 's' },
55 { "exclusive", no_argument, 0, 'x' }, 55 { "exclusive", no_argument, 0, 'x' },
56 { "unlock", no_argument, 0, 'u' }, 56 { "unlock", no_argument, 0, 'u' },
57 { "verbose", no_argument, 0, 'v' }, 57 { "verbose", no_argument, 0, 'v' },
58 { "command", required_argument, 0, 'c' }, 58 { "command", required_argument, 0, 'c' },
59 { "wait", required_argument, 0, 'w' }, 59 { "wait", required_argument, 0, 'w' },
60 { "timeout", required_argument, 0, 'w' }, 60 { "timeout", required_argument, 0, 'w' },
61 { NULL, 0, 0, 0 }, 61 { NULL, 0, 0, 0 },
62}; 62};
63 63
64static sig_atomic_t timeout_expired; 64static sig_atomic_t timeout_expired;
65 65
66static __dead void 66static __dead __printflike(1, 2) void
67usage(const char *fmt, ...)  67usage(const char *fmt, ...)
68{ 68{
69 if (fmt) { 69 if (fmt) {
70 va_list ap; 70 va_list ap;
71 va_start(ap, fmt); 71 va_start(ap, fmt);
72 fprintf(stderr, "%s: ", getprogname()); 72 fprintf(stderr, "%s: ", getprogname());
73 vfprintf(stderr, fmt, ap); 73 vfprintf(stderr, fmt, ap);
74 fputc('\n', stderr); 74 fputc('\n', stderr);
75 va_end(ap); 75 va_end(ap);
76 } 76 }
77 77
78 fprintf(stderr, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir " 78 fprintf(stderr, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir "
79 "[-c command]|command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n", 79 "[-c command]|command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n",
80 getprogname(), getprogname()); 80 getprogname(), getprogname());
81 exit(EXIT_FAILURE); 81 exit(EXIT_FAILURE);
82} 82}
83 83
84static void 84static void
85sigalrm(int sig) 85sigalrm(int sig)
86{ 86{
87 timeout_expired++; 87 timeout_expired++;
88} 88}
89 89
90static const char * 90static const char *
91lock2name(int l) 91lock2name(int l)
92{ 92{
93 static char buf[1024]; 93 static char buf[1024];
94 int nb = l & LOCK_NB; 94 int nb = l & LOCK_NB;
95 95
96 l &= ~LOCK_NB; 96 l &= ~LOCK_NB;
97 if (nb) 97 if (nb)
98 strlcpy(buf, "LOCK_NB|", sizeof(buf)); 98 strlcpy(buf, "LOCK_NB|", sizeof(buf));
99 else 99 else
100 buf[0] = '\0'; 100 buf[0] = '\0';
101 101
102 switch (l) { 102 switch (l) {
103 case LOCK_SH: 103 case LOCK_SH:
104 strlcat(buf, "LOCK_SH", sizeof(buf)); 104 strlcat(buf, "LOCK_SH", sizeof(buf));
105 return buf; 105 return buf;
106 case LOCK_EX: 106 case LOCK_EX:
107 strlcat(buf, "LOCK_EX", sizeof(buf)); 107 strlcat(buf, "LOCK_EX", sizeof(buf));
108 return buf; 108 return buf;
109 case LOCK_UN: 109 case LOCK_UN:
110 strlcat(buf, "LOCK_UN", sizeof(buf)); 110 strlcat(buf, "LOCK_UN", sizeof(buf));
111 return buf; 111 return buf;
112 default: 112 default:
113 snprintf(buf, sizeof(buf), "*%d*", l | nb); 113 snprintf(buf, sizeof(buf), "*%d*", l | nb);
114 return buf; 114 return buf;
115 } 115 }
116} 116}
117 117
118static char 118static char
119lockchar(int l) 119lockchar(int l)
120{ 120{
121 switch (l & ~LOCK_NB) { 121 switch (l & ~LOCK_NB) {
122 case LOCK_SH: 122 case LOCK_SH:
123 return 's'; 123 return 's';
124 case LOCK_EX: 124 case LOCK_EX:
125 return 'x'; 125 return 'x';
126 case LOCK_UN: 126 case LOCK_UN:
127 return 'u'; 127 return 'u';
128 default: 128 default:
129 return '*'; 129 return '*';
130 } 130 }
131} 131}
132 132
133static char * 133static char *
134cmdline(char **av) 134cmdline(char **av)
135{ 135{
136 char *v = NULL; 136 char *v = NULL;
137 while (*av) 137 while (*av)
138 if (v) { 138 if (v) {
139 if (asprintf(&v, "%s %s", v, *av++) < 0) 139 if (asprintf(&v, "%s %s", v, *av++) < 0)
140 err(EXIT_FAILURE, "malloc"); 140 err(EXIT_FAILURE, "malloc");
141 } else { 141 } else {
142 if ((v = strdup(*av++)) == NULL) 142 if ((v = strdup(*av++)) == NULL)
143 err(EXIT_FAILURE, "strdup"); 143 err(EXIT_FAILURE, "strdup");
144 } 144 }
145 return v; 145 return v;
146} 146}
147 147
148int 148int
149main(int argc, char *argv[]) 149main(int argc, char *argv[])
150{ 150{
151 int c; 151 int c;
152 int lock = 0; 152 int lock = 0;
153 double timeout = 0; 153 double timeout = 0;
154 int cls = 0; 154 int cls = 0;
155 int fd = -1; 155 int fd = -1;
156 int debug = 0; 156 int debug = 0;
157 int verbose = 0; 157 int verbose = 0;
158 char *mcargv[] = { 158 char *mcargv[] = {
159 __UNCONST(_PATH_BSHELL), __UNCONST("-c"), NULL, NULL 159 __UNCONST(_PATH_BSHELL), __UNCONST("-c"), NULL, NULL
160 }; 160 };
161 char **cmdargv = NULL, *v; 161 char **cmdargv = NULL, *v;
162 timer_t tm; 162 timer_t tm;
163 163
164 setprogname(argv[0]); 164 setprogname(argv[0]);
165 165
166 while ((c = getopt_long(argc, argv, "+dnosuvw:x", flock_longopts, NULL)) 166 while ((c = getopt_long(argc, argv, "+dnosuvw:x", flock_longopts, NULL))
167 != -1) 167 != -1)
168 switch (c) { 168 switch (c) {
169 case 'd': 169 case 'd':
170 debug++; 170 debug++;
171 break; 171 break;
172 case 'x': 172 case 'x':
173#define T(l) (lock & ~LOCK_NB) != (l) && (lock & ~LOCK_NB) != 0 173#define T(l) (lock & ~LOCK_NB) != (l) && (lock & ~LOCK_NB) != 0
174 if (T(LOCK_EX)) 174 if (T(LOCK_EX))
175 goto badlock; 175 goto badlock;
176 lock |= LOCK_EX; 176 lock |= LOCK_EX;
177 break; 177 break;
178 case 'n': 178 case 'n':
179 lock |= LOCK_NB; 179 lock |= LOCK_NB;
180 break; 180 break;
181 case 's': 181 case 's':
182 if (T(LOCK_SH)) 182 if (T(LOCK_SH))
183 goto badlock; 183 goto badlock;
184 lock |= LOCK_SH; 184 lock |= LOCK_SH;
185 break; 185 break;
186 case 'u': 186 case 'u':
187 if (T(LOCK_UN)) 187 if (T(LOCK_UN))
188 goto badlock; 188 goto badlock;
189 lock |= LOCK_UN; 189 lock |= LOCK_UN;
190 break; 190 break;
191 case 'w': 191 case 'w':
192 timeout = strtod(optarg, NULL); 192 timeout = strtod(optarg, NULL);
193 break; 193 break;
194 case 'v': 194 case 'v':
195 verbose = 1; 195 verbose = 1;
196 break; 196 break;
197 case 'o': 197 case 'o':
198 cls = 1; 198 cls = 1;
199 break; 199 break;
200 default: 200 default:
201 usage("Invalid option '%c'", c); 201 usage("Invalid option '%c'", c);
202 badlock: 202 badlock:
203 usage("-%c can't be used with -%c", c, lockchar(lock)); 203 usage("-%c can't be used with -%c", c, lockchar(lock));
204 } 204 }
205 205
206 argc -= optind; 206 argc -= optind;
207 argv += optind; 207 argv += optind;
208 208
209 if ((lock & ~LOCK_NB) == 0) 209 if ((lock & ~LOCK_NB) == 0)
210 usage("Missing lock type flag"); 210 usage("Missing lock type flag");
211 211
212 switch (argc) { 212 switch (argc) {
213 case 0: 213 case 0:
214 usage("Missing lock file argument"); 214 usage("Missing lock file argument");
215 case 1: 215 case 1:
216 if (cls) 216 if (cls)
217 usage("Close is valid only for descriptors"); 217 usage("Close is valid only for descriptors");
218 fd = strtol(argv[0], NULL, 0); // XXX: error checking 218 fd = strtol(argv[0], NULL, 0); // XXX: error checking
219 if (debug) { 219 if (debug) {
220 fprintf(stderr, "descriptor %s lock %s\n", 220 fprintf(stderr, "descriptor %s lock %s\n",
221 argv[0], lock2name(lock)); 221 argv[0], lock2name(lock));
222 } 222 }
223 break; 223 break;
224 224
225 default: 225 default:
226 if ((lock & LOCK_NB) == LOCK_UN) 226 if ((lock & LOCK_NB) == LOCK_UN)
227 usage("Unlock is only valid for descriptors"); 227 usage("Unlock is only valid for descriptors");
228 if (strcmp(argv[1], "-c") == 0 || 228 if (strcmp(argv[1], "-c") == 0 ||
229 strcmp(argv[1], "--command") == 0) { 229 strcmp(argv[1], "--command") == 0) {
230 if (argc == 2) 230 if (argc == 2)
231 usage("Missing argument to %s", strcmp(argv[1], 231 usage("Missing argument to %s", strcmp(argv[1],
232 "-c") == 0 ? "-c" : "--command"); 232 "-c") == 0 ? "-c" : "--command");
233 mcargv[2] = argv[2]; 233 mcargv[2] = argv[2];
234 cmdargv = mcargv; 234 cmdargv = mcargv;
235 } else 235 } else
236 cmdargv = argv + 1; 236 cmdargv = argv + 1;
237  237
238 if ((fd = open(argv[0], O_RDONLY)) == -1) { 238 if ((fd = open(argv[0], O_RDONLY)) == -1) {
239 if (errno != ENOENT ||  239 if (errno != ENOENT ||
240 (fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1) 240 (fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1)
241 err(EXIT_FAILURE, "Cannot open `%s'", argv[0]); 241 err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
242 } 242 }
243 if (debug) { 243 if (debug) {
244 fprintf(stderr, "file %s lock %s command %s ...\n", 244 fprintf(stderr, "file %s lock %s command %s ...\n",
245 argv[0], lock2name(lock), v = cmdline(cmdargv)); 245 argv[0], lock2name(lock), v = cmdline(cmdargv));
246 free(v); 246 free(v);
247 } 247 }
248 break; 248 break;
249 } 249 }
250 250
251 if (timeout) { 251 if (timeout) {
252 struct sigevent ev; 252 struct sigevent ev;
253 struct itimerspec it; 253 struct itimerspec it;
254 struct sigaction sa; 254 struct sigaction sa;
255 255
256 timespecclear(&it.it_interval); 256 timespecclear(&it.it_interval);
257 it.it_value.tv_sec = timeout; 257 it.it_value.tv_sec = timeout;
258 it.it_value.tv_nsec = (timeout - it.it_value.tv_sec) * 258 it.it_value.tv_nsec = (timeout - it.it_value.tv_sec) *
259 1000000000; 259 1000000000;
260 260
261 memset(&ev, 0, sizeof(ev)); 261 memset(&ev, 0, sizeof(ev));
262 ev.sigev_notify = SIGEV_SIGNAL; 262 ev.sigev_notify = SIGEV_SIGNAL;
263 ev.sigev_signo = SIGALRM; 263 ev.sigev_signo = SIGALRM;
264 264
265 if (timer_create(CLOCK_REALTIME, &ev, &tm) == -1) 265 if (timer_create(CLOCK_REALTIME, &ev, &tm) == -1)
266 err(EXIT_FAILURE, "timer_create"); 266 err(EXIT_FAILURE, "timer_create");
267 267
268 if (timer_settime(tm, TIMER_RELTIME, &it, NULL) == -1) 268 if (timer_settime(tm, TIMER_RELTIME, &it, NULL) == -1)
269 err(EXIT_FAILURE, "timer_settime"); 269 err(EXIT_FAILURE, "timer_settime");
270 270
271 memset(&sa, 0, sizeof(sa)); 271 memset(&sa, 0, sizeof(sa));
272 sa.sa_handler = sigalrm; 272 sa.sa_handler = sigalrm;
273 sigemptyset(&sa.sa_mask); 273 sigemptyset(&sa.sa_mask);
274 sa.sa_flags = 0; 274 sa.sa_flags = 0;
275 if (sigaction(SIGALRM, &sa, NULL) == -1) 275 if (sigaction(SIGALRM, &sa, NULL) == -1)
276 err(EXIT_FAILURE, "sigaction"); 276 err(EXIT_FAILURE, "sigaction");
277 277
278 if (debug) 278 if (debug)
279 fprintf(stderr, "alarm %g\n", timeout); 279 fprintf(stderr, "alarm %g\n", timeout);
280 } 280 }
281 281
282 while (flock(fd, lock) == -1) { 282 while (flock(fd, lock) == -1) {
283 if (errno == EINTR && timeout_expired == 0) 283 if (errno == EINTR && timeout_expired == 0)
284 continue; 284 continue;
285 if (verbose) 285 if (verbose)
286 err(EXIT_FAILURE, "flock(%d, %s)", fd, lock2name(lock)); 286 err(EXIT_FAILURE, "flock(%d, %s)", fd, lock2name(lock));
287 else 287 else
288 return EXIT_FAILURE; 288 return EXIT_FAILURE;
289 } 289 }
290 290
291 if (timeout) 291 if (timeout)
292 timer_delete(tm); 292 timer_delete(tm);
293 293
294 if (cls) 294 if (cls)
295 (void)close(fd); 295 (void)close(fd);
296 296
297 if (cmdargv != NULL) { 297 if (cmdargv != NULL) {
298 execvp(cmdargv[0], cmdargv); 298 execvp(cmdargv[0], cmdargv);
299 err(EXIT_FAILURE, "execvp '%s'", v = cmdline(cmdargv)); 299 err(EXIT_FAILURE, "execvp '%s'", v = cmdline(cmdargv));
300 free(v); 300 free(v);
301 } 301 }
302 return 0; 302 return 0;
303} 303}

cvs diff -r1.1 -r1.2 src/usr.bin/ftp/ssl.h (switch to unified diff)

--- src/usr.bin/ftp/ssl.h 2012/12/21 18:07:36 1.1
+++ src/usr.bin/ftp/ssl.h 2014/01/07 02:07:08 1.2
@@ -1,62 +1,63 @@ @@ -1,62 +1,63 @@
1/* $NetBSD: ssl.h,v 1.1 2012/12/21 18:07:36 christos Exp $ */ 1/* $NetBSD: ssl.h,v 1.2 2014/01/07 02:07:08 joerg Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28#ifdef WITH_SSL 28#ifdef WITH_SSL
29 29
30#define FETCH struct fetch_connect 30#define FETCH struct fetch_connect
31struct fetch_connect; 31struct fetch_connect;
32 32
33int fetch_printf(struct fetch_connect *, const char *fmt, ...); 33int fetch_printf(struct fetch_connect *, const char *fmt, ...)
 34 __printflike(2, 3);
34int fetch_fileno(struct fetch_connect *); 35int fetch_fileno(struct fetch_connect *);
35int fetch_error(struct fetch_connect *); 36int fetch_error(struct fetch_connect *);
36int fetch_flush(struct fetch_connect *); 37int fetch_flush(struct fetch_connect *);
37struct fetch_connect *fetch_open(const char *, const char *); 38struct fetch_connect *fetch_open(const char *, const char *);
38struct fetch_connect *fetch_fdopen(int, const char *); 39struct fetch_connect *fetch_fdopen(int, const char *);
39int fetch_close(struct fetch_connect *); 40int fetch_close(struct fetch_connect *);
40ssize_t fetch_read(void *, size_t, size_t, struct fetch_connect *); 41ssize_t fetch_read(void *, size_t, size_t, struct fetch_connect *);
41char *fetch_getln(char *, int, struct fetch_connect *); 42char *fetch_getln(char *, int, struct fetch_connect *);
42int fetch_getline(struct fetch_connect *, char *, size_t, const char **); 43int fetch_getline(struct fetch_connect *, char *, size_t, const char **);
43void fetch_set_ssl(struct fetch_connect *, void *); 44void fetch_set_ssl(struct fetch_connect *, void *);
44void *fetch_start_ssl(int); 45void *fetch_start_ssl(int);
45 46
46#else /* !WITH_SSL */ 47#else /* !WITH_SSL */
47 48
48#define FETCH FILE 49#define FETCH FILE
49 50
50#define fetch_printf fprintf 51#define fetch_printf fprintf
51#define fetch_fileno fileno 52#define fetch_fileno fileno
52#define fetch_error ferror 53#define fetch_error ferror
53#define fetch_flush fflush 54#define fetch_flush fflush
54#define fetch_open fopen 55#define fetch_open fopen
55#define fetch_fdopen fdopen 56#define fetch_fdopen fdopen
56#define fetch_close fclose 57#define fetch_close fclose
57#define fetch_read fread 58#define fetch_read fread
58#define fetch_getln fgets 59#define fetch_getln fgets
59#define fetch_getline get_line 60#define fetch_getline get_line
60#define fetch_set_ssl(a, b) 61#define fetch_set_ssl(a, b)
61 62
62#endif /* !WITH_SSL */ 63#endif /* !WITH_SSL */

cvs diff -r1.24 -r1.25 src/usr.bin/units/units.c (switch to unified diff)

--- src/usr.bin/units/units.c 2013/01/06 00:19:13 1.24
+++ src/usr.bin/units/units.c 2014/01/07 02:07:09 1.25
@@ -1,910 +1,910 @@ @@ -1,910 +1,910 @@
1/* $NetBSD: units.c,v 1.24 2013/01/06 00:19:13 wiz Exp $ */ 1/* $NetBSD: units.c,v 1.25 2014/01/07 02:07:09 joerg Exp $ */
2 2
3/* 3/*
4 * units.c Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu) 4 * units.c Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu)
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. The name of the author may not be used to endorse or promote products 11 * 2. The name of the author may not be used to endorse or promote products
12 * derived from this software without specific prior written permission. 12 * derived from this software without specific prior written permission.
13 * Disclaimer: This software is provided by the author "as is". The author 13 * Disclaimer: This software is provided by the author "as is". The author
14 * shall not be liable for any damages caused in any way by this software. 14 * shall not be liable for any damages caused in any way by this software.
15 * 15 *
16 * I would appreciate (though I do not require) receiving a copy of any 16 * I would appreciate (though I do not require) receiving a copy of any
17 * improvements you might make to this program. 17 * improvements you might make to this program.
18 */ 18 */
19 19
20#include <ctype.h> 20#include <ctype.h>
21#include <err.h> 21#include <err.h>
22#include <float.h> 22#include <float.h>
23#include <stdio.h> 23#include <stdio.h>
24#include <string.h> 24#include <string.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <unistd.h> 26#include <unistd.h>
27 27
28#include "pathnames.h" 28#include "pathnames.h"
29 29
30#define VERSION "1.0" 30#define VERSION "1.0"
31 31
32#ifndef UNITSFILE 32#ifndef UNITSFILE
33#define UNITSFILE _PATH_UNITSLIB 33#define UNITSFILE _PATH_UNITSLIB
34#endif 34#endif
35 35
36#define MAXUNITS 1000 36#define MAXUNITS 1000
37#define MAXPREFIXES 50 37#define MAXPREFIXES 50
38 38
39#define MAXSUBUNITS 500 39#define MAXSUBUNITS 500
40 40
41#define PRIMITIVECHAR '!' 41#define PRIMITIVECHAR '!'
42 42
43static int precision = 8; /* for printf with "%.*g" format */ 43static int precision = 8; /* for printf with "%.*g" format */
44 44
45static const char *errprefix = NULL; /* if not NULL, then prepend this 45static const char *errprefix = NULL; /* if not NULL, then prepend this
46 * to error messages and send them to 46 * to error messages and send them to
47 * stdout instead of stderr. 47 * stdout instead of stderr.
48 */ 48 */
49 49
50static const char *powerstring = "^"; 50static const char *powerstring = "^";
51 51
52static struct { 52static struct {
53 const char *uname; 53 const char *uname;
54 const char *uval; 54 const char *uval;
55} unittable[MAXUNITS]; 55} unittable[MAXUNITS];
56 56
57struct unittype { 57struct unittype {
58 const char *numerator[MAXSUBUNITS]; 58 const char *numerator[MAXSUBUNITS];
59 const char *denominator[MAXSUBUNITS]; 59 const char *denominator[MAXSUBUNITS];
60 double factor; 60 double factor;
61}; 61};
62 62
63struct { 63struct {
64 const char *prefixname; 64 const char *prefixname;
65 const char *prefixval; 65 const char *prefixval;
66} prefixtable[MAXPREFIXES]; 66} prefixtable[MAXPREFIXES];
67 67
68 68
69static const char *NULLUNIT = ""; 69static const char *NULLUNIT = "";
70 70
71static int unitcount; 71static int unitcount;
72static int prefixcount; 72static int prefixcount;
73 73
74 74
75static int addsubunit(const char *[], const char *); 75static int addsubunit(const char *[], const char *);
76static int addunit(struct unittype *, const char *, int); 76static int addunit(struct unittype *, const char *, int);
77static void cancelunit(struct unittype *); 77static void cancelunit(struct unittype *);
78static int compare(const void *, const void *); 78static int compare(const void *, const void *);
79static int compareproducts(const char **, const char **); 79static int compareproducts(const char **, const char **);
80static int compareunits(struct unittype *, struct unittype *); 80static int compareunits(struct unittype *, struct unittype *);
81static int compareunitsreciprocal(struct unittype *, struct unittype *); 81static int compareunitsreciprocal(struct unittype *, struct unittype *);
82static int completereduce(struct unittype *); 82static int completereduce(struct unittype *);
83static void initializeunit(struct unittype *); 83static void initializeunit(struct unittype *);
84static void readerror(int); 84static void readerror(int);
85static void readunits(const char *); 85static void readunits(const char *);
86static int reduceproduct(struct unittype *, int); 86static int reduceproduct(struct unittype *, int);
87static int reduceunit(struct unittype *); 87static int reduceunit(struct unittype *);
88static void showanswer(struct unittype *, struct unittype *); 88static void showanswer(struct unittype *, struct unittype *);
89static void showunit(struct unittype *); 89static void showunit(struct unittype *);
90static void sortunit(struct unittype *); 90static void sortunit(struct unittype *);
91__dead static void usage(void); 91__dead static void usage(void);
92static void zeroerror(void); 92static void zeroerror(void);
93static char *dupstr(const char *); 93static char *dupstr(const char *);
94static const char *lookupunit(const char *); 94static const char *lookupunit(const char *);
95 95
96static char * 96static char *
97dupstr(const char *str) 97dupstr(const char *str)
98{ 98{
99 char *ret; 99 char *ret;
100 100
101 ret = strdup(str); 101 ret = strdup(str);
102 if (!ret) 102 if (!ret)
103 err(3, "Memory allocation error"); 103 err(3, "Memory allocation error");
104 return (ret); 104 return (ret);
105} 105}
106 106
107 107
108static void 108static __printflike(1, 2) void
109mywarnx(const char *fmt, ...) 109mywarnx(const char *fmt, ...)
110{ 110{
111 va_list args; 111 va_list args;
112 112
113 va_start(args, fmt); 113 va_start(args, fmt);
114 if (errprefix) { 114 if (errprefix) {
115 /* warn to stdout, with errprefix prepended */ 115 /* warn to stdout, with errprefix prepended */
116 printf("%s", errprefix); 116 printf("%s", errprefix);
117 vprintf(fmt, args); 117 vprintf(fmt, args);
118 printf("%s", "\n"); 118 printf("%s", "\n");
119 } else { 119 } else {
120 /* warn to stderr */ 120 /* warn to stderr */
121 vwarnx(fmt, args); 121 vwarnx(fmt, args);
122 } 122 }
123 va_end(args); 123 va_end(args);
124} 124}
125 125
126static void 126static void
127readerror(int linenum) 127readerror(int linenum)
128{ 128{
129 mywarnx("Error in units file '%s' line %d", UNITSFILE, linenum); 129 mywarnx("Error in units file '%s' line %d", UNITSFILE, linenum);
130} 130}
131 131
132 132
133static void 133static void
134readunits(const char *userfile) 134readunits(const char *userfile)
135{ 135{
136 FILE *unitfile; 136 FILE *unitfile;
137 char line[80], *lineptr; 137 char line[80], *lineptr;
138 int len, linenum, i, isdup; 138 int len, linenum, i, isdup;
139 139
140 unitcount = 0; 140 unitcount = 0;
141 linenum = 0; 141 linenum = 0;
142 142
143 if (userfile) { 143 if (userfile) {
144 unitfile = fopen(userfile, "rt"); 144 unitfile = fopen(userfile, "rt");
145 if (!unitfile) 145 if (!unitfile)
146 err(1, "Unable to open units file '%s'", userfile); 146 err(1, "Unable to open units file '%s'", userfile);
147 } 147 }
148 else { 148 else {
149 unitfile = fopen(UNITSFILE, "rt"); 149 unitfile = fopen(UNITSFILE, "rt");
150 if (!unitfile) { 150 if (!unitfile) {
151 char *direc, *env; 151 char *direc, *env;
152 char filename[1000]; 152 char filename[1000];
153 char separator[2]; 153 char separator[2];
154 154
155 env = getenv("PATH"); 155 env = getenv("PATH");
156 if (env) { 156 if (env) {
157 if (strchr(env, ';')) 157 if (strchr(env, ';'))
158 strlcpy(separator, ";", 158 strlcpy(separator, ";",
159 sizeof(separator)); 159 sizeof(separator));
160 else 160 else
161 strlcpy(separator, ":", 161 strlcpy(separator, ":",
162 sizeof(separator)); 162 sizeof(separator));
163 direc = strtok(env, separator); 163 direc = strtok(env, separator);
164 while (direc) { 164 while (direc) {
165 strlcpy(filename, "", sizeof(filename)); 165 strlcpy(filename, "", sizeof(filename));
166 strlcat(filename, direc, 166 strlcat(filename, direc,
167 sizeof(filename)); 167 sizeof(filename));
168 strlcat(filename, "/", 168 strlcat(filename, "/",
169 sizeof(filename)); 169 sizeof(filename));
170 strlcat(filename, UNITSFILE, 170 strlcat(filename, UNITSFILE,
171 sizeof(filename)); 171 sizeof(filename));
172 unitfile = fopen(filename, "rt"); 172 unitfile = fopen(filename, "rt");
173 if (unitfile) 173 if (unitfile)
174 break; 174 break;
175 direc = strtok(NULL, separator); 175 direc = strtok(NULL, separator);
176 } 176 }
177 } 177 }
178 if (!unitfile) 178 if (!unitfile)
179 errx(1, "Can't find units file '%s'", 179 errx(1, "Can't find units file '%s'",
180 UNITSFILE); 180 UNITSFILE);
181 } 181 }
182 } 182 }
183 while (!feof(unitfile)) { 183 while (!feof(unitfile)) {
184 if (!fgets(line, 79, unitfile)) 184 if (!fgets(line, 79, unitfile))
185 break; 185 break;
186 linenum++; 186 linenum++;
187 lineptr = line; 187 lineptr = line;
188 if (*lineptr == '/') 188 if (*lineptr == '/')
189 continue; 189 continue;
190 lineptr += strspn(lineptr, " \n\t"); 190 lineptr += strspn(lineptr, " \n\t");
191 len = strcspn(lineptr, " \n\t"); 191 len = strcspn(lineptr, " \n\t");
192 lineptr[len] = 0; 192 lineptr[len] = 0;
193 if (!strlen(lineptr)) 193 if (!strlen(lineptr))
194 continue; 194 continue;
195 if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */ 195 if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */
196 if (prefixcount == MAXPREFIXES) { 196 if (prefixcount == MAXPREFIXES) {
197 mywarnx( 197 mywarnx(
198 "Memory for prefixes exceeded in line %d", 198 "Memory for prefixes exceeded in line %d",
199 linenum); 199 linenum);
200 continue; 200 continue;
201 } 201 }
202 lineptr[strlen(lineptr) - 1] = 0; 202 lineptr[strlen(lineptr) - 1] = 0;
203 for (isdup = 0, i = 0; i < prefixcount; i++) { 203 for (isdup = 0, i = 0; i < prefixcount; i++) {
204 if (!strcmp(prefixtable[i].prefixname, 204 if (!strcmp(prefixtable[i].prefixname,
205 lineptr)) { 205 lineptr)) {
206 isdup = 1; 206 isdup = 1;
207 break; 207 break;
208 } 208 }
209 } 209 }
210 if (isdup) { 210 if (isdup) {
211 mywarnx( 211 mywarnx(
212 "Redefinition of prefix '%s' on line %d ignored", 212 "Redefinition of prefix '%s' on line %d ignored",
213 lineptr, linenum); 213 lineptr, linenum);
214 continue; 214 continue;
215 } 215 }
216 prefixtable[prefixcount].prefixname = dupstr(lineptr); 216 prefixtable[prefixcount].prefixname = dupstr(lineptr);
217 lineptr += len + 1; 217 lineptr += len + 1;
218 if (!strlen(lineptr)) { 218 if (!strlen(lineptr)) {
219 readerror(linenum); 219 readerror(linenum);
220 continue; 220 continue;
221 } 221 }
222 lineptr += strspn(lineptr, " \n\t"); 222 lineptr += strspn(lineptr, " \n\t");
223 len = strcspn(lineptr, "\n\t"); 223 len = strcspn(lineptr, "\n\t");
224 lineptr[len] = 0; 224 lineptr[len] = 0;
225 prefixtable[prefixcount++].prefixval = dupstr(lineptr); 225 prefixtable[prefixcount++].prefixval = dupstr(lineptr);
226 } 226 }
227 else { /* it's not a prefix */ 227 else { /* it's not a prefix */
228 if (unitcount == MAXUNITS) { 228 if (unitcount == MAXUNITS) {
229 mywarnx("Memory for units exceeded in line %d", 229 mywarnx("Memory for units exceeded in line %d",
230 linenum); 230 linenum);
231 continue; 231 continue;
232 } 232 }
233 for (isdup = 0, i = 0; i < unitcount; i++) { 233 for (isdup = 0, i = 0; i < unitcount; i++) {
234 if (!strcmp(unittable[i].uname, lineptr)) { 234 if (!strcmp(unittable[i].uname, lineptr)) {
235 isdup = 1; 235 isdup = 1;
236 break; 236 break;
237 } 237 }
238 } 238 }
239 if (isdup) { 239 if (isdup) {
240 mywarnx( 240 mywarnx(
241 "Redefinition of unit '%s' on line %d ignored", 241 "Redefinition of unit '%s' on line %d ignored",
242 lineptr, linenum); 242 lineptr, linenum);
243 continue; 243 continue;
244 } 244 }
245 unittable[unitcount].uname = dupstr(lineptr); 245 unittable[unitcount].uname = dupstr(lineptr);
246 lineptr += len + 1; 246 lineptr += len + 1;
247 lineptr += strspn(lineptr, " \n\t"); 247 lineptr += strspn(lineptr, " \n\t");
248 if (!strlen(lineptr)) { 248 if (!strlen(lineptr)) {
249 readerror(linenum); 249 readerror(linenum);
250 continue; 250 continue;
251 } 251 }
252 len = strcspn(lineptr, "\n\t"); 252 len = strcspn(lineptr, "\n\t");
253 lineptr[len] = 0; 253 lineptr[len] = 0;
254 unittable[unitcount++].uval = dupstr(lineptr); 254 unittable[unitcount++].uval = dupstr(lineptr);
255 } 255 }
256 } 256 }
257 fclose(unitfile); 257 fclose(unitfile);
258} 258}
259 259
260static void 260static void
261initializeunit(struct unittype * theunit) 261initializeunit(struct unittype * theunit)
262{ 262{
263 theunit->factor = 1.0; 263 theunit->factor = 1.0;
264 theunit->numerator[0] = theunit->denominator[0] = NULL; 264 theunit->numerator[0] = theunit->denominator[0] = NULL;
265} 265}
266 266
267static int 267static int
268addsubunit(const char *product[], const char *toadd) 268addsubunit(const char *product[], const char *toadd)
269{ 269{
270 const char **ptr; 270 const char **ptr;
271 271
272 for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++); 272 for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++);
273 if (ptr >= product + MAXSUBUNITS) { 273 if (ptr >= product + MAXSUBUNITS) {
274 mywarnx("Memory overflow in unit reduction"); 274 mywarnx("Memory overflow in unit reduction");
275 return 1; 275 return 1;
276 } 276 }
277 if (!*ptr) 277 if (!*ptr)
278 *(ptr + 1) = 0; 278 *(ptr + 1) = 0;
279 *ptr = dupstr(toadd); 279 *ptr = dupstr(toadd);
280 return 0; 280 return 0;
281} 281}
282 282
283static void 283static void
284showunit(struct unittype * theunit) 284showunit(struct unittype * theunit)
285{ 285{
286 const char **ptr; 286 const char **ptr;
287 int printedslash; 287 int printedslash;
288 int counter = 1; 288 int counter = 1;
289 289
290 printf("\t%.*g", precision, theunit->factor); 290 printf("\t%.*g", precision, theunit->factor);
291 for (ptr = theunit->numerator; *ptr; ptr++) { 291 for (ptr = theunit->numerator; *ptr; ptr++) {
292 if (ptr > theunit->numerator && **ptr && 292 if (ptr > theunit->numerator && **ptr &&
293 !strcmp(*ptr, *(ptr - 1))) 293 !strcmp(*ptr, *(ptr - 1)))
294 counter++; 294 counter++;
295 else { 295 else {
296 if (counter > 1) 296 if (counter > 1)
297 printf("%s%d", powerstring, counter); 297 printf("%s%d", powerstring, counter);
298 if (**ptr) 298 if (**ptr)
299 printf(" %s", *ptr); 299 printf(" %s", *ptr);
300 counter = 1; 300 counter = 1;
301 } 301 }
302 } 302 }
303 if (counter > 1) 303 if (counter > 1)
304 printf("%s%d", powerstring, counter); 304 printf("%s%d", powerstring, counter);
305 counter = 1; 305 counter = 1;
306 printedslash = 0; 306 printedslash = 0;
307 for (ptr = theunit->denominator; *ptr; ptr++) { 307 for (ptr = theunit->denominator; *ptr; ptr++) {
308 if (ptr > theunit->denominator && **ptr && 308 if (ptr > theunit->denominator && **ptr &&
309 !strcmp(*ptr, *(ptr - 1))) 309 !strcmp(*ptr, *(ptr - 1)))
310 counter++; 310 counter++;
311 else { 311 else {
312 if (counter > 1) 312 if (counter > 1)
313 printf("%s%d", powerstring, counter); 313 printf("%s%d", powerstring, counter);
314 if (**ptr) { 314 if (**ptr) {
315 if (!printedslash) 315 if (!printedslash)
316 printf(" /"); 316 printf(" /");
317 printedslash = 1; 317 printedslash = 1;
318 printf(" %s", *ptr); 318 printf(" %s", *ptr);
319 } 319 }
320 counter = 1; 320 counter = 1;
321 } 321 }
322 } 322 }
323 if (counter > 1) 323 if (counter > 1)
324 printf("%s%d", powerstring, counter); 324 printf("%s%d", powerstring, counter);
325 printf("\n"); 325 printf("\n");
326} 326}
327 327
328static void 328static void
329zeroerror(void) 329zeroerror(void)
330{ 330{
331 mywarnx("Unit reduces to zero"); 331 mywarnx("Unit reduces to zero");
332} 332}
333 333
334/* 334/*
335 Adds the specified string to the unit. 335 Adds the specified string to the unit.
336 Flip is 0 for adding normally, 1 for adding reciprocal. 336 Flip is 0 for adding normally, 1 for adding reciprocal.
337 337
338 Returns 0 for successful addition, nonzero on error. 338 Returns 0 for successful addition, nonzero on error.
339*/ 339*/
340 340
341static int 341static int
342addunit(struct unittype * theunit, const char *toadd, int flip) 342addunit(struct unittype * theunit, const char *toadd, int flip)
343{ 343{
344 char *scratch, *savescr; 344 char *scratch, *savescr;
345 char *item; 345 char *item;
346 char *divider, *slash; 346 char *divider, *slash;
347 int doingtop; 347 int doingtop;
348 348
349 savescr = scratch = dupstr(toadd); 349 savescr = scratch = dupstr(toadd);
350 for (slash = scratch + 1; *slash; slash++) 350 for (slash = scratch + 1; *slash; slash++)
351 if (*slash == '-' && 351 if (*slash == '-' &&
352 (tolower((unsigned char)*(slash - 1)) != 'e' || 352 (tolower((unsigned char)*(slash - 1)) != 'e' ||
353 !strchr(".0123456789", *(slash + 1)))) 353 !strchr(".0123456789", *(slash + 1))))
354 *slash = ' '; 354 *slash = ' ';
355 slash = strchr(scratch, '/'); 355 slash = strchr(scratch, '/');
356 if (slash) 356 if (slash)
357 *slash = 0; 357 *slash = 0;
358 doingtop = 1; 358 doingtop = 1;
359 do { 359 do {
360 item = strtok(scratch, " *\t\n/"); 360 item = strtok(scratch, " *\t\n/");
361 while (item) { 361 while (item) {
362 if (strchr("0123456789.", *item)) { 362 if (strchr("0123456789.", *item)) {
363 /* item starts with a number */ 363 /* item starts with a number */
364 char *endptr; 364 char *endptr;
365 double num; 365 double num;
366 366
367 divider = strchr(item, '|'); 367 divider = strchr(item, '|');
368 if (divider) { 368 if (divider) {
369 *divider = 0; 369 *divider = 0;
370 num = strtod(item, &endptr); 370 num = strtod(item, &endptr);
371 if (!num) { 371 if (!num) {
372 zeroerror(); 372 zeroerror();
373 return 1; 373 return 1;
374 } 374 }
375 if (endptr != divider) { 375 if (endptr != divider) {
376 /* "6foo|2" is an error */ 376 /* "6foo|2" is an error */
377 mywarnx("Junk before '|'"); 377 mywarnx("Junk before '|'");
378 return 1; 378 return 1;
379 } 379 }
380 if (doingtop ^ flip) 380 if (doingtop ^ flip)
381 theunit->factor *= num; 381 theunit->factor *= num;
382 else 382 else
383 theunit->factor /= num; 383 theunit->factor /= num;
384 num = strtod(divider + 1, &endptr); 384 num = strtod(divider + 1, &endptr);
385 if (!num) { 385 if (!num) {
386 zeroerror(); 386 zeroerror();
387 return 1; 387 return 1;
388 } 388 }
389 if (doingtop ^ flip) 389 if (doingtop ^ flip)
390 theunit->factor /= num; 390 theunit->factor /= num;
391 else 391 else
392 theunit->factor *= num; 392 theunit->factor *= num;
393 if (*endptr) { 393 if (*endptr) {
394 /* "6|2foo" is like "6|2 foo" */ 394 /* "6|2foo" is like "6|2 foo" */
395 item = endptr; 395 item = endptr;
396 continue; 396 continue;
397 } 397 }
398 } 398 }
399 else { 399 else {
400 num = strtod(item, &endptr); 400 num = strtod(item, &endptr);
401 if (!num) { 401 if (!num) {
402 zeroerror(); 402 zeroerror();
403 return 1; 403 return 1;
404 } 404 }
405 if (doingtop ^ flip) 405 if (doingtop ^ flip)
406 theunit->factor *= num; 406 theunit->factor *= num;
407 else 407 else
408 theunit->factor /= num; 408 theunit->factor /= num;
409 if (*endptr) { 409 if (*endptr) {
410 /* "3foo" is like "3 foo" */ 410 /* "3foo" is like "3 foo" */
411 item = endptr; 411 item = endptr;
412 continue; 412 continue;
413 } 413 }
414 } 414 }
415 } 415 }
416 else { /* item is not a number */ 416 else { /* item is not a number */
417 int repeat = 1; 417 int repeat = 1;
418 418
419 if (strchr("23456789", 419 if (strchr("23456789",
420 item[strlen(item) - 1])) { 420 item[strlen(item) - 1])) {
421 repeat = item[strlen(item) - 1] - '0'; 421 repeat = item[strlen(item) - 1] - '0';
422 item[strlen(item) - 1] = 0; 422 item[strlen(item) - 1] = 0;
423 } 423 }
424 for (; repeat; repeat--) 424 for (; repeat; repeat--)
425 if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item)) 425 if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item))
426 return 1; 426 return 1;
427 } 427 }
428 item = strtok(NULL, " *\t/\n"); 428 item = strtok(NULL, " *\t/\n");
429 } 429 }
430 doingtop--; 430 doingtop--;
431 if (slash) { 431 if (slash) {
432 scratch = slash + 1; 432 scratch = slash + 1;
433 } 433 }
434 else 434 else
435 doingtop--; 435 doingtop--;
436 } while (doingtop >= 0); 436 } while (doingtop >= 0);
437 free(savescr); 437 free(savescr);
438 return 0; 438 return 0;
439} 439}
440 440
441static int 441static int
442compare(const void *item1, const void *item2) 442compare(const void *item1, const void *item2)
443{ 443{
444 return strcmp(*(const char * const *) item1, 444 return strcmp(*(const char * const *) item1,
445 *(const char * const *) item2); 445 *(const char * const *) item2);
446} 446}
447 447
448static void 448static void
449sortunit(struct unittype * theunit) 449sortunit(struct unittype * theunit)
450{ 450{
451 const char **ptr; 451 const char **ptr;
452 int count; 452 int count;
453 453
454 for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++); 454 for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++);
455 qsort(theunit->numerator, count, sizeof(char *), compare); 455 qsort(theunit->numerator, count, sizeof(char *), compare);
456 for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++); 456 for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++);
457 qsort(theunit->denominator, count, sizeof(char *), compare); 457 qsort(theunit->denominator, count, sizeof(char *), compare);
458} 458}
459 459
460static void 460static void
461cancelunit(struct unittype * theunit) 461cancelunit(struct unittype * theunit)
462{ 462{
463 const char **den, **num; 463 const char **den, **num;
464 int comp; 464 int comp;
465 465
466 den = theunit->denominator; 466 den = theunit->denominator;
467 num = theunit->numerator; 467 num = theunit->numerator;
468 468
469 while (*num && *den) { 469 while (*num && *den) {
470 comp = strcmp(*den, *num); 470 comp = strcmp(*den, *num);
471 if (!comp) { 471 if (!comp) {
472/* if (*den!=NULLUNIT) free(*den); 472/* if (*den!=NULLUNIT) free(*den);
473 if (*num!=NULLUNIT) free(*num);*/ 473 if (*num!=NULLUNIT) free(*num);*/
474 *den++ = NULLUNIT; 474 *den++ = NULLUNIT;
475 *num++ = NULLUNIT; 475 *num++ = NULLUNIT;
476 } 476 }
477 else if (comp < 0) 477 else if (comp < 0)
478 den++; 478 den++;
479 else 479 else
480 num++; 480 num++;
481 } 481 }
482} 482}
483 483
484 484
485 485
486 486
487/* 487/*
488 Looks up the definition for the specified unit. 488 Looks up the definition for the specified unit.
489 Returns a pointer to the definition or a null pointer 489 Returns a pointer to the definition or a null pointer
490 if the specified unit does not appear in the units table. 490 if the specified unit does not appear in the units table.
491*/ 491*/
492 492
493static char buffer[100]; /* buffer for lookupunit answers with 493static char buffer[100]; /* buffer for lookupunit answers with
494 prefixes */ 494 prefixes */
495 495
496static const char * 496static const char *
497lookupunit(const char *unit) 497lookupunit(const char *unit)
498{ 498{
499 int i; 499 int i;
500 char *copy; 500 char *copy;
501 501
502 for (i = 0; i < unitcount; i++) { 502 for (i = 0; i < unitcount; i++) {
503 if (!strcmp(unittable[i].uname, unit)) 503 if (!strcmp(unittable[i].uname, unit))
504 return unittable[i].uval; 504 return unittable[i].uval;
505 } 505 }
506 506
507 if (unit[strlen(unit) - 1] == '^') { 507 if (unit[strlen(unit) - 1] == '^') {
508 copy = dupstr(unit); 508 copy = dupstr(unit);
509 copy[strlen(copy) - 1] = 0; 509 copy[strlen(copy) - 1] = 0;
510 for (i = 0; i < unitcount; i++) { 510 for (i = 0; i < unitcount; i++) {
511 if (!strcmp(unittable[i].uname, copy)) { 511 if (!strcmp(unittable[i].uname, copy)) {
512 strlcpy(buffer, copy, sizeof(buffer)); 512 strlcpy(buffer, copy, sizeof(buffer));
513 free(copy); 513 free(copy);
514 return buffer; 514 return buffer;
515 } 515 }
516 } 516 }
517 free(copy); 517 free(copy);
518 } 518 }
519 if (unit[strlen(unit) - 1] == 's') { 519 if (unit[strlen(unit) - 1] == 's') {
520 copy = dupstr(unit); 520 copy = dupstr(unit);
521 copy[strlen(copy) - 1] = 0; 521 copy[strlen(copy) - 1] = 0;
522 for (i = 0; i < unitcount; i++) { 522 for (i = 0; i < unitcount; i++) {
523 if (!strcmp(unittable[i].uname, copy)) { 523 if (!strcmp(unittable[i].uname, copy)) {
524 strlcpy(buffer, copy, sizeof(buffer)); 524 strlcpy(buffer, copy, sizeof(buffer));
525 free(copy); 525 free(copy);
526 return buffer; 526 return buffer;
527 } 527 }
528 } 528 }
529 if (copy[strlen(copy) - 1] == 'e') { 529 if (copy[strlen(copy) - 1] == 'e') {
530 copy[strlen(copy) - 1] = 0; 530 copy[strlen(copy) - 1] = 0;
531 for (i = 0; i < unitcount; i++) { 531 for (i = 0; i < unitcount; i++) {
532 if (!strcmp(unittable[i].uname, copy)) { 532 if (!strcmp(unittable[i].uname, copy)) {
533 strlcpy(buffer, copy, sizeof(buffer)); 533 strlcpy(buffer, copy, sizeof(buffer));
534 free(copy); 534 free(copy);
535 return buffer; 535 return buffer;
536 } 536 }
537 } 537 }
538 } 538 }
539 free(copy); 539 free(copy);
540 } 540 }
541 for (i = 0; i < prefixcount; i++) { 541 for (i = 0; i < prefixcount; i++) {
542 if (!strncmp(prefixtable[i].prefixname, unit, 542 if (!strncmp(prefixtable[i].prefixname, unit,
543 strlen(prefixtable[i].prefixname))) { 543 strlen(prefixtable[i].prefixname))) {
544 unit += strlen(prefixtable[i].prefixname); 544 unit += strlen(prefixtable[i].prefixname);
545 if (!strlen(unit) || lookupunit(unit)) { 545 if (!strlen(unit) || lookupunit(unit)) {
546 strlcpy(buffer, prefixtable[i].prefixval, 546 strlcpy(buffer, prefixtable[i].prefixval,
547 sizeof(buffer)); 547 sizeof(buffer));
548 strlcat(buffer, " ", sizeof(buffer)); 548 strlcat(buffer, " ", sizeof(buffer));
549 strlcat(buffer, unit, sizeof(buffer)); 549 strlcat(buffer, unit, sizeof(buffer));
550 return buffer; 550 return buffer;
551 } 551 }
552 } 552 }
553 } 553 }
554 return 0; 554 return 0;
555} 555}
556 556
557 557
558 558
559/* 559/*
560 reduces a product of symbolic units to primitive units. 560 reduces a product of symbolic units to primitive units.
561 The three low bits are used to return flags: 561 The three low bits are used to return flags:
562 562
563 bit 0 (1) set on if reductions were performed without error. 563 bit 0 (1) set on if reductions were performed without error.
564 bit 1 (2) set on if no reductions are performed. 564 bit 1 (2) set on if no reductions are performed.
565 bit 2 (4) set on if an unknown unit is discovered. 565 bit 2 (4) set on if an unknown unit is discovered.
566*/ 566*/
567 567
568 568
569#define ERROR 4 569#define ERROR 4
570 570
571static int 571static int
572reduceproduct(struct unittype * theunit, int flip) 572reduceproduct(struct unittype * theunit, int flip)
573{ 573{
574 574
575 const char *toadd; 575 const char *toadd;
576 const char **product; 576 const char **product;
577 int didsomething = 2; 577 int didsomething = 2;
578 578
579 if (flip) 579 if (flip)
580 product = theunit->denominator; 580 product = theunit->denominator;
581 else 581 else
582 product = theunit->numerator; 582 product = theunit->numerator;
583 583
584 for (; *product; product++) { 584 for (; *product; product++) {
585 585
586 for (;;) { 586 for (;;) {
587 if (!strlen(*product)) 587 if (!strlen(*product))
588 break; 588 break;
589 toadd = lookupunit(*product); 589 toadd = lookupunit(*product);
590 if (!toadd) { 590 if (!toadd) {
591 mywarnx("Unknown unit '%s'", *product); 591 mywarnx("Unknown unit '%s'", *product);
592 return ERROR; 592 return ERROR;
593 } 593 }
594 if (strchr(toadd, PRIMITIVECHAR)) 594 if (strchr(toadd, PRIMITIVECHAR))
595 break; 595 break;
596 didsomething = 1; 596 didsomething = 1;
597 if (*product != NULLUNIT) { 597 if (*product != NULLUNIT) {
598 free(__UNCONST(*product)); 598 free(__UNCONST(*product));
599 *product = NULLUNIT; 599 *product = NULLUNIT;
600 } 600 }
601 if (addunit(theunit, toadd, flip)) 601 if (addunit(theunit, toadd, flip))
602 return ERROR; 602 return ERROR;
603 } 603 }
604 } 604 }
605 return didsomething; 605 return didsomething;
606} 606}
607 607
608 608
609/* 609/*
610 Reduces numerator and denominator of the specified unit. 610 Reduces numerator and denominator of the specified unit.
611 Returns 0 on success, or 1 on unknown unit error. 611 Returns 0 on success, or 1 on unknown unit error.
612*/ 612*/
613 613
614static int 614static int
615reduceunit(struct unittype * theunit) 615reduceunit(struct unittype * theunit)
616{ 616{
617 int ret; 617 int ret;
618 618
619 ret = 1; 619 ret = 1;
620 while (ret & 1) { 620 while (ret & 1) {
621 ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1); 621 ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1);
622 if (ret & 4) 622 if (ret & 4)
623 return 1; 623 return 1;
624 } 624 }
625 return 0; 625 return 0;
626} 626}
627 627
628static int 628static int
629compareproducts(const char **one, const char **two) 629compareproducts(const char **one, const char **two)
630{ 630{
631 while (*one || *two) { 631 while (*one || *two) {
632 if (!*one && *two != NULLUNIT) 632 if (!*one && *two != NULLUNIT)
633 return 1; 633 return 1;
634 if (!*two && *one != NULLUNIT) 634 if (!*two && *one != NULLUNIT)
635 return 1; 635 return 1;
636 if (*one == NULLUNIT) 636 if (*one == NULLUNIT)
637 one++; 637 one++;
638 else if (*two == NULLUNIT) 638 else if (*two == NULLUNIT)
639 two++; 639 two++;
640 else if (*one && *two && strcmp(*one, *two)) 640 else if (*one && *two && strcmp(*one, *two))
641 return 1; 641 return 1;
642 else 642 else
643 one++, two++; 643 one++, two++;
644 } 644 }
645 return 0; 645 return 0;
646} 646}
647 647
648 648
649/* Return zero if units are compatible, nonzero otherwise */ 649/* Return zero if units are compatible, nonzero otherwise */
650 650
651static int 651static int
652compareunits(struct unittype * first, struct unittype * second) 652compareunits(struct unittype * first, struct unittype * second)
653{ 653{
654 return 654 return
655 compareproducts(first->numerator, second->numerator) || 655 compareproducts(first->numerator, second->numerator) ||
656 compareproducts(first->denominator, second->denominator); 656 compareproducts(first->denominator, second->denominator);
657} 657}
658 658
659static int 659static int
660compareunitsreciprocal(struct unittype * first, struct unittype * second) 660compareunitsreciprocal(struct unittype * first, struct unittype * second)
661{ 661{
662 return 662 return
663 compareproducts(first->numerator, second->denominator) || 663 compareproducts(first->numerator, second->denominator) ||
664 compareproducts(first->denominator, second->numerator); 664 compareproducts(first->denominator, second->numerator);
665} 665}
666 666
667 667
668static int 668static int
669completereduce(struct unittype * unit) 669completereduce(struct unittype * unit)
670{ 670{
671 if (reduceunit(unit)) 671 if (reduceunit(unit))
672 return 1; 672 return 1;
673 sortunit(unit); 673 sortunit(unit);
674 cancelunit(unit); 674 cancelunit(unit);
675 return 0; 675 return 0;
676} 676}
677 677
678 678
679static void 679static void
680showanswer(struct unittype * have, struct unittype * want) 680showanswer(struct unittype * have, struct unittype * want)
681{ 681{
682 if (compareunits(have, want)) { 682 if (compareunits(have, want)) {
683 if (compareunitsreciprocal(have, want)) { 683 if (compareunitsreciprocal(have, want)) {
684 printf("conformability error\n"); 684 printf("conformability error\n");
685 showunit(have); 685 showunit(have);
686 showunit(want); 686 showunit(want);
687 } else { 687 } else {
688 printf("\treciprocal conversion\n"); 688 printf("\treciprocal conversion\n");
689 printf("\t* %.*g\n\t/ %.*g\n", 689 printf("\t* %.*g\n\t/ %.*g\n",
690 precision, 1 / (have->factor * want->factor), 690 precision, 1 / (have->factor * want->factor),
691 precision, want->factor * have->factor); 691 precision, want->factor * have->factor);
692 } 692 }
693 } 693 }
694 else 694 else
695 printf("\t* %.*g\n\t/ %.*g\n", 695 printf("\t* %.*g\n\t/ %.*g\n",
696 precision, have->factor / want->factor, 696 precision, have->factor / want->factor,
697 precision, want->factor / have->factor); 697 precision, want->factor / have->factor);
698} 698}
699 699
700static int 700static int
701listunits(int expand) 701listunits(int expand)
702{ 702{
703 struct unittype theunit; 703 struct unittype theunit;
704 const char *thename; 704 const char *thename;
705 const char *thedefn; 705 const char *thedefn;
706 int errors = 0; 706 int errors = 0;
707 int i; 707 int i;
708 int printexpansion; 708 int printexpansion;
709 709
710 /* 710 /*
711 * send error and warning messages to stdout, 711 * send error and warning messages to stdout,
712 * and make them look like comments. 712 * and make them look like comments.
713 */ 713 */
714 errprefix = "/ "; 714 errprefix = "/ ";
715 715
716#if 0 /* debug */ 716#if 0 /* debug */
717 printf("/ expand=%d precision=%d unitcount=%d prefixcount=%d\n", 717 printf("/ expand=%d precision=%d unitcount=%d prefixcount=%d\n",
718 expand, precision, unitcount, prefixcount); 718 expand, precision, unitcount, prefixcount);
719#endif 719#endif
720 720
721 /* 1. Dump all primitive units, e.g. "m !a!", "kg !b!", ... */ 721 /* 1. Dump all primitive units, e.g. "m !a!", "kg !b!", ... */
722 printf("/ Primitive units\n"); 722 printf("/ Primitive units\n");
723 for (i = 0; i < unitcount; i++) { 723 for (i = 0; i < unitcount; i++) {
724 thename = unittable[i].uname; 724 thename = unittable[i].uname;
725 thedefn = unittable[i].uval; 725 thedefn = unittable[i].uval;
726 if (thedefn[0] == PRIMITIVECHAR) { 726 if (thedefn[0] == PRIMITIVECHAR) {
727 printf("%s\t%s\n", thename, thedefn); 727 printf("%s\t%s\n", thename, thedefn);
728 } 728 }
729 } 729 }
730 730
731 /* 2. Dump all prefixes, e.g. "yotta- 1e24", "zetta- 1e21", ... */ 731 /* 2. Dump all prefixes, e.g. "yotta- 1e24", "zetta- 1e21", ... */
732 printf("/ Prefixes\n"); 732 printf("/ Prefixes\n");
733 for (i = 0; i < prefixcount; i++) { 733 for (i = 0; i < prefixcount; i++) {
734 printexpansion = expand; 734 printexpansion = expand;
735 thename = prefixtable[i].prefixname; 735 thename = prefixtable[i].prefixname;
736 thedefn = prefixtable[i].prefixval; 736 thedefn = prefixtable[i].prefixval;
737 if (expand) { 737 if (expand) {
738 /* 738 /*
739 * prefix names are sometimes identical to unit 739 * prefix names are sometimes identical to unit
740 * names, so we have to expand thedefn instead of 740 * names, so we have to expand thedefn instead of
741 * expanding thename. 741 * expanding thename.
742 */ 742 */
743 initializeunit(&theunit); 743 initializeunit(&theunit);
744 if (addunit(&theunit, thedefn, 0) != 0 744 if (addunit(&theunit, thedefn, 0) != 0
745 || completereduce(&theunit) != 0) { 745 || completereduce(&theunit) != 0) {
746 errors++; 746 errors++;
747 printexpansion = 0; 747 printexpansion = 0;
748 mywarnx("Error in prefix '%s-'", thename); 748 mywarnx("Error in prefix '%s-'", thename);
749 } 749 }
750 } 750 }
751 if (printexpansion) { 751 if (printexpansion) {
752 printf("%s-", thename); 752 printf("%s-", thename);
753 showunit(&theunit); 753 showunit(&theunit);
754 } else 754 } else
755 printf("%s-\t%s\n", thename, thedefn); 755 printf("%s-\t%s\n", thename, thedefn);
756 } 756 }
757 757
758 /* 3. Dump all other units. */ 758 /* 3. Dump all other units. */
759 printf("/ Other units\n"); 759 printf("/ Other units\n");
760 for (i = 0; i < unitcount; i++) { 760 for (i = 0; i < unitcount; i++) {
761 printexpansion = expand; 761 printexpansion = expand;
762 thename = unittable[i].uname; 762 thename = unittable[i].uname;
763 thedefn = unittable[i].uval; 763 thedefn = unittable[i].uval;
764 if (thedefn[0] == PRIMITIVECHAR) 764 if (thedefn[0] == PRIMITIVECHAR)
765 continue; 765 continue;
766 if (expand) { 766 if (expand) {
767 /* 767 /*
768 * expand thename, not thedefn, so that 768 * expand thename, not thedefn, so that
769 * we can catch errors in the name itself. 769 * we can catch errors in the name itself.
770 * e.g. a name that contains a hyphen 770 * e.g. a name that contains a hyphen
771 * will be interpreted as multiplication. 771 * will be interpreted as multiplication.
772 */ 772 */
773 initializeunit(&theunit); 773 initializeunit(&theunit);
774 if (addunit(&theunit, thename, 0) != 0 774 if (addunit(&theunit, thename, 0) != 0
775 || completereduce(&theunit) != 0) { 775 || completereduce(&theunit) != 0) {
776 errors++; 776 errors++;
777 printexpansion = 0; 777 printexpansion = 0;
778 mywarnx("Error in unit '%s'", thename); 778 mywarnx("Error in unit '%s'", thename);
779 } 779 }
780 } 780 }
781 if (printexpansion) { 781 if (printexpansion) {
782 printf("%s", thename); 782 printf("%s", thename);
783 showunit(&theunit); 783 showunit(&theunit);
784 } else 784 } else
785 printf("%s\t%s\n", thename, thedefn); 785 printf("%s\t%s\n", thename, thedefn);
786 } 786 }
787 787
788 if (errors) 788 if (errors)
789 mywarnx("Definitions with errors: %d", errors); 789 mywarnx("Definitions with errors: %d", errors);
790 return (errors ? 1 : 0); 790 return (errors ? 1 : 0);
791} 791}
792 792
793static void 793static void
794usage(void) 794usage(void)
795{ 795{
796 fprintf(stderr, 796 fprintf(stderr,
797 "\nunits [-Llqv] [-f filename] [[count] from-unit to-unit]\n"); 797 "\nunits [-Llqv] [-f filename] [[count] from-unit to-unit]\n");
798 fprintf(stderr, "\n -f specify units file\n"); 798 fprintf(stderr, "\n -f specify units file\n");
799 fprintf(stderr, " -L list units in standardized base units\n"); 799 fprintf(stderr, " -L list units in standardized base units\n");
800 fprintf(stderr, " -l list units\n"); 800 fprintf(stderr, " -l list units\n");
801 fprintf(stderr, " -q suppress prompting (quiet)\n"); 801 fprintf(stderr, " -q suppress prompting (quiet)\n");
802 fprintf(stderr, " -v print version number\n"); 802 fprintf(stderr, " -v print version number\n");
803 exit(3); 803 exit(3);
804} 804}
805 805
806int 806int
807main(int argc, char **argv) 807main(int argc, char **argv)
808{ 808{
809 809
810 struct unittype have, want; 810 struct unittype have, want;
811 char havestr[81], wantstr[81]; 811 char havestr[81], wantstr[81];
812 int optchar; 812 int optchar;
813 const char *userfile = 0; 813 const char *userfile = 0;
814 int list = 0, listexpand = 0; 814 int list = 0, listexpand = 0;
815 int quiet = 0; 815 int quiet = 0;
816 816
817 while ((optchar = getopt(argc, argv, "lLvqf:")) != -1) { 817 while ((optchar = getopt(argc, argv, "lLvqf:")) != -1) {
818 switch (optchar) { 818 switch (optchar) {
819 case 'l': 819 case 'l':
820 list = 1; 820 list = 1;
821 break; 821 break;
822 case 'L': 822 case 'L':
823 list = 1; 823 list = 1;
824 listexpand = 1; 824 listexpand = 1;
825 precision = DBL_DIG; 825 precision = DBL_DIG;
826 break; 826 break;
827 case 'f': 827 case 'f':
828 userfile = optarg; 828 userfile = optarg;
829 break; 829 break;
830 case 'q': 830 case 'q':
831 quiet = 1; 831 quiet = 1;
832 break; 832 break;
833 case 'v': 833 case 'v':
834 fprintf(stderr, "\n units version %s Copyright (c) 1993 by Adrian Mariano\n", 834 fprintf(stderr, "\n units version %s Copyright (c) 1993 by Adrian Mariano\n",
835 VERSION); 835 VERSION);
836 fprintf(stderr, " This program may be freely distributed\n"); 836 fprintf(stderr, " This program may be freely distributed\n");
837 usage(); 837 usage();
838 default: 838 default:
839 usage(); 839 usage();
840 break; 840 break;
841 } 841 }
842 } 842 }
843 843
844 argc -= optind; 844 argc -= optind;
845 argv += optind; 845 argv += optind;
846 846
847 if ((argc != 3 && argc != 2 && argc != 0) 847 if ((argc != 3 && argc != 2 && argc != 0)
848 || (list && argc != 0)) 848 || (list && argc != 0))
849 usage(); 849 usage();
850 850
851 if (list) 851 if (list)
852 errprefix = "/ "; /* set this before reading the file */ 852 errprefix = "/ "; /* set this before reading the file */
853 853
854 readunits(userfile); 854 readunits(userfile);
855 855
856 if (list) 856 if (list)
857 return listunits(listexpand); 857 return listunits(listexpand);
858 858
859 if (argc == 3) { 859 if (argc == 3) {
860 strlcpy(havestr, argv[0], sizeof(havestr)); 860 strlcpy(havestr, argv[0], sizeof(havestr));
861 strlcat(havestr, " ", sizeof(havestr)); 861 strlcat(havestr, " ", sizeof(havestr));
862 strlcat(havestr, argv[1], sizeof(havestr)); 862 strlcat(havestr, argv[1], sizeof(havestr));
863 argc--; 863 argc--;
864 argv++; 864 argv++;
865 argv[0] = havestr; 865 argv[0] = havestr;
866 } 866 }
867 867
868 if (argc == 2) { 868 if (argc == 2) {
869 strlcpy(havestr, argv[0], sizeof(havestr)); 869 strlcpy(havestr, argv[0], sizeof(havestr));
870 strlcpy(wantstr, argv[1], sizeof(wantstr)); 870 strlcpy(wantstr, argv[1], sizeof(wantstr));
871 initializeunit(&have); 871 initializeunit(&have);
872 addunit(&have, havestr, 0); 872 addunit(&have, havestr, 0);
873 completereduce(&have); 873 completereduce(&have);
874 initializeunit(&want); 874 initializeunit(&want);
875 addunit(&want, wantstr, 0); 875 addunit(&want, wantstr, 0);
876 completereduce(&want); 876 completereduce(&want);
877 showanswer(&have, &want); 877 showanswer(&have, &want);
878 } 878 }
879 else { 879 else {
880 if (!quiet) 880 if (!quiet)
881 printf("%d units, %d prefixes\n\n", unitcount, 881 printf("%d units, %d prefixes\n\n", unitcount,
882 prefixcount); 882 prefixcount);
883 for (;;) { 883 for (;;) {
884 do { 884 do {
885 initializeunit(&have); 885 initializeunit(&have);
886 if (!quiet) 886 if (!quiet)
887 printf("You have: "); 887 printf("You have: ");
888 if (!fgets(havestr, 80, stdin)) { 888 if (!fgets(havestr, 80, stdin)) {
889 if (!quiet) 889 if (!quiet)
890 putchar('\n'); 890 putchar('\n');
891 exit(0); 891 exit(0);
892 } 892 }
893 } while (addunit(&have, havestr, 0) || 893 } while (addunit(&have, havestr, 0) ||
894 completereduce(&have)); 894 completereduce(&have));
895 do { 895 do {
896 initializeunit(&want); 896 initializeunit(&want);
897 if (!quiet) 897 if (!quiet)
898 printf("You want: "); 898 printf("You want: ");
899 if (!fgets(wantstr, 80, stdin)) { 899 if (!fgets(wantstr, 80, stdin)) {
900 if (!quiet) 900 if (!quiet)
901 putchar('\n'); 901 putchar('\n');
902 exit(0); 902 exit(0);
903 } 903 }
904 } while (addunit(&want, wantstr, 0) || 904 } while (addunit(&want, wantstr, 0) ||
905 completereduce(&want)); 905 completereduce(&want));
906 showanswer(&have, &want); 906 showanswer(&have, &want);
907 } 907 }
908 } 908 }
909 return (0); 909 return (0);
910} 910}