/[ascend]/trunk/base/generic/compiler/units.c
ViewVC logotype

Contents of /trunk/base/generic/compiler/units.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 709 - (show annotations) (download) (as text)
Wed Jun 28 16:28:57 2006 UTC (13 years, 5 months ago) by johnpye
File MIME type: text/x-csrc
File size: 22996 byte(s)
Monster commit!
Lots of recommenting and reorganising of external relations-related stuff.
Replaced a lot of ascmalloc and asccalloc calls with the new ASC_NEW* macros.
Fixed (?) the problem Art is having with icons in PyGTK.
Turned on -Wall in SConstruct and fixed up a stack of warnings.
Removed the redundant exit(2) from after Asc_Panic calls and added __attribute__((noreturn)).
Set doxygen to create callgraphs to level 2, updated doxyfile to version 1.4.7.
Fixed up building of extfntest.c.
1 /*
2 * Ascend Units Type Implementation
3 * by Tom Epperly
4 * 9/13/89
5 * Version: $Revision: 1.18 $
6 * Version control file: $RCSfile: units.c,v $
7 * Date last modified: $Date: 1998/04/11 01:32:11 $
8 * Last modified by: $Author: ballan $
9 *
10 * This file is part of the Ascend Language Interpreter.
11 *
12 * Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
13 *
14 * The Ascend Language Interpreter is free software; you can redistribute
15 * it and/or modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * The Ascend Language Interpreter is distributed in hope that it will be
20 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with the program; if not, write to the Free Software Foundation,
26 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
27 * COPYING.
28 */
29
30 #include <math.h>
31 #include <ctype.h>
32 #include <utilities/ascConfig.h>
33 #include <utilities/ascMalloc.h>
34 #include <general/hashpjw.h>
35 #include <general/dstring.h>
36 #include "compiler.h"
37 #include "instance_enum.h"
38 #include "cmpfunc.h"
39 #include "symtab.h"
40 #include "fractions.h"
41 #include "dimen.h"
42 #include "dimen_io.h"
43 #include "units.h"
44 #include "compiler.h"
45
46 #ifndef lint
47 static CONST char UnitsModuleID[] = "$Id: units.c,v 1.18 1998/04/11 01:32:11 ballan Exp $";
48 #endif
49
50 enum units_scanner_tokens {
51 units_id,
52 units_real,
53 units_times,
54 units_divide,
55 units_power,
56 units_open,
57 units_close,
58 units_end,
59 units_err, /* unexpected character at position */
60 units_oversized, /* oversized */
61 units_real_err /* bad character in real or character */
62 /* missing */
63 };
64
65 struct ParseReturn {
66 double conv;
67 dim_type dim;
68 };
69
70 /* parsing global variables */
71 char *g_units_str = NULL;
72 unsigned long g_units_str_len = 0;
73 char g_units_id_space[MAXTOKENLENGTH+1];
74
75 /* hash table global variables */
76 struct Units *g_units_hash_table[UNITS_HASH_SIZE];
77 unsigned long g_units_size = 0;
78 unsigned long g_units_collisions = 0;
79
80 static
81 struct ParseReturn CheckNewUnits(CONST char *, unsigned long int *CONST,
82 int *CONST);
83
84 static
85 struct ParseReturn ParseString(CONST char *c,
86 unsigned long int *CONST pos,
87 int *CONST error_code);
88
89 static
90 void CopyToGlobal(register CONST char *c)
91 {
92 register char *p;
93 register unsigned length;
94 length = strlen(c);
95 if (g_units_str==NULL) {
96 g_units_str = ascmalloc((unsigned)length+(unsigned)1);
97 g_units_str_len = length;
98 }
99 else
100 if (length > g_units_str_len) {
101 g_units_str = ascrealloc(g_units_str,(unsigned)length+(unsigned)1);
102 g_units_str_len = length;
103 }
104 p = g_units_str;
105 while((*c) != '\0')
106 if (!isspace(*c)) *(p++) = *(c++);
107 else c++;
108 *p = '\0';
109 }
110
111 static
112 void DefineFundamentalUnit(CONST char *dimname, char *unitname)
113 {
114 CONST struct Units *uptr;
115 dim_type dim, *dimp;
116
117 dimp = &dim;
118 ClearDimensions(dimp);
119 ParseDim(dimp,dimname);
120 dimp = (dim_type *)FindOrAddDimen(dimp);
121 uptr = DefineUnits(AddSymbol(unitname),(double)1.0,dimp);
122 if (uptr==NULL) {
123 FPRINTF(ASCERR,"Unable to define SI unit %s.\n",unitname);
124 }
125 }
126
127 static
128 void DefineFundamentalUnits(void)
129 {
130 DefineFundamentalUnit("M",UNIT_BASE_MASS);
131 DefineFundamentalUnit("Q",UNIT_BASE_QUANTITY);
132 DefineFundamentalUnit("T", UNIT_BASE_TIME);
133 DefineFundamentalUnit("L", UNIT_BASE_LENGTH);
134 DefineFundamentalUnit("TMP", UNIT_BASE_TEMPERATURE);
135 DefineFundamentalUnit("C", UNIT_BASE_CURRENCY);
136 DefineFundamentalUnit("E", UNIT_BASE_ELECTRIC_CURRENT);
137 DefineFundamentalUnit("LUM", UNIT_BASE_LUMINOUS_INTENSITY);
138 DefineFundamentalUnit("P", UNIT_BASE_PLANE_ANGLE);
139 DefineFundamentalUnit("S", UNIT_BASE_SOLID_ANGLE);
140 }
141
142 /* internal translate table of some utility */
143 static
144 char *g_unit_base_name[NUM_DIMENS];
145
146 void InitUnitsTable(void)
147 {
148 register unsigned long c;
149 register CONST struct Units *result;
150
151 for(c=0;c<UNITS_HASH_SIZE;g_units_hash_table[c++]=NULL);
152 /* no body */
153 g_units_size = 0;
154 g_units_collisions = 0;
155 result = DefineUnits(AddSymbol("?"),1.0,WildDimension());
156 result = DefineUnits(AddSymbol(""),1.0,Dimensionless());
157 DefineFundamentalUnits();
158 g_unit_base_name[D_MASS] = UNIT_BASE_MASS;
159 g_unit_base_name[D_QUANTITY] = UNIT_BASE_QUANTITY;
160 g_unit_base_name[D_LENGTH] = UNIT_BASE_LENGTH;
161 g_unit_base_name[D_TIME] = UNIT_BASE_TIME;
162 g_unit_base_name[D_TEMPERATURE] = UNIT_BASE_TEMPERATURE;
163 g_unit_base_name[D_CURRENCY] = UNIT_BASE_CURRENCY;
164 g_unit_base_name[D_ELECTRIC_CURRENT] = UNIT_BASE_ELECTRIC_CURRENT;
165 g_unit_base_name[D_LUMINOUS_INTENSITY] = UNIT_BASE_LUMINOUS_INTENSITY;
166 g_unit_base_name[D_PLANE_ANGLE] = UNIT_BASE_PLANE_ANGLE;
167 g_unit_base_name[D_SOLID_ANGLE] = UNIT_BASE_SOLID_ANGLE;
168 }
169
170 void DestroyUnitsTable(void)
171 {
172 register unsigned long c;
173 struct Units *ptr,*next;
174 for(c=0;c<UNITS_HASH_SIZE;g_units_hash_table[c++]=NULL){
175 next = g_units_hash_table[c];
176 while((ptr = next)!=NULL){
177 next = ptr->next;
178 ascfree(ptr);
179 }
180 }
181 g_units_size = 0;
182 g_units_collisions = 0;
183 if (g_units_str) ascfree(g_units_str);
184 g_units_str = 0;
185 g_units_str_len = 0;
186 }
187
188 struct UnitDefinition *CreateUnitDef(symchar *lhs, CONST char *rhs,
189 CONST char *filename, int linenum)
190 {
191 int len;
192 struct UnitDefinition *ud;
193 char *ustr;
194
195 if (lhs==NULL || rhs == NULL || filename == NULL) {
196 FPRINTF(ASCERR," CreateUnitDef miscalled.\n");
197 return NULL;
198 }
199 ud = (struct UnitDefinition *)ascmalloc(sizeof(struct UnitDefinition));
200 if (ud == NULL) {
201 FPRINTF(ASCERR," malloc failed in CreateUnitDef for %s: %s %d\n",
202 SCP(lhs),filename,linenum);
203 return NULL;
204 }
205 len = strlen(rhs) + 1;
206 ustr = ASC_NEW_ARRAY(char,len);
207 if (ustr == NULL) {
208 FPRINTF(ASCERR," malloc failed in CreateUnitDef for %s: %s %d\n",
209 rhs,filename,linenum);
210 ascfree(ud);
211 return NULL;
212 }
213 strcpy(ustr,rhs);
214
215 ud->new_name = lhs;
216 ud->unitsexpr = ustr;
217 ud->filename = filename;
218 ud->linenum = linenum;
219 return ud;
220 }
221
222 void DestroyUnitDef(struct UnitDefinition *ud)
223 {
224 if (ud==NULL) {
225 return;
226 }
227 ascfree((char *)ud->unitsexpr);
228 ud->new_name = NULL;
229 ud->unitsexpr = ud->filename = NULL;
230 ascfree((char *)ud);
231 }
232
233 void ProcessUnitDef(struct UnitDefinition *ud)
234 {
235 CONST struct Units *result;
236 struct ParseReturn pr;
237 unsigned long pos;
238 char **errv;
239 int code;
240
241 if (ud==NULL) {
242 return;
243 }
244 pr = CheckNewUnits(ud->unitsexpr,&pos,&code);
245 if (code!=0) {
246 errv = UnitsExplainError(ud->unitsexpr,code,pos);
247 FPRINTF(ASCERR,"ERROR: %s.\n", errv[0]);
248 FPRINTF(ASCERR," %s =\n",SCP(ud->new_name));
249 FPRINTF(ASCERR," {%s};\n",errv[1]);
250 FPRINTF(ASCERR," -%s\n",errv[2]);
251 FPRINTF(ASCERR," %s:%d\n\n",ud->filename,ud->linenum);
252 return;
253 }
254 result = DefineUnits(ud->new_name,pr.conv,FindOrAddDimen(&pr.dim));
255 if (result == NULL) {
256 errv = UnitsExplainError(ud->unitsexpr,11,0);
257 FPRINTF(ASCERR,"ERROR: %s.\n", errv[0]);
258 FPRINTF(ASCERR," %s =\n",SCP(ud->new_name));
259 FPRINTF(ASCERR," {%s};\n",errv[1]);
260 FPRINTF(ASCERR," -%s\n",errv[2]);
261 FPRINTF(ASCERR," %s:%d\n\n",ud->filename,ud->linenum);
262 return;
263 }
264 }
265
266 /*
267 * it is not appropriate to replace this with a pointer hashing
268 * ufnction since the string hashed may not be a symchar.
269 */
270 #define UnitsHashFunction(s) hashpjw(s,UNITS_HASH_SIZE)
271
272 CONST struct Units *LookupUnits(CONST char *c)
273 {
274 register struct Units *result;
275 register int str_cmp=1;
276 if ((result=g_units_hash_table[UnitsHashFunction(c)])!=NULL) {
277 while(((str_cmp=strcmp(SCP(UnitsDescription(result)),c))<0) &&
278 (result->next != NULL))
279 result = result->next;
280 if (str_cmp==0) return result;
281 }
282 return NULL;
283 }
284
285 static
286 struct Units *CheckUnitsMatch(struct Units *p,
287 double conv,
288 CONST dim_type *dim)
289 {
290 if ((conv!=UnitsConvFactor(p))||(!SameDimen(dim,UnitsDimensions(p)))) {
291 return NULL;
292 } else {
293 return p;
294 }
295 }
296
297 CONST struct Units *DefineUnits(symchar *c, double conv,
298 CONST dim_type *dim)
299 {
300 register unsigned long bucket;
301 register struct Units *result,*tmp;
302 register int str_cmp;
303 assert(AscFindSymbol(c)!=NULL);
304 bucket=UnitsHashFunction(SCP(c));
305 if (g_units_hash_table[bucket]!=NULL) {
306 result=g_units_hash_table[bucket];
307 str_cmp = CmpSymchar(c,UnitsDescription(result));
308 if (str_cmp==0) {
309 return CheckUnitsMatch(result,conv,dim);
310 } else if (str_cmp<0) {
311 /* insert before list head */
312 g_units_hash_table[bucket]=
313 (struct Units *)ascmalloc(sizeof(struct Units));
314 g_units_hash_table[bucket]->next = result;
315 result = g_units_hash_table[bucket];
316 } else {
317 while ((result->next!=NULL)&&
318 ((str_cmp=CmpSymchar(c,UnitsDescription(result->next)))>0))
319 result = result->next;
320 if (str_cmp==0) return CheckUnitsMatch(result->next,conv,dim);
321 tmp = result->next;
322 result->next = (struct Units *)ascmalloc(sizeof(struct Units));
323 result = result->next;
324 result->next = tmp;
325 }
326 g_units_size++;
327 g_units_collisions++;
328 result->description = c;
329 result->conversion_factor = conv;
330 result->dim = dim;
331 }
332 else { /* empty bucket */
333 g_units_size++;
334 result = g_units_hash_table[bucket] =
335 (struct Units *)ascmalloc(sizeof(struct Units));
336 result->next = NULL;
337 result->description = c;
338 result->dim = dim;
339 result->conversion_factor = conv;
340 }
341 return result;
342 }
343
344 static
345 void SkipStrBlanks(CONST char *c, unsigned long int *CONST pos)
346 {
347 while(isspace(c[*pos])) (*pos)++;
348 }
349
350 static
351 int AddChar(register char ch, register unsigned int pos)
352 {
353 if (pos < MAXTOKENLENGTH) {
354 g_units_id_space[pos]=ch;
355 return 1;
356 }
357 g_units_id_space[MAXTOKENLENGTH] = '\0';
358 return 0;
359 }
360
361 static
362 enum units_scanner_tokens GetUnitsToken(CONST char *c,
363 unsigned long int *CONST pos)
364 {
365 register unsigned cc;
366 SkipStrBlanks(c,pos);
367 if (isalpha(c[*pos])) {
368 cc = 0;
369 do {
370 if (AddChar(c[*pos],cc++)) (*pos)++;
371 else return units_oversized;
372 } while(isalpha(c[*pos])||(isdigit(c[*pos]))||(c[*pos]=='_'));
373 g_units_id_space[cc]='\0';
374 return units_id;
375 }
376 else if (isdigit(c[*pos])) { /* real or integer */
377 cc = 0;
378 do {
379 if (AddChar(c[*pos],cc++)) (*pos)++;
380 else return units_oversized;
381 } while (isdigit(c[*pos]));
382 if (c[*pos] == '.') {
383 if (AddChar(c[*pos],cc++)) (*pos)++;
384 else return units_oversized;
385 while (isdigit(c[*pos])) {
386 if (AddChar(c[*pos],cc++)) (*pos)++;
387 else return units_oversized;
388 }
389 }
390 if ((c[*pos] == 'e')||(c[*pos] == 'E')) {
391 if (AddChar(c[*pos],cc++)) (*pos)++;
392 else return units_oversized;
393 if ((c[*pos] == '+')||(c[*pos] == '-')) {
394 if (AddChar(c[*pos],cc++)) (*pos)++;
395 else return units_oversized;
396 }
397 if (isdigit(c[*pos])) {
398 do {
399 if (AddChar(c[*pos],cc++)) (*pos)++;
400 else return units_oversized;
401 } while (isdigit(c[*pos]));
402 }
403 else {
404 g_units_id_space[cc]='\0';
405 return units_real_err;
406 }
407 }
408 g_units_id_space[cc]='\0';
409 return units_real;
410 }
411 else
412 switch(c[*pos]) {
413 case '.': /* real */
414 cc = 0;
415 if (AddChar(c[*pos],cc++)) (*pos)++;
416 else return units_oversized;
417 if (isdigit(c[*pos])) {
418 do {
419 if (AddChar(c[*pos],cc++)) (*pos)++;
420 else return units_oversized;
421 } while (isdigit(c[*pos]));
422 }
423 else {
424 g_units_id_space[cc]='\0';
425 return units_real_err;
426 }
427 if ((c[*pos] == 'e')||(c[*pos] == 'E')) {
428 if (AddChar(c[*pos] ,cc++)) (*pos)++;
429 else return units_oversized;
430 if ((c[*pos] == '+')||(c[*pos] == '-')) {
431 if (AddChar(c[*pos],cc++)) (*pos)++;
432 else return units_oversized;
433 }
434 if (isdigit(c[*pos])) {
435 do {
436 if (AddChar(c[*pos],cc++)) (*pos)++;
437 else return units_oversized;
438 } while (isdigit(c[*pos]));
439 }
440 else {
441 g_units_id_space[cc]='\0';
442 return units_real_err;
443 }
444 }
445 g_units_id_space[cc]='\0';
446 return units_real;
447 case '^':
448 (*pos)++;
449 return units_power;
450 case '*':
451 (*pos)++;
452 return units_times;
453 case '/':
454 (*pos)++;
455 return units_divide;
456 case '(':
457 (*pos)++;
458 return units_open;
459 case ')':
460 (*pos)++;
461 return units_close;
462 case '\0':
463 return units_end;
464 default:
465 return units_err;
466 }
467 }
468
469 static
470 double AdjustConv(double d, struct fraction f, int *CONST error_code)
471 {
472 f = Simplify(f);
473 if (Numerator(f)<0) {
474 if (Denominator(f)!=1) {
475 *error_code = 10;
476 return 0.0;
477 }
478 return 1.0/pow(d,-(double)Numerator(f));
479 }
480 else
481 return pow(d,(double)Numerator(f)/(double)Denominator(f));
482 }
483
484 static
485 FRACPART ParseInt(CONST char *c,
486 unsigned long int *CONST pos,
487 int *CONST error_code)
488 {
489 register unsigned count=0;
490 SkipStrBlanks(c,pos);
491 if ((c[*pos]=='-')||(c[*pos]=='+'))
492 g_units_id_space[count++]=c[(*pos)++];
493 if (!isdigit(c[*pos])) {
494 *error_code = 10;
495 return 1;
496 }
497 while (isdigit(c[*pos])) {
498 if (count < MAXTOKENLENGTH)
499 g_units_id_space[count++]=c[(*pos)++];
500 else {
501 *error_code = 10;
502 return 1;
503 }
504 }
505 g_units_id_space[count]='\0';
506 return (FRACPART)atoi(g_units_id_space);
507 }
508
509 static
510 struct fraction ParseFraction(CONST char *c,
511 unsigned long int *CONST pos,
512 int *CONST error_code)
513 {
514 register FRACPART num,denom;
515 SkipStrBlanks(c,pos);
516 if (c[*pos]=='(') {
517 (*pos)++;
518 num = ParseInt(c,pos,error_code);
519 if (*error_code != 0) {
520 SkipStrBlanks(c,pos);
521 if (c[*pos] == '/') {
522 (*pos)++;
523 denom = ParseInt(c,pos,error_code);
524 if (*error_code != 0) {
525 SkipStrBlanks(c,pos);
526 if (c[*pos] == ')') {
527 (*pos)++;
528 return CreateFraction(num,denom);
529 }
530 else { /* unclosed parenthesis */
531 *error_code = 2;
532 return CreateFraction(1,1);
533 }
534 }
535 }
536 else if (c[*pos] == ')') { /* okay */
537 (*pos)++;
538 return CreateFraction(num,1);
539 }
540 else { /* error unclosed parenthesis */
541 *error_code = 2;
542 return CreateFraction(1,1);
543 }
544 }
545 }
546 else if (isdigit(c[*pos])||(c[*pos]=='+')||(c[*pos]=='-'))
547 return CreateFraction(ParseInt(c,pos,error_code),1);
548 *error_code = 10;
549 return CreateFraction(1,1);
550 }
551
552 static
553 struct ParseReturn ParseTerm(CONST char *c,
554 unsigned long int *CONST pos,
555 int *CONST error_code)
556 {
557 register CONST struct Units *lookup;
558 struct fraction frac;
559 enum units_scanner_tokens tok;
560 struct ParseReturn result;
561 unsigned long oldpos;
562 result.conv = 1.0;
563 ClearDimensions(&(result.dim));
564 SkipStrBlanks(c,pos);
565 oldpos = *pos;
566 switch(GetUnitsToken(c,pos)) {
567 case units_id:
568 lookup = LookupUnits(g_units_id_space);
569 if (lookup!=NULL) {
570 CopyDimensions(UnitsDimensions(lookup),&result.dim);
571 result.conv = UnitsConvFactor(lookup);
572 }
573 else {
574 *pos = oldpos;
575 *error_code = 1;
576 return result;
577 }
578 break;
579 case units_real:
580 result.conv = atof(g_units_id_space);
581 break;
582 case units_open:
583 result = ParseString(c,pos,error_code);
584 if (*error_code == 0) {
585 if (GetUnitsToken(c,pos)!=units_close) {/* unbalanced parenthesis */
586 *error_code = 2;
587 *pos = oldpos;
588 return result;
589 }
590 } else {
591 return result;
592 }
593 break;
594 case units_err:
595 *error_code = 3;
596 return result;
597 case units_end:
598 *error_code = 7;
599 return result;
600 case units_oversized:
601 *error_code = 5;
602 *pos = oldpos;
603 return result;
604 case units_real_err:
605 *error_code = 4;
606 *pos = oldpos;
607 return result;
608 case units_divide:
609 case units_power:
610 case units_times:
611 *pos = oldpos;
612 *error_code = 8;
613 return result;
614 case units_close:
615 *pos = oldpos;
616 *error_code = 9;
617 return result;
618 }
619 SkipStrBlanks(c,pos);
620 if (c[*pos]=='^') {
621 tok = GetUnitsToken(c,pos);
622 SkipStrBlanks(c,pos);
623 oldpos = *pos;
624 frac = ParseFraction(c,pos,error_code);
625 if (*error_code==0) {
626 result.dim = ScaleDimensions(&result.dim,frac);
627 result.conv = AdjustConv(result.conv,frac,error_code);
628 }
629 if (*error_code!=0) *pos = oldpos;
630 }
631 return result;
632 }
633
634 static
635 struct ParseReturn MultiplyPR(CONST struct ParseReturn *r1,
636 CONST struct ParseReturn *r2)
637 {
638 struct ParseReturn result;
639 result.conv = r1->conv*r2->conv;
640 result.dim = AddDimensions(&(r1->dim),&(r2->dim));
641 return result;
642 }
643
644 static
645 struct ParseReturn DividePR(CONST struct ParseReturn *r1,
646 CONST struct ParseReturn *r2)
647 {
648 struct ParseReturn result;
649 result.conv = r1->conv/r2->conv;
650 result.dim = SubDimensions(&(r1->dim),&(r2->dim));
651 return result;
652 }
653
654 static
655 struct ParseReturn ParseString(CONST char *c,
656 unsigned long int *CONST pos,
657 int *CONST error_code)
658 {
659 struct ParseReturn result1,result2;
660 unsigned long oldpos;
661 result1 = ParseTerm(c,pos,error_code);
662 while (*error_code == 0 ) {
663 SkipStrBlanks(c,pos);
664 oldpos = *pos;
665 switch(GetUnitsToken(c,pos)) {
666 case units_oversized:
667 case units_id:
668 case units_real_err:
669 case units_real:
670 case units_open:
671 *pos = oldpos;
672 *error_code = 6;
673 return result1;
674 case units_times:
675 result2 = ParseTerm(c,pos,error_code);
676 if (*error_code==0) {
677 result1 = MultiplyPR(&result1,&result2);
678 }
679 break;
680 case units_divide:
681 result2 = ParseTerm(c,pos,error_code);
682 if (*error_code==0) {
683 result1 = DividePR(&result1,&result2);
684 }
685 break;
686 case units_close:
687 case units_end: /* natural closings */
688 return result1;
689 case units_err:
690 *error_code = 3;
691 return result1;
692 default:
693 /* units power? */
694 break;
695 }
696 }
697 return result1;
698 }
699
700 /*
701 * Checks the RHS of a new unit definition.
702 * returns valid parsereturn iff *error_code = 0 on exit.
703 * This has no effects
704 * on the global unit table, so it returns a ParseReturn
705 * instead of a units pointer.
706 * If unit already exists and the old and new definitions
707 * are incompatible, returns error.
708 */
709 static
710 struct ParseReturn CheckNewUnits(CONST char *c,
711 unsigned long int *CONST pos,
712 int *CONST error_code)
713 {
714 struct ParseReturn preturn;
715 register CONST struct Units *result;
716
717 /* initialize return codes */
718 *pos = 0;
719 *error_code = 0;
720 /* copy string to global string while removing blanks */
721 CopyToGlobal(c);
722 /* check if units are previously defined */
723 result = LookupUnits(g_units_str);
724 if (result != NULL) {
725 preturn.conv = UnitsConvFactor(result);
726 preturn.dim = *(UnitsDimensions(result));
727 return preturn;
728 }
729 /* it couldn't find a match, so the string must be parsed */
730 preturn = ParseString(c,pos,error_code);
731 return preturn;
732 }
733
734 CONST struct Units *FindOrDefineUnits(CONST char *c,
735 unsigned long int *CONST pos,
736 int *CONST error_code)
737 {
738 register CONST struct Units *result;
739 struct ParseReturn preturn;
740
741 /* initialize return codes */
742 *pos = 0;
743 *error_code = 0;
744 /* copy string to global string while removing blanks */
745 CopyToGlobal(c);
746 /* check if units are previously defined */
747 result = LookupUnits(g_units_str);
748 if (result != NULL) {
749 return result;
750 }
751 /* it couldn't find a match, so the string must be parsed */
752 preturn = ParseString(c,pos,error_code);
753 if (*error_code == 0) {
754 result = DefineUnits(AddSymbol(g_units_str),
755 preturn.conv,
756 FindOrAddDimen(&preturn.dim));
757 }
758 return result;
759 }
760
761 char *UnitsStringSI(struct Units *p)
762 {
763 Asc_DString ds, *dsPtr;
764 char expo[20];
765 char *result;
766 int numseen = 0;
767 int i;
768 int k;
769
770 if (p==NULL) {
771 return NULL;
772 }
773 if (IsWild(p->dim)) {
774 result = ASC_NEW_ARRAY(char,2);
775 sprintf(result,"*");
776 return result;
777 }
778 dsPtr = &ds;
779 Asc_DStringInit(dsPtr);
780 for (i=0; i < NUM_DIMENS; i++) {
781 k = GetDimPower(*(p->dim),i);
782 if (k > 0) {
783 if (numseen) {
784 Asc_DStringAppend(dsPtr,"*",1);
785 }
786 Asc_DStringAppend(dsPtr,g_unit_base_name[i],-1);
787 if (k > 1) {
788 sprintf(expo,"^%d",k);
789 Asc_DStringAppend(dsPtr,expo,-1);
790 }
791 numseen =1;
792 }
793 }
794 if (!numseen) {
795 Asc_DStringAppend(dsPtr,"1",1);
796 }
797 for (i=0; i < NUM_DIMENS; i++) {
798 k = GetDimPower(*(p->dim),i);
799 if (k < 0) {
800 Asc_DStringAppend(dsPtr,"/",1);
801 Asc_DStringAppend(dsPtr,g_unit_base_name[i],-1);
802 if (k < -1) {
803 sprintf(expo,"^%d",-k);
804 Asc_DStringAppend(dsPtr,expo,-1);
805 }
806 }
807 }
808 result = Asc_DStringResult(dsPtr);
809 return result;
810 }
811
812 void DumpUnits(FILE *file)
813 {
814 register unsigned long c;
815 register struct Units *p;
816 char *ds;
817 FPRINTF(file,"Units dump\n");
818 for(c=0;c<UNITS_HASH_SIZE;c++) {
819 for(p = g_units_hash_table[c];p!=NULL;p=p->next) {
820 ds = WriteDimensionString(p->dim);
821 FPRINTF(file,"%35s %14g %s\n",
822 SCP(p->description),
823 p->conversion_factor,ds);
824 if (ds != NULL) {
825 ascfree(ds);
826 }
827 }
828 }
829 }
830
831 static
832 char *g_unit_explain_error_strings[3] = {NULL,NULL,NULL};
833 #define ERRV g_unit_explain_error_strings
834
835 char **UnitsExplainError(CONST char *ustr, int code, int pos)
836 {
837 #define UEESIZE 14
838 #define UEELAST (UEESIZE-3) /* last real message */
839 #define UEECALL (UEESIZE-2)
840 #define UEEMEM (UEESIZE-1)
841 static char *g_units_errors[UEESIZE] = {
842 "unit ok",
843 "undefined unit in expression",
844 "unbalanced ( or () in denominator",
845 "illegal character",
846 "illegal real value",
847 "unit name too long",
848 "operator ( * or / ) missing",
849 "term missing after *,/, or (",
850 "term missing before * or /",
851 "too many )",
852 "illegal fractional exponent",
853 "redefinition of unit",
854 /* these two should be last */
855 "error in call to UnitsExplainError",
856 "malloc fail in UnitsExplainError"
857 };
858 int c,len;
859 char *line;
860
861 if (ERRV[2] != g_units_errors[UEECALL] &&
862 ERRV[2] != g_units_errors[UEEMEM] &&
863 ERRV[2] != NULL) {
864 ascfree(ERRV[2]);
865 ERRV[2] = NULL;
866 }
867 if (code<0 || code>UEELAST || ustr==NULL) {
868 ERRV[0] = g_units_errors[UEECALL];
869 ERRV[1] = g_units_errors[UEECALL];
870 ERRV[2] = g_units_errors[UEECALL];
871 return ERRV;
872 }
873 len = strlen(ustr);
874 if (pos<0 || pos>=len ) {
875 ERRV[0] = g_units_errors[UEECALL];
876 ERRV[1] = g_units_errors[UEECALL];
877 ERRV[2] = g_units_errors[UEECALL];
878 return ERRV;
879 }
880 line = ASC_NEW_ARRAY_CLEAR(char,len+2);
881 if (line==NULL) {
882 ERRV[0] = g_units_errors[UEEMEM];
883 ERRV[1] = g_units_errors[UEEMEM];
884 ERRV[2] = g_units_errors[UEEMEM];
885 return ERRV;
886 }
887 ERRV[0] = g_units_errors[code];
888 ERRV[1] = (char *)ustr;
889 ERRV[2] = line;
890 c = 0;
891 while ( c < pos) {
892 line[c] = '-';
893 c++;
894 }
895 line[c] = '^';
896 c++;
897 line[c] = '\0';
898 return ERRV;
899 }
900

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22