|
|
1.1 root 1: static char Copyright[] = "$Copyright: (c) 1985, INETCO Systems, Ltd.$";
2: static char Release[] = "$Release: INETCO COHERENT V8.0$";
3: static char Date[] = "$Date: 91/04/19 12:41:06 $";
4:
5: /* (-lgl
6: * The information contained herein is a trade secret of Mark Williams
7: * Company, and is confidential information. It is provided under a
8: * license agreement, and may be copied or disclosed only under the
9: * terms of that agreement. Any reproduction or disclosure of this
10: * material without the express written authorization of Mark Williams
11: * Company or persuant to the license agreement is unlawful.
12: *
13: * Coherent Version 2.3.38
14: * Copyright (c) 1982, 1983, 1984.
15: * An unpublished work by Mark Williams Company, Chicago.
16: * All rights reserved.
17: -lgl) */
18: /*
19: * units -- do multiplicative unit conversions
20: * td 80.09.04
21: * Modified to keep the intermediate format in a file and
22: * update it automatically when it has changed.
23: * (NOTE: program is setuid to bin)
24: * rec 84.08.13
25: * Changed Waiting for Godot ... to Rebuilding %s from %s.
26: * (Nota Bene:
27: * cc -o units -f units.c
28: * chown bin /bin/units
29: * chmod 4755 /bin/units
30: * )
31: */
32:
33: #include <stdio.h>
34: #include <sys/stat.h>
35:
36: #define NDIM 12
37: #define NUNITS 900
38: #define NBUF 256 /* Length of longest line */
39: #define UMAGIC 0123456 /* Magic number written in binary header */
40:
41: /*
42: * Header for the units file.
43: * This tells that it is the real
44: * thing and how much to read in.
45: */
46: typedef struct HDR {
47: unsigned h_magic;
48: unsigned h_nunits;
49: unsigned h_ssize; /* String space size */
50: } HDR;
51:
52: HDR hdr;
53:
54: typedef struct UNIT {
55: char *u_name;
56: double u_val;
57: char u_dim[NDIM];
58: } UNIT;
59:
60: UNIT *units;
61: struct stat sb;
62: char ufile[] = "/usr/lib/units";
63: char binufile[] = "/usr/lib/binunits";
64: char buf[NBUF];
65: char inbuf[BUFSIZ];
66:
67: int nunits;
68: int uflag; /* Update information only */
69: FILE *fd;
70: int peekc = EOF;
71: int lastc = EOF;
72: int lineno = 1;
73:
74: char *getname();
75: char *prefix();
76: char *alloc();
77:
78: main(argc, argv)
79: int argc;
80: char *argv[];
81: {
82: UNIT have, want;
83: register int i;
84:
85: setbuf(stdout, NULL);
86: setbuf(stderr, NULL);
87: if (argc>1 && *argv[1]=='-') {
88: if (argv[1][1]=='u' && argv[1][2]=='\0')
89: uflag++;
90: else {
91: fprintf(stderr, "Usage: units [-u]\n");
92: exit(1);
93: }
94: }
95: init();
96: setbuf(fd = stdin, inbuf);
97: Again:
98: if (!getunit(&have, "You have: ")
99: || !getunit(&want, "You want: "))
100: exit(0);
101: for (i=0; i!=NDIM; i++)
102: if (have.u_dim[i] != want.u_dim[i]) {
103: printf("Conformability\n");
104: punit(&have);
105: punit(&want);
106: goto Again;
107: }
108: printf("* %g\n/ %g\n", have.u_val/want.u_val, want.u_val/have.u_val);
109: goto Again;
110: }
111:
112: /*
113: * Initialise by reading in units information
114: * either in binary or ascii form and updating
115: * the binary information.
116: */
117: init()
118: {
119: if (!binary())
120: update();
121: printf("%d units\n", nunits);
122: peekc = EOF;
123: if (uflag)
124: exit(0);
125: /*
126: * Throw away super-user information
127: */
128: setuid(getuid());
129: }
130:
131: /*
132: * Attempt to read in the already-stored
133: * binary information. Return non-zero if
134: * successful.
135: */
136: binary()
137: {
138: register char *sstart;
139: register int n;
140: register int bfd;
141: time_t timeasc;
142:
143: if (stat(ufile, &sb) < 0)
144: return (0);
145: timeasc = sb.st_mtime;
146: if ((bfd = open(binufile, 0))<0 || fstat(bfd, &sb)<0)
147: return (0);
148: if (timeasc > sb.st_mtime) /* Out of date? */
149: goto bad1;
150: if (read(bfd, &hdr, sizeof(hdr)) != sizeof(hdr))
151: goto bad1;
152: if (hdr.h_magic != UMAGIC)
153: goto bad1;
154: nunits = hdr.h_nunits;
155: sstart = alloc(hdr.h_ssize);
156: if (read(bfd, sstart, hdr.h_ssize) != hdr.h_ssize)
157: goto bad;
158: units = (UNIT *)alloc(n = nunits*sizeof(UNIT));
159: if (read(bfd, units, n) != n)
160: goto bad;
161: for (n=0; n!=nunits; n++)
162: units[n].u_name += (long)sstart;
163: close(bfd);
164: return (1);
165: bad:
166: brk(sstart);
167: bad1:
168: close(bfd);
169: return (0);
170: }
171:
172: /*
173: * Update units information by reading the
174: * units file.
175: */
176: update()
177: {
178: register char *name;
179: register int i;
180: register char *sstart, *send;
181: register int bfd;
182:
183: fprintf(stderr, "Rebuilding %s from %s ...\n", binufile, ufile);
184: if ((fd = fopen(ufile, "r")) == NULL)
185: cerr("can't open unit file `%s'", ufile);
186: setbuf(fd, inbuf);
187: units = (UNIT *)alloc(NUNITS*sizeof(UNIT));
188: sstart = sbrk(0);
189: for (nunits=0; nunits!=NUNITS; nunits++) {
190: name = getname();
191: for (i=0; i!=nunits; i++)
192: if (strcmp(units[i].u_name, name) == 0)
193: fprintf(stderr, "`%s' redefined, line %d\n",
194: name, lineno);
195: units[nunits].u_name = name;
196: if (!getunit(&units[nunits], NULL))
197: break;
198: }
199: send = sbrk(0);
200: if (!feof(fd))
201: cerr("too many units");
202: fclose(fd);
203: /*
204: * Write out, if possible, binary
205: * information for faster response next time.
206: */
207: if ((bfd = creat(binufile, 0644)) >= 0) {
208: hdr.h_magic = UMAGIC;
209: hdr.h_nunits = nunits;
210: hdr.h_ssize = send-sstart;
211: if (write(bfd, &hdr, sizeof(hdr)) != sizeof(hdr))
212: goto bad;
213: if (write(bfd, sstart, hdr.h_ssize) != hdr.h_ssize)
214: goto bad;
215: for (i=0; i!=nunits; i++)
216: units[i].u_name -= (long)sstart;/* Rel. address */
217: write(bfd, units, nunits*sizeof(UNIT));
218: for (i=0; i!=nunits; i++)
219: units[i].u_name += (long)sstart;
220: bad:
221: close(bfd);
222: }
223: }
224:
225: nextc()
226: {
227: register int c;
228:
229: if (peekc != EOF) {
230: c = peekc;
231: peekc = EOF;
232: return (c);
233: }
234: if (lastc == '\n')
235: lineno++;
236: lastc = getc(fd);
237: if (lastc == '#') { /* Eat a comment */
238: do {
239: lastc = getc(fd);
240: } while(lastc!='\n' && lastc!=EOF);
241: }
242: return (lastc);
243: }
244:
245: char *
246: getname()
247: {
248: register char *s, *t;
249: register int c;
250: register char *v;
251:
252: do {
253: c = nextc();
254: } while(c==' ' || c=='\n' || c=='\t');
255: s = buf;
256: while(c!=' ' && c!='\t' && c!='\n' && c!=EOF) {
257: *s++ = c;
258: c = nextc();
259: }
260: *s = '\0';
261: peekc = c;
262: v = t = alloc(strlen(buf)+1);
263: s = buf;
264: while (*t++ = *s++)
265: ;
266: return (v);
267: }
268:
269: punit(u)
270: register UNIT *u;
271: {
272: register int i;
273:
274: printf("%g", u->u_val);
275: for (i=0; i!=NDIM; i++)
276: if (u->u_dim[i] == 1)
277: printf(" %s", units[i].u_name);
278: else if (u->u_dim[i] > 0)
279: printf(" %s+%d", units[i].u_name, u->u_dim[i]);
280: else if (u->u_dim[i] < 0)
281: printf(" %s-%d", units[i].u_name, -u->u_dim[i]);
282: printf("\n");
283: }
284:
285: double
286: ipow(d, n)
287: double d;
288: {
289: double v;
290:
291: v = 1.;
292: if (n < 0) {
293: d = 1./d;
294: n = -n;
295: }
296: while (n) {
297: v *= d;
298: --n;
299: }
300: return (v);
301: }
302:
303: struct{
304: char *prefix;
305: double factor;
306: }pre[]={
307: "femto", 1e-15,
308: "pico", 1e-12,
309: "nano", 1e-9,
310: "micro", 1e-6,
311: "milli", 1e-3,
312: "centi", 1e-2,
313: "deci", 1e-1,
314: "hemi", .5,
315: "demi", .5,
316: "semi", .5,
317: "sesqui", 1.5,
318: "deka", 1e1,
319: "hecto", 1e2,
320: "hekto", 1e2, /* common (?) misspelling */
321: "kilo", 1e3,
322: "myria", 1e5,
323: "mega", 1e6,
324: "giga", 1e9,
325: "tera", 1e12,
326: NULL, 1.
327: };
328: /*
329: * Return the string stripped of its
330: * prefix (if any). Set factor
331: * to the multiplicative factor indicated by
332: * the prefix found.
333: */
334: char *
335: prefix(str, factor)
336: char *str;
337: double *factor;
338: {
339: register char *s, *t;
340: register int i;
341:
342: for (i=0; pre[i].prefix!=NULL; i++) {
343: s = pre[i].prefix;
344: t = str;
345: while (*s != '\0')
346: if (*s++ != *t++)
347: break;
348: if (*s == '\0') {
349: *factor = *factor * pre[i].factor;
350: return (t);
351: }
352: }
353: return(NULL);
354: }
355:
356: getunit(u, prompt)
357: UNIT *u;
358: char *prompt;
359: {
360: register int c;
361: register char *s;
362: register int i;
363: int j, expon, digit, div, pow;
364: double factor;
365: double atof();
366:
367: Again:
368: if (prompt != NULL)
369: printf("%s", prompt);
370: u->u_val = 1.;
371: for (i=0; i != NDIM; i++)
372: u->u_dim[i] = 0;
373: div = 0;
374: pow = 1;
375: for(;;)switch(c=nextc()){
376: case ' ':
377: case '\t':
378: break;
379: case '\n':
380: return (1);
381: case EOF:
382: return (0);
383: case '0':case '1':case '2':case '3':case '4':
384: case '5':case '6':case '7':case '8':case '9':
385: case '.':case '-':case '+':
386: /*
387: * a palpable number
388: */
389: s = buf;
390: if (c == '+')
391: c = nextc();
392: digit = 0;
393: while (c>='0' && c<='9') {
394: *s++ = c;
395: c = nextc();
396: digit++;
397: }
398: if (c == '.') {
399: *s++ = c;
400: while ((c=nextc())>='0' && c<='9') {
401: *s++ = c;
402: digit++;
403: }
404: }
405: if (!digit) {
406: Badnumber:
407: *s = '\0';
408: fprintf(stderr, "Bad number `%s'\n", buf);
409: goto Bad;
410: }
411: if (c=='e' || c=='E') {
412: *s++ = 'e';
413: c = nextc();
414: if (c == '+')
415: c = nextc();
416: else if (c == '-') {
417: *s++ = c;
418: c = nextc();
419: }
420: if (c<'0' || '9'<c)
421: goto Badnumber;
422: do {
423: *s++ = c;
424: c = nextc();
425: } while('0'<=c && c<='9');
426: }
427: *s = '\0';
428: peekc = c;
429: factor = atof(buf);
430: if (div) {
431: if (factor == 0.) {
432: fprintf(stderr, "Divide check\n");
433: goto Bad;
434: }
435: u->u_val /= factor;
436: div = 0;
437: } else
438: u->u_val *= factor;
439: break;
440:
441: case '/': /* divide by next unit */
442: if (div) {
443: Baddiv:
444: fprintf(stderr, "Two division signs in a row\n");
445: goto Bad;
446: }
447: div++;
448: break;
449:
450: case '!': /* primitive unit */
451: i = 0;
452: if ((c = nextc())<'0' || c>'9') {
453: fprintf(stderr, "`!' must precede a number\n");
454: goto Bad;
455: }
456: do {
457: i = i*10+c-'0';
458: c = nextc();
459: } while('0'<=c && c<='9');
460: peekc = c;
461: if (i<0 || NDIM<=i) {
462: printf("Primitive unit out of range [0,%d]\n", NDIM-1);
463: goto Bad;
464: }
465: u->u_dim[i]++;
466: break;
467:
468: default:
469: s = buf;
470: do {
471: *s++ = c;
472: c = nextc();
473: } while(c!=EOF && !anyc(c, "/0123456789+-. \t\n"));
474: *s = '\0';
475: s = buf;
476: if (strcmp(s, "per") == 0) {
477: if (div)
478: goto Baddiv;
479: div++;
480: break;
481: }
482: if (strcmp(s, "square")==0 || strcmp(s, "sq")==0) {
483: pow *= 2;
484: break;
485: }
486: if (strcmp(s, "cubic")==0 || strcmp(s, "cu")==0) {
487: pow *= 3;
488: break;
489: }
490: factor = 1.;
491: do {
492: for (i=0; i!=nunits; i++)
493: if (eqplural(s, units[i].u_name))
494: break;
495: } while(i==nunits && (s=prefix(s, &factor))!=NULL);
496: if (i == nunits) {
497: fprintf(stderr, "Unrecognised unit %s\n", buf);
498: goto Bad;
499: }
500: if (c=='+' || c=='-') {
501: if (c == '-')
502: div = !div;
503: expon = 0;
504: if ((c = nextc())<'0' || c>'9') {
505: printf("+ or - must be followed by digits\n");
506: goto Bad;
507: }
508: do {
509: expon = expon*10+c-'0';
510: c = nextc();
511: } while('0'<=c && c<='9');
512: } else
513: expon = 1;
514: expon *= pow;
515: pow = 1;
516: peekc = c;
517: if (div) {
518: expon = -expon;
519: div = 0;
520: }
521: u->u_val *= ipow(factor*units[i].u_val, expon);
522: for (j=0; j!=NDIM; j++)
523: u->u_dim[j] += units[i].u_dim[j]*expon;
524: }
525: Bad:
526: while (c!='\n' && c!=EOF)
527: c = nextc();
528: if (prompt!=NULL)
529: goto Again;
530: printf("line %d\n", lineno);
531: return (1);
532: }
533:
534: /*
535: * Check for any occurrences of
536: * the character `c' in string `s'.
537: */
538: anyc(c, s)
539: register char c;
540: register char *s;
541: {
542: while (*s != '\0')
543: if (c == *s++)
544: return (1);
545: return (0);
546: }
547:
548: /*
549: * Return non-zero if string `s' is the
550: * same or plural as string `t'.
551: */
552: eqplural(s, t)
553: register char *s, *t;
554: {
555: while (*t != '\0')
556: if (*s++ != *t++)
557: return (0);
558: return (*s=='\0' || (*s++=='s' && *s=='\0'));
559: }
560:
561: /*
562: * Diagnostics
563: */
564: /* VARARGS */
565: cerr(x)
566: {
567: fprintf(stderr, "units: %r\n", &x);
568: exit(1);
569: }
570:
571: /*
572: * Use sbrk for alloc to get
573: * contiguous memory.
574: */
575: char *
576: alloc(nb)
577: unsigned nb;
578: {
579: register char *rp;
580:
581: if ((rp = sbrk(nb)) == NULL)
582: cerr("out of memory");
583: return (rp);
584: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.