|
|
1.1 root 1: /*
2: * $Header: /newbits/bin/units.c,v 1.2 89/02/22 05:09:42 bin Exp $
3: * $Log: /newbits/bin/units.c,v $
4: * Revision 1.2 89/02/22 05:09:42 bin
5: * Changed memory allocation to work better on the atari.
6: * Changed where it looks for units and binary units, using path.
7: *
8: */
9: static char *revision = "$Revision 1.1 $";
10: static char *header =
11: "$Header: /newbits/bin/units.c,v 1.2 89/02/22 05:09:42 bin Exp $";
12:
13: /*
14: * units -- do multiplicative unit conversions
15: * td 80.09.04
16: * Modified to keep the intermediate format in a file and
17: * update it automatically when it has changed.
18: * (NOTE: program is setuid to bin)
19: * rec 84.08.13
20: * Changed Waiting for Godot ... to Rebuilding %s from %s.
21: * (Nota Bene:
22: * cc -o units -f units.c
23: * chown bin /bin/units
24: * chmod 4755 /bin/units
25: * )
26: */
27:
28: #include <stdio.h>
29: #include <sys/stat.h>
30: #include <path.h>
31: #ifdef GEM
32: #include <osbind.h>
33: #endif
34:
35: #define PATHSIZE 64
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[] = "units";
63: char binufile[] = "binunits";
64: char *uname;
65: char *buname;
66: char buf[NBUF];
67: char inbuf[BUFSIZ];
68:
69: extern char *getenv(), *path(), *index(), *strcpy();
70:
71: int nunits;
72: int uflag; /* Update information only */
73: FILE *fd;
74: int peekc = EOF;
75: int lastc = EOF;
76: int lineno = 1;
77:
78: char *getname();
79: char *prefix();
80: char *alloc();
81:
82: main(argc, argv)
83: int argc;
84: char *argv[];
85: {
86: UNIT have, want;
87: register int i;
88:
89: setbuf(stdout, NULL);
90: setbuf(stderr, NULL);
91: if (argc>1 && *argv[1]=='-') {
92: if (argv[1][1]=='u' && argv[1][2]=='\0')
93: uflag++;
94: else {
95: fprintf(stderr, "Usage: units [-u]\n");
96: exit(1);
97: }
98: }
99: init();
100: setbuf(fd = stdin, inbuf);
101: Again:
102: if (!getunit(&have, "You have: ")
103: || !getunit(&want, "You want: "))
104: exit(0);
105: for (i=0; i!=NDIM; i++)
106: if (have.u_dim[i] != want.u_dim[i]) {
107: printf("Conformability\n");
108: punit(&have);
109: punit(&want);
110: goto Again;
111: }
112: printf("* %g\n/ %g\n", have.u_val/want.u_val, want.u_val/have.u_val);
113: goto Again;
114: }
115:
116: /*
117: * Initialise by reading in units information
118: * either in binary or ascii form and updating
119: * the binary information.
120: */
121: init()
122: {
123: if (!binary())
124: update();
125: printf("%d units\n", nunits);
126: peekc = EOF;
127: if (uflag)
128: exit(0);
129: }
130:
131: /*
132: * allocate a new copy.
133: */
134: char *
135: newcpy(s)
136: register char *s;
137: {
138: return(strcpy(malloc(strlen(s) + 1), s));
139: }
140:
141: /*
142: * find a file on a path in the environment, or a default path
143: * with an access priveledge.
144: *
145: * example: pathn("helpfile", "LIBPATH", ",,\lib", "r");
146: *
147: * Returns full path name.
148: */
149: char *
150: pathn(name, envpath, deflpath, acs)
151: char *name, *envpath, *deflpath, *acs;
152: {
153: static char fullname[PATHSIZE];
154: register char *pathptr;
155:
156: if((NULL == envpath) || (NULL == (pathptr = getenv(envpath))))
157: pathptr = deflpath;
158:
159: if(NULL == index(acs, 'w')) {
160: if ((pathptr = path(pathptr, name, AREAD)) == NULL)
161: fullname[0] = '\0'; /* bad name */
162: else
163: strcpy(fullname, pathptr);
164: }
165: else {
166: register char *p, c;
167:
168: if((p = path(pathptr, name, AWRITE)) == NULL) {
169: for(p = fullname; (c = *pathptr++) && c != LISTSEP;)
170: *p++ = c;
171: *p++ = PATHSEP;
172: strcpy(p, name);
173: } else
174: strcpy(fullname, p);
175: }
176: return(fullname);
177: }
178:
179: /*
180: * Attempt to read in the already-stored
181: * binary information. Return non-zero if
182: * successful.
183: *
184: * if(binary and ascii)
185: * if(binary out of date)
186: * rebuild
187: * else
188: * use binary
189: * if(binary and no ascii)
190: * use binary
191: * if(ascii and no binary)
192: * rebuild
193: * crash
194: */
195: binary()
196: {
197: register char *sstart;
198: register int n;
199: register int bfd;
200: time_t timeasc;
201:
202: uname = newcpy(pathn(ufile, "LIBPATH", DEFLIBPATH, "r"));
203: buname = newcpy(pathn(binufile, "LIBPATH", DEFLIBPATH, "r"));
204: if(!buname[0]) { /* no binary */
205: if(!uname[0]) /* also no ansii */
206: cerr("can't find unit file `%s' or `%s'",
207: ufile, binufile);
208: buname = malloc(strlen(uname) + strlen(binufile));
209: strcpy(buname, uname);
210: strcpy(index(buname, '\0') - strlen(ufile), binufile);
211: return(0);
212: }
213: else if(!stat(uname, &sb)) { /* binary and ascii found */
214: timeasc = sb.st_mtime;
215: if(stat(buname, &sb) || (timeasc > sb.st_mtime))
216: return(0); /* bin file out of date */
217: }
218: if(uflag) /* update only */
219: return(0);
220: if((bfd = open(buname, 0)) < 0)
221: return (0);
222: if(read(bfd, &hdr, sizeof(hdr)) != sizeof(hdr))
223: goto bad;
224: if(hdr.h_magic != UMAGIC)
225: goto bad;
226: nunits = hdr.h_nunits;
227: sstart = alloc(hdr.h_ssize);
228: if (read(bfd, sstart, hdr.h_ssize) != hdr.h_ssize)
229: goto bad;
230: units = (UNIT *)alloc(n = nunits*sizeof(UNIT));
231: if (read(bfd, units, n) != n)
232: goto bad;
233: for (n=0; n!=nunits; n++)
234: units[n].u_name += (long)sstart;
235: close(bfd);
236: return (1);
237: bad:
238: close(bfd);
239: return (0);
240: }
241:
242: /*
243: * Update units information by reading the
244: * units file.
245: */
246: update()
247: {
248: register char *name;
249: register int i;
250: register char *sstart, *send;
251: register int bfd;
252:
253: fprintf(stderr, "Rebuilding %s from %s ...\n", buname, uname);
254: if ((fd = fopen(uname, "r")) == NULL)
255: cerr("can't open unit file `%s'", ufile);
256: setbuf(fd, inbuf);
257: units = (UNIT *)alloc(NUNITS*sizeof(UNIT));
258: sstart = alloc(0);
259: for (nunits=0; nunits!=NUNITS; nunits++) {
260: name = getname();
261: for (i=0; i!=nunits; i++)
262: if (strcmp(units[i].u_name, name) == 0)
263: fprintf(stderr, "`%s' redefined, line %d\n",
264: name, lineno);
265: units[nunits].u_name = name;
266: if (!getunit(&units[nunits], NULL))
267: break;
268: }
269: send = alloc(0);
270: if (!feof(fd))
271: cerr("too many units");
272: fclose(fd);
273: /*
274: * Write out, if possible, binary
275: * information for faster response next time.
276: */
277: if ((bfd = creat(buname, 0644)) >= 0) {
278: hdr.h_magic = UMAGIC;
279: hdr.h_nunits = nunits;
280: hdr.h_ssize = send-sstart;
281: if (write(bfd, &hdr, sizeof(hdr)) != sizeof(hdr))
282: goto bad;
283: if (write(bfd, sstart, hdr.h_ssize) != hdr.h_ssize)
284: goto bad;
285: for (i=0; i!=nunits; i++)
286: units[i].u_name -= (long)sstart;/* Rel. address */
287: write(bfd, units, nunits*sizeof(UNIT));
288: for (i=0; i!=nunits; i++)
289: units[i].u_name += (long)sstart;
290: bad:
291: close(bfd);
292: }
293: }
294:
295: nextc()
296: {
297: register int c;
298:
299: if (peekc != EOF) {
300: c = peekc;
301: peekc = EOF;
302: return (c);
303: }
304: if (lastc == '\n')
305: lineno++;
306: lastc = getc(fd);
307: if (lastc == '#') { /* Eat a comment */
308: do {
309: lastc = getc(fd);
310: } while(lastc!='\n' && lastc!=EOF);
311: }
312: return (lastc);
313: }
314:
315: char *
316: getname()
317: {
318: register char *s, *t;
319: register int c;
320: register char *v;
321:
322: do {
323: c = nextc();
324: } while(c==' ' || c=='\n' || c=='\t');
325: s = buf;
326: while(c!=' ' && c!='\t' && c!='\n' && c!=EOF) {
327: *s++ = c;
328: c = nextc();
329: }
330: *s = '\0';
331: peekc = c;
332: v = t = alloc(strlen(buf)+1);
333: s = buf;
334: while (*t++ = *s++)
335: ;
336: return (v);
337: }
338:
339: punit(u)
340: register UNIT *u;
341: {
342: register int i;
343:
344: printf("%g", u->u_val);
345: for (i=0; i!=NDIM; i++)
346: if (u->u_dim[i] == 1)
347: printf(" %s", units[i].u_name);
348: else if (u->u_dim[i] > 0)
349: printf(" %s+%d", units[i].u_name, u->u_dim[i]);
350: else if (u->u_dim[i] < 0)
351: printf(" %s-%d", units[i].u_name, -u->u_dim[i]);
352: printf("\n");
353: }
354:
355: double
356: ipow(d, n)
357: double d;
358: {
359: double v;
360:
361: v = 1.;
362: if (n < 0) {
363: d = 1./d;
364: n = -n;
365: }
366: while (n) {
367: v *= d;
368: --n;
369: }
370: return (v);
371: }
372:
373: struct{
374: char *prefix;
375: double factor;
376: }pre[]={
377: "femto", 1e-15,
378: "pico", 1e-12,
379: "nano", 1e-9,
380: "micro", 1e-6,
381: "milli", 1e-3,
382: "centi", 1e-2,
383: "deci", 1e-1,
384: "hemi", .5,
385: "demi", .5,
386: "semi", .5,
387: "sesqui", 1.5,
388: "deka", 1e1,
389: "hecto", 1e2,
390: "hekto", 1e2, /* common (?) misspelling */
391: "kilo", 1e3,
392: "myria", 1e5,
393: "mega", 1e6,
394: "giga", 1e9,
395: "tera", 1e12,
396: NULL, 1.
397: };
398: /*
399: * Return the string stripped of its
400: * prefix (if any). Set factor
401: * to the multiplicative factor indicated by
402: * the prefix found.
403: */
404: char *
405: prefix(str, factor)
406: char *str;
407: double *factor;
408: {
409: register char *s, *t;
410: register int i;
411:
412: for (i=0; pre[i].prefix!=NULL; i++) {
413: s = pre[i].prefix;
414: t = str;
415: while (*s != '\0')
416: if (*s++ != *t++)
417: break;
418: if (*s == '\0') {
419: *factor = *factor * pre[i].factor;
420: return (t);
421: }
422: }
423: return(NULL);
424: }
425:
426: getunit(u, prompt)
427: UNIT *u;
428: char *prompt;
429: {
430: register int c;
431: register char *s;
432: register int i;
433: int j, expon, digit, div, pow;
434: double factor;
435: double atof();
436:
437: Again:
438: if (prompt != NULL)
439: printf("%s", prompt);
440: u->u_val = 1.;
441: for (i=0; i != NDIM; i++)
442: u->u_dim[i] = 0;
443: div = 0;
444: pow = 1;
445: for(;;)switch(c=nextc()){
446: case ' ':
447: case '\t':
448: break;
449: case '\n':
450: return (1);
451: case EOF:
452: return (0);
453: case '0':case '1':case '2':case '3':case '4':
454: case '5':case '6':case '7':case '8':case '9':
455: case '.':case '-':case '+':
456: /*
457: * a palpable number
458: */
459: s = buf;
460: if (c == '+')
461: c = nextc();
462: digit = 0;
463: while (c>='0' && c<='9') {
464: *s++ = c;
465: c = nextc();
466: digit++;
467: }
468: if (c == '.') {
469: *s++ = c;
470: while ((c=nextc())>='0' && c<='9') {
471: *s++ = c;
472: digit++;
473: }
474: }
475: if (!digit) {
476: Badnumber:
477: *s = '\0';
478: fprintf(stderr, "Bad number `%s'\n", buf);
479: goto Bad;
480: }
481: if (c=='e' || c=='E') {
482: *s++ = 'e';
483: c = nextc();
484: if (c == '+')
485: c = nextc();
486: else if (c == '-') {
487: *s++ = c;
488: c = nextc();
489: }
490: if (c<'0' || '9'<c)
491: goto Badnumber;
492: do {
493: *s++ = c;
494: c = nextc();
495: } while('0'<=c && c<='9');
496: }
497: *s = '\0';
498: peekc = c;
499: factor = atof(buf);
500: if (div) {
501: if (factor == 0.) {
502: fprintf(stderr, "Divide check\n");
503: goto Bad;
504: }
505: u->u_val /= factor;
506: div = 0;
507: } else
508: u->u_val *= factor;
509: break;
510:
511: case '/': /* divide by next unit */
512: if (div) {
513: Baddiv:
514: fprintf(stderr, "Two division signs in a row\n");
515: goto Bad;
516: }
517: div++;
518: break;
519:
520: case '!': /* primitive unit */
521: i = 0;
522: if ((c = nextc())<'0' || c>'9') {
523: fprintf(stderr, "`!' must precede a number\n");
524: goto Bad;
525: }
526: do {
527: i = i*10+c-'0';
528: c = nextc();
529: } while('0'<=c && c<='9');
530: peekc = c;
531: if (i<0 || NDIM<=i) {
532: printf("Primitive unit out of range [0,%d]\n", NDIM-1);
533: goto Bad;
534: }
535: u->u_dim[i]++;
536: break;
537:
538: default:
539: s = buf;
540: do {
541: *s++ = c;
542: c = nextc();
543: } while(c!=EOF && !anyc(c, "/0123456789+-. \t\n"));
544: *s = '\0';
545: s = buf;
546: if (strcmp(s, "per") == 0) {
547: if (div)
548: goto Baddiv;
549: div++;
550: break;
551: }
552: if (strcmp(s, "square")==0 || strcmp(s, "sq")==0) {
553: pow *= 2;
554: break;
555: }
556: if (strcmp(s, "cubic")==0 || strcmp(s, "cu")==0) {
557: pow *= 3;
558: break;
559: }
560: factor = 1.;
561: do {
562: for (i=0; i!=nunits; i++)
563: if (eqplural(s, units[i].u_name))
564: break;
565: } while(i==nunits && (s=prefix(s, &factor))!=NULL);
566: if (i == nunits) {
567: fprintf(stderr, "Unrecognised unit %s\n", buf);
568: goto Bad;
569: }
570: if (c=='+' || c=='-') {
571: if (c == '-')
572: div = !div;
573: expon = 0;
574: if ((c = nextc())<'0' || c>'9') {
575: printf("+ or - must be followed by digits\n");
576: goto Bad;
577: }
578: do {
579: expon = expon*10+c-'0';
580: c = nextc();
581: } while('0'<=c && c<='9');
582: } else
583: expon = 1;
584: expon *= pow;
585: pow = 1;
586: peekc = c;
587: if (div) {
588: expon = -expon;
589: div = 0;
590: }
591: u->u_val *= ipow(factor*units[i].u_val, expon);
592: for (j=0; j!=NDIM; j++)
593: u->u_dim[j] += units[i].u_dim[j]*expon;
594: }
595: Bad:
596: while (c!='\n' && c!=EOF)
597: c = nextc();
598: if (prompt!=NULL)
599: goto Again;
600: printf("line %d\n", lineno);
601: return (1);
602: }
603:
604: /*
605: * Check for any occurrences of
606: * the character `c' in string `s'.
607: */
608: anyc(c, s)
609: register char c;
610: register char *s;
611: {
612: while (*s != '\0')
613: if (c == *s++)
614: return (1);
615: return (0);
616: }
617:
618: /*
619: * Return non-zero if string `s' is the
620: * same or plural as string `t'.
621: */
622: eqplural(s, t)
623: register char *s, *t;
624: {
625: while (*t != '\0')
626: if (*s++ != *t++)
627: return (0);
628: return (*s=='\0' || (*s++=='s' && *s=='\0'));
629: }
630:
631: /*
632: * Diagnostics
633: */
634: /* VARARGS */
635: cerr(x)
636: char *x;
637: {
638: fprintf(stderr, "units: %r\n", &x);
639: exit(1);
640: }
641:
642: /*
643: * get contiguous memory.
644: */
645: char *
646: alloc(nb)
647: unsigned nb;
648: {
649: register char *rp;
650: #ifndef GEM
651: if((rp = sbrk(nb)) == ((char *)-1))
652: cerr("out of memory");
653: #else
654: static char *mp = NULL;
655: static long l;
656:
657: if((NULL == mp) &&
658: (!(l = Malloc(-1L)) ||
659: !(mp = (char *)Malloc(l))))
660: cerr("no memory");
661:
662: if(0 > (l -= nb))
663: cerr("out of memory");
664: rp = mp;
665: mp += nb;
666: #endif
667: return (rp);
668: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.