Return to thTestParse.c CVS log | Up to [HallC] / Analyzer / CTP |
1 saw 1.1 /*----------------------------------------------------------------------------- 2 * Copyright (c) 1993 Southeastern Universities Research Association, 3 * Continuous Electron Beam Accelerator Facility 4 * 5 * This software was developed under a United States Government license 6 * described in the NOTICE file included as part of this distribution. 7 * 8 * Stephen A. Wood, 12000 Jefferson Ave., Newport News, VA 23606 9 * Email: saw@cebaf.gov Tel: (804) 249-7367 Fax: (804) 249-5800 10 *----------------------------------------------------------------------------- 11 * 12 * Description: 13 * The expression parser and stack executor for the Test Package 14 * 15 * Author: Stephen Wood, CEBAF Hall C 16 * 17 * Revision History: 18 * $Log: thTestParse.c,v $ | ||
19 jones 1.6 * Revision 1.4.24.1.2.1 2011/03/03 20:09:44 jones 20 * Used to be %li and %ld, but that makes 8 byte result stuffed into 4 byte *tokval 21 * | ||
22 jones 1.5 * Revision 1.4.24.1 2007/09/10 21:32:47 pcarter 23 * Implemented changes to allow compilation on RHEL 3,4,5 and MacOSX 24 * 25 * Revision 1.4 2003/02/21 20:55:25 saw 26 * Clean up some types and casts to reduce compiler warnings. 27 * | ||
28 saw 1.4 * Revision 1.3 1999/11/04 20:34:07 saw 29 * Alpha compatibility. 30 * New RPC call needed for root event display. 31 * Start of code to write ROOT trees (ntuples) from new "tree" block 32 * | ||
33 saw 1.3 * Revision 1.19 1999/08/25 13:16:07 saw 34 * *** empty log message *** 35 * 36 * Revision 1.18 1999/07/07 13:43:51 saw 37 * Don't make numbers starting with "0" be octal. Accept 0x as hex. 38 * 39 * Move thTestRHandler() into thTestParse.c | ||
40 saw 1.2 * 41 * Revision 1.17 1999/03/01 20:00:50 saw 42 * Fix bug where a series of numbers added or subtracted in a parameter line 43 * got evaluated to be just the first number. Improve the scientific 44 * number detection to do this. 45 * | ||
46 saw 1.1 * Revision 1.16 1996/07/31 20:36:56 saw 47 * Support floating point for mod command. Add trig functions. 48 * 49 * Revision 1.15 1995/08/03 13:56:36 saw 50 * Add single argument functions 51 * 52 * Revision 1.14 1995/04/10 15:51:21 saw 53 * thEvalImed returns INTOVF if double result is to large to convert to int. 54 * 55 * Revision 1.13 1995/02/14 16:53:52 saw 56 * Make compatible with OSF/Alpha (64 bit pointers) 57 * 58 * Revision 1.12 1995/01/09 16:06:11 saw 59 * Fix a short malloc for a string 60 * 61 * Revision 1.11 1994/11/17 18:14:21 saw 62 * Strip out unary + operators when parsing expressions 63 * 64 * Revision 1.10 1994/11/07 14:28:34 saw 65 * Add thevalchk fortran call to check for expressions. 66 * Try to avoid bomb outs for bad expressions 67 saw 1.1 * 68 * Revision 1.9 1994/10/03 12:41:22 saw 69 * All "/" (division) has real result. New op "//" has integerized 70 * result. thEvalImed actually gets a double from thTestExecute. 71 * Added fortran interfaces to thEvalImed (itheval, ftheval, dtheval). 72 * 73 * Revision 1.8 1994/09/12 15:12:31 saw 74 * thGetTok was missing reset of lastop on EOL 75 * 76 * Revision 1.7 1994/08/29 20:08:10 saw 77 * Fix calculation of testscalervarname length 78 * 79 * Revision 1.6 1994/08/26 17:46:18 saw 80 * Register test scaler results 81 * 82 * Revision 1.5 1994/08/26 13:36:46 saw 83 * Add DAVAR_REPOINTOK to some flags 84 * 85 * Revision 1.4 1994/06/03 18:54:29 saw 86 * Replace stderr with STDERR 87 * 88 saw 1.1 * Revision 1.3 1993/12/02 21:33:36 saw 89 * Fully allow use of doubles in test expressions 90 * 91 * Revision 1.2 1993/11/24 21:24:54 saw 92 * thEvalImed now returns double instead of floating result. 93 * 94 * Revision 1.3 1993/09/22 17:51:06 saw 95 * Allow integer constants to be octal or hex. 96 * 97 * Revision 1.2 1993/05/11 18:00:10 saw 98 * Update header 99 * 100 */ 101 102 /* thTestParse.c 103 104 Make test result variable that are created take the type of the rhs??? 105 Add variable names to stack so that expressions can be recreated. 106 Allow constants to be hex or octal. 107 Agree on a new comment character or syntax since ! is not part 108 of expressions. 109 saw 1.1 Add unary operators to executor. Allow + to be a unary operator too. 110 111 Need to build up a linked list of test results used in a block. Don't 112 duplicate any variables. Print warning when a scaler test result is 113 reused. 114 115 */ 116 /*An argument is a variable name, an array, or a number. Numbers are not 117 allowed for test result. Arrays start at 0 if []'s are used and start 118 at 1 if ()'s are used. Arrays may only be used for test results if they 119 are already registered by the analyzer. (May add option to declare them 120 in the test package.)*/ 121 122 #include <stdio.h> 123 #include <string.h> 124 #include <math.h> | ||
125 jones 1.5 126 #define INT_MAX 2147483647 127 /* limits.h is used only to get #define INT_MAX 2147483647 128 * If you don't have limits.h, try #include <values.h> instead and then 129 * #define INT_MAX MAXINT */ 130 //#include <limits.h> 131 | ||
132 saw 1.3 #include <rpc/rpc.h> | ||
133 saw 1.1 #include "daVar.h" | ||
134 saw 1.3 #include "daVarRpc.h" 135 #include "daVarHandlers.h" | ||
136 saw 1.1 #include "th.h" 137 #include "thUtils.h" 138 #include "thTestParse.h" 139 #include "thInternal.h" 140 #include "cfortran.h" 141 | ||
142 saw 1.4 daVarStatus thTestRHandler(char *name, daVarStruct *varclass, any *retval); | ||
143 saw 1.1 144 CODE opstack[100]; /* Operator stack */ 145 CODE typstack[100]; /* Result type stack */ 146 147 typedef struct 148 { 149 char *ops; 150 int toks[3]; 151 } OPTABLE; 152 153 OPTABLE optable[] = 154 { 155 {"(",{OPLP}}, 156 {")",{OPRP}}, 157 {"[",{OPLINDEXB}}, 158 {"]",{OPRP}}, 159 {"-",{OPSUB}}, 160 {"+",{OPADD}}, 161 {"<<=",{OPISLT,OPSHL,OPISLE}}, 162 {">>=",{OPISGT,OPSHR,OPISGE}}, 163 {"==",{OPEQUAL,OPISEQUAL}}, 164 saw 1.1 {"!=",{OPNOT,OPISNOTEQUAL}}, 165 {"&&",{OPBITAND,OPLOGAND}}, 166 {"||",{OPBITOR,OPLOGOR}}, 167 {"^^",{OPBITXOR,OPLOGXOR}}, 168 {"*",{OPTIMES}}, 169 {"//",{OPDIV,OPIDIV}}, 170 {"%",{OPMOD}}, 171 {"~",{OPCOMP}}, 172 {",",{OPCOMMA}}, 173 {0,{0,0,0}}}; 174 static char *opchars=0; 175 176 /* For Q like test package format, must be in same order as type 177 types listed in typedef for thTestType. */ 178 char *testCodes[tBAD] 179 = {"GA","PA","EQ","BI","AN","IO","EO","MA","US"}; 180 181 typedef struct 182 { 183 CODE op; 184 CODE result[9]; 185 saw 1.1 } TYPETABLE; 186 187 TYPETABLE typetable[] = 188 { 189 {OPLINDEX,{0,0,0,1,1,1,2,2,2}}, /* Result is same as variable */ 190 {OPLINDEXB,{0,0,0,1,1,1,2,2,2}}, /* being indexed */ 191 {OPLINDEXP,{0,0,0,1,1,1,2,2,2}}, /* Result is same as variable */ 192 {OPLINDEXPB,{0,0,0,1,1,1,2,2,2}}, /* being indexed */ 193 {OPEQUAL,{0,0,0,1,1,1,2,2,2}}, /* Set result type to LHS type */ 194 {OPLOGOR,{0,0,0,0,0,0,0,0,0}}, /* Result is always integer */ 195 {OPLOGXOR,{0,0,0,0,0,0,0,0,0}}, 196 {OPLOGAND,{0,0,0,0,0,0,0,0,0}}, 197 {OPBITOR,{0,0,0,0,0,0,0,0,0}}, 198 {OPBITXOR,{0,0,0,0,0,0,0,0,0}}, 199 {OPBITAND,{0,0,0,0,0,0,0,0,0}}, 200 {OPISEQUAL,{0,0,0,0,0,0,0,0,0}}, 201 {OPISNOTEQUAL,{0,0,0,0,0,0,0,0,0}}, 202 {OPISLT,{0,0,0,0,0,0,0,0,0}}, 203 {OPISLE,{0,0,0,0,0,0,0,0,0}}, 204 {OPISGT,{0,0,0,0,0,0,0,0,0}}, 205 {OPISGE,{0,0,0,0,0,0,0,0,0}}, 206 saw 1.1 {OPSHL,{0,0,0,0,0,0,0,0,0}}, 207 {OPSHR,{0,0,0,0,0,0,0,0,0}}, 208 {OPADD,{0,2,2,2,2,2,2,2,2}}, /* Result is double unless both ops int */ 209 {OPSUB,{0,2,2,2,2,2,2,2,2}}, 210 {OPTIMES,{0,2,2,2,2,2,2,2,2}}, 211 {OPDIV,{2,2,2,2,2,2,2,2,2}}, /* Result always double */ 212 {OPIDIV,{0,0,0,0,0,0,0,0,0}}, /* Result always integer */ 213 {OPMOD,{0,2,2,2,2,2,2,2,2}}, 214 {OPNEG,{0,1,2,0,1,2,0,1,2}}, /* No lh operand, type = rh type */ 215 {OPNOT,{0,0,0,0,0,0,0,0,0}}, /* No lh operand, type always int */ 216 {OPCOMP,{0,0,0,0,0,0,0,0,0}}, /* No lh operand, type always int */ 217 {0,{0,0,0,0,0,0,0,0,0}}}; 218 219 INTRINSIC_FUNCTIONS intrinsic_functions[] = 220 { 221 {"abs",{0,1,2}}, 222 {"sqrt",{2,2,2}}, 223 {"exp",{2,2,2}}, 224 {"sin",{2,2,2}}, 225 {"cos",{2,2,2}}, 226 {"tan",{2,2,2}}, 227 saw 1.1 {0,{0,0,0}} 228 }; 229 char *thGetTok(char *linep, int *tokenid, char **tokstr, 230 CODE *tokval, void **tokptr, int expflag, daVarStructList **vlisthead) 231 /* Pass a pointer to the unscanned portion of the line. 232 Returns An ID code for operators, and an operand type for operands in 233 tokenid. 234 Returns the string for the operand in tokstr. (Null otherwise) 235 Returns the operand value in tokval, or in tokptr if the operand is 236 a pointer. 237 If the operand is a function, then tokenid will be pushfunction, and 238 tokval will be a the fuction id. 239 240 Function returns pointer to remainder of the line. 241 242 243 */ 244 { 245 static char string[100]; 246 static int lasttoktype=0; /* Last tok was an operator */ 247 static CODE lastop=0; 248 saw 1.1 249 char *savelinep; 250 char *stringp; 251 char *ptr,c; 252 int tindex,sindex; 253 daVarStruct *varp; 254 DAFLOAT f; 255 256 /* Build up a list of characters that can start operators */ 257 if(opchars == 0){ 258 int count=0; 259 int i; 260 261 while(optable[count++].ops != 0) ; 262 opchars = (char *) malloc(count); 263 for(i=0;i<(count-1); i++) 264 opchars[i] = optable[i].ops[0]; 265 opchars[count-1] = 0; 266 } 267 268 *tokstr = 0; 269 saw 1.1 *tokval = 0; 270 *tokptr = 0; 271 *tokenid = 0; /* Will signify an undeclared operand */ 272 273 if(!(*linep)) { 274 *tokenid = OPEOL; 275 lasttoktype = 0; 276 lastop = 0; 277 return(0); 278 } 279 savelinep = linep; 280 while(*linep == ' ' || *linep == '\t') linep++; 281 if((ptr = strchr(opchars,*linep))) { /* Operator */ 282 tindex = ptr - opchars; 283 if(lasttoktype == 0 && *linep == '-') { /* Last thing was an operator */ 284 *tokenid = OPNEG; /* So the '-' must be a negative sign */ 285 linep++; 286 } else if(lasttoktype == 0 && *linep == '+') { /* Unary plus */ 287 linep++; 288 goto operand; 289 } else if(lasttoktype == 1 && *linep == '(') { 290 saw 1.1 *tokenid = OPLINDEX; 291 linep++; 292 } else if(lasttoktype == 3 && *linep == '(') { 293 /* How will we know when the right hand operator is the closing 294 paren of the function? We don't need to know. The RHP only 295 acts to determine precedence. */ 296 *tokenid = OPLFARG; 297 linep++; 298 } else { 299 linep++; 300 *tokenid = optable[tindex].toks[0]; 301 sindex = 1; 302 if(*linep) { /* Don't search past end of line */ 303 while((c = optable[tindex].ops[sindex])) { 304 if(*linep == c) { 305 *tokenid = optable[tindex].toks[sindex]; 306 linep++; 307 break; 308 } 309 sindex++; 310 } 311 saw 1.1 } 312 } 313 /* Following two lines were before last }. */ 314 if(*tokenid == OPRP) lasttoktype = 2; /* Minus is minus after ) or ] */ 315 else lasttoktype = 0; 316 /* For OPLINDEX and OPLINDEXB, need to search ahead for matching ) or ] 317 and check if the next operator is an = not ==). If so, then we 318 need to return OPLINDEXP or OPLINDEXPB. */ 319 if(*tokenid == OPLINDEX || *tokenid == OPLINDEXB){ 320 char *p; char rc; int ccount=0; int bcount=0; 321 if(*tokenid == OPLINDEXB) rc = ']'; 322 else rc = ')'; 323 p = linep; 324 while(*p && (*p != rc || bcount || ccount)) { 325 switch(*p++) 326 { 327 case '(': ccount++; break; 328 case ')': ccount--; break; 329 case '[': bcount++; break; 330 case ']': bcount--; break; 331 default: break; 332 saw 1.1 } 333 } /* Only NULL or balanced rc terminates */ 334 if(*p++){ /* Search for = */ 335 while(*p == ' ' || *p=='\t') p++; 336 if(*p == '=' && *(p+1) != '=') { 337 *tokenid += (OPLINDEXP - OPLINDEX); 338 /* Assumes OPLINDEXBP-OPLINDEXB is the same*/ 339 } 340 } else 341 fprintf(STDERR,"thTest: Parenthesis balance problem\n"); 342 } 343 lastop = *tokenid; 344 } else { /* Operand */ | ||
345 jones 1.5 // int optype; | ||
346 saw 1.1 int isnum; 347 int efound; 348 349 operand: 350 lasttoktype = 1; 351 stringp = string; 352 /* Scan until operator or whitespace is reached */ 353 isnum = 1; efound = 0; 354 /* What a hack to check for scientific notation */ 355 while(*linep && *linep!=' ' && *linep!='\t' && !strchr(opchars,*linep)){ 356 if(*linep == 'e' || *linep == 'E') { 357 if(efound) { 358 isnum = 0; 359 } else { 360 if(stringp > string) { 361 efound=1; 362 } else { 363 isnum = 0; 364 } 365 } 366 } else if(!isdigit(*linep) && *linep != '.') isnum = 0; 367 saw 1.1 *stringp++ = *linep++; 368 } 369 if(isnum && efound) { /* Exponential, scan past last digit */ 370 if(*linep == '-' || *linep == '+') *stringp++ = *linep++; 371 while(isdigit(*linep)) { 372 *stringp++ = *linep++; 373 } 374 } 375 while(*linep == ' ' || *linep == '\t') linep++; /* Skip past whitespace */ 376 *stringp = 0; 377 *tokstr = string; 378 /* printf("token=%s\n",string);*/ 379 switch(thIDToken(string)) 380 { 381 case TOKINT: | ||
382 jones 1.6 /* Used to be %li and %ld, but that makes 8 byte result stuffed into 383 4 byte *tokval */ | ||
384 saw 1.2 if(string[0] == '0' && (string[1] == 'x' || string[1] == 'X')) { | ||
385 jones 1.6 sscanf(string,"%i",tokval); /* Treat as Hex */ | ||
386 saw 1.2 } else { | ||
387 jones 1.6 sscanf(string,"%d",tokval); /* Treat as decimal */ | ||
388 saw 1.2 } | ||
389 saw 1.1 *tokenid = OPPUSHINT; 390 break; 391 case TOKFLOAT: 392 f = atof(string); 393 *tokval = *(DAINT *)&f; /* Copy floating value */ 394 *tokenid = OPPUSHFLOAT; 395 break; 396 case TOKVAR: 397 { 398 char **classlist; 399 thOperandType optype; 400 401 optype = thGetOperandType(string,linep,lastop,0); 402 classlist = thGetClassList(optype); | ||
403 saw 1.3 /* Probably should consistently use the same class list of 404 TEST,EVENT,PARM here */ | ||
405 saw 1.1 /* If token is a result variable (and we are in non-immediate mode), and the 406 variable is an integer type, then we need to add this variable to a list 407 of variables for the current block. (Probably add real variable to 408 the list anyway. ) This will allow us to acumulate scalers. The opaque 409 pointer of each variable in the list will point to the scaler array. */ 410 411 /* First check if variable is really an intrinsic function */ 412 { 413 int ifunc; 414 ifunc = 0; 415 while(intrinsic_functions[ifunc].name) { 416 if(strcasecmp(string,intrinsic_functions[ifunc].name)==0) { 417 *tokenid = OPPUSHFUNCTION; 418 *tokval = ifunc; 419 lasttoktype = 3; 420 break; 421 } 422 ifunc++; 423 } 424 if(*tokenid) break; /* Hopefully this breaks out of case */ 425 } 426 saw 1.1 if(daVarLookupPWithClass(string,classlist,&varp) == S_SUCCESS) { 427 /* printf("Found variable %s[%s]\n",string,varp->name);*/ 428 if(varp->type == DAVARFLOAT) {/* If next operator is a ( or [ */ 429 /* printf("FLOAT ");*/ 430 /* then push pointer instead of */ 431 #define ISARRAYORLHS(x) (*x=='(' || *x=='[' || (*x=='=' && *(x+1)!='=')) 432 *tokenid = ISARRAYORLHS(linep) ? OPPUSHPFLOAT : OPPUSHFLOATP; 433 } else if(varp->type == DAVARDOUBLE){ /* value onto rpn stack */ 434 /* printf("DOUBL ");*/ 435 *tokenid = ISARRAYORLHS(linep) ? OPPUSHPDOUBLE : OPPUSHDOUBLEP; 436 } else if(varp->type == DAVARINT){ /* value onto rpn stack */ 437 /* printf("INT ");*/ 438 *tokenid = ISARRAYORLHS(linep) ? OPPUSHPINT : OPPUSHINTP; 439 } 440 else { 441 fprintf(STDERR 442 ,"thTest: Variable %s[%s] must be integer, float or double\n" 443 ,string,varp->name); 444 } 445 /* *tokval = *(DAINT *)&varp->varptr;*/ /* Get the pointer */ 446 *tokptr = varp->varptr; 447 saw 1.1 } else if(*linep=='=' && (*(linep+1)!='=')){ 448 /* Undefined variable is an unindexed result */ 449 /* For now, create an integer variable. Later figure out how 450 to make the variable the same type as the rhs */ 451 daVarStruct var; 452 var.name = (char *) malloc(strlen(classlist[0]) 453 +strlen(string)+2); 454 strcpy(var.name,classlist[0]); 455 strcat(var.name,"."); 456 strcat(var.name,string); 457 var.varptr = (void *) malloc(sizeof(DAINT)); 458 var.size = 1; 459 var.opaque = 0; | ||
460 saw 1.4 var.rhook = 0; 461 var.whook = 0; | ||
462 saw 1.1 var.type = DAVARINT; 463 var.flag = DAVAR_READONLY | DAVAR_REPOINTOK; 464 var.title = savelinep; 465 daVarRegister((int) 0,&var); /* Create test result */ 466 daVarLookupP(var.name,&varp); 467 free(var.name); 468 printf("Created test result %s\n",varp->name); 469 *tokenid = OPPUSHPINT; 470 /* *tokval = *(DAINT *)&varp->varptr;*/ 471 *tokptr = varp->varptr; 472 } /* else 473 printf("%s not found\n",string); 474 }*/ 475 /* If variable does not exist, caller will note that toktype and 476 tokval have not been set. */ 477 if(optype == otRESULT && vlisthead){ /* Don't make scalers for */ 478 thAddVarToList(vlisthead,varp); /* Variables created in */ 479 if(varp->type == DAVARINT) { /* thEvalImed */ 480 DAINT *sarray; int i; 481 if(varp->opaque == 0) { /* No scaler array yet */ 482 char *testscalervarname; 483 saw 1.1 daVarStruct *svarp; /* Pointer to scaler var struct */ 484 testscalervarname = /* Add the "scaler" attribute */ 485 (char *) malloc(strlen(varp->name)+strlen(SCALERSTR)+2); 486 strcpy(testscalervarname,varp->name); 487 strcat(testscalervarname,"."); 488 strcat(testscalervarname,SCALERSTR); 489 if(daVarLookupP(testscalervarname,&svarp) != S_SUCCESS) { 490 daVarStruct svar; 491 svar.name = testscalervarname; 492 svar.opaque = 0; | ||
493 saw 1.4 svar.rhook = 0; 494 svar.whook = 0; | ||
495 saw 1.1 svar.type = DAVARINT; 496 svar.flag = DAVAR_READONLY | DAVAR_REPOINTOK; 497 svar.varptr = (void *) malloc(varp->size*sizeof(DAINT)); 498 svar.size = varp->size; 499 /* Actually not OK to repoint, but this says CTP made it */ 500 svar.title = varp->name; 501 daVarRegister((int) 0, &svar); 502 daVarLookupP(svar.name,&svarp); 503 } 504 varp->opaque = (DAINT *) svarp->varptr; 505 varp->rhook = thTestRHandler; 506 free(testscalervarname); 507 } 508 sarray = varp->opaque; 509 for(i=0;i<varp->size;i++) 510 sarray[i] = 0; 511 } 512 } 513 } 514 break; 515 default: 516 saw 1.1 fprintf(STDERR,"thTest: Error understanding %s\n",string); 517 break; 518 } 519 /* printf("token = %x\n",*tokenid);*/ 520 lastop = 0; 521 } 522 while(*linep == ' ' || *linep == '\t') linep++; /* Skip whitespace */ 523 return(linep); 524 } 525 526 527 char **thGetClassList(thOperandType optype) 528 { 529 static char *explist[]={PARMSTR,EVENTSTR,TESTSTR,0}; /* Immediate expressions */ 530 static char *loglist[]={TESTSTR,PARMSTR,EVENTSTR,0}; /* Logical operand */ 531 static char *numlist[]={EVENTSTR,PARMSTR,TESTSTR,0}; /* Operand is a value */ 532 static char *resultlistp[]={TESTSTR,EVENTSTR,PARMSTR,0}; /* Operand is a result */ 533 | ||
534 saw 1.3 #define ALWAYSTESTFIRST 535 #ifdef ALWAYSTESTFIRST 536 return(resultlistp); 537 #else | ||
538 saw 1.1 switch(optype) 539 { 540 case otIMMED: 541 return(explist); 542 case otLOGIC: 543 return(loglist); 544 case otVALUE: 545 return(numlist); 546 case otRESULT: 547 return(resultlistp); 548 } | ||
549 saw 1.3 #endif | ||
550 saw 1.1 } 551 552 thOperandType thGetOperandType(char *soperand, char *rest, CODE lastop, 553 int expflag) 554 { 555 if(expflag) 556 return(otIMMED); 557 else if(lastop == OPNOT) 558 return(otLOGIC); 559 else if(lastop != 0 && (lastop != OPLOGOR) 560 && (lastop != OPLOGAND) && (lastop != OPLOGXOR) 561 && (lastop != OPEQUAL) && (lastop != OPCOMMA) 562 && (lastop != OPLP)) 563 return(otVALUE); 564 else { 565 /* This is really ugly code to determine if the operand 566 is a result, logical operand, or numerical operand from the 567 surrounding operators. The last operator is known, but it must 568 search ahead for the next operator. This code should be burried 569 in a subroutine. */ 570 571 saw 1.1 char *p; 572 p = rest; 573 if(*p == '(' || *p == '[') { 574 int ccount=0; int bcount=0; 575 if(*p++ == '(') ccount++; else bcount++; 576 while(*p && (bcount || ccount)){ 577 /* printf("%c(%d,%d)\n",*p,ccount,bcount);*/ 578 switch(*p++) { 579 case '(': ccount++; break; case ')': ccount--; break; 580 case '[': bcount++; break; case ']': bcount--; break; 581 default: break; 582 } 583 } 584 /* printf("pos=%c, %d %d ",*p,ccount,bcount);*/ 585 } 586 while(*p == ' ' || *p =='\t') p++; 587 #define ISLOG(x,y) (*x==y && *(x+1)==y) 588 /* printf(", Nextchar=%c: ",*p);*/ 589 if(*p=='=' && *(p+1)!='=') { 590 return(otRESULT); 591 } else if((ISLOG(p,'|') || ISLOG(p,'&') || ISLOG(p,'^') 592 saw 1.1 || *p=='\0' || *p==',' || *p == ')')) 593 return(otLOGIC); 594 } 595 return(otVALUE); 596 } 597 598 CODE thGetResultType(CODE operator, CODE leftoptype, CODE rightoptype) 599 { 600 /* For a given operator, determine the data type of the result a given 601 combination of the types of the lh and rh operands. 602 Assumes that only types 0, 1, or 2 are allowed. */ 603 604 int lrindex; 605 int i; 606 607 if(leftoptype < 0 || leftoptype > 2 || rightoptype < 0 || rightoptype > 2) { 608 fprintf(STDERR,"thTest: Illegal operand type %x %x\n",leftoptype,rightoptype); 609 return(0); 610 } 611 lrindex = (leftoptype * 3) + rightoptype; 612 for(i=0; typetable[i].op; i++) { /* Do Linear search for the operator */ 613 saw 1.1 if(operator == typetable[i].op) { 614 return(typetable[i].result[lrindex]); 615 } 616 } 617 fprintf(STDERR,"Operator %x not found in result type table\n",operator); 618 return(0); 619 } 620 | ||
621 saw 1.3 thStatus thEvalImed(char *line, DADOUBLE *d, DAINT *i) | ||
622 saw 1.1 /* ImmedOBiately evaluate the expression in line. Will internally evaluate to 623 a float, and then pass back both the float and interized values. */ 624 { 625 CODEPTR codehead, codenext, codelimit, codelastop; 626 int codesize; 627 #define RDOUBLE 628 #ifdef RDOUBLE 629 double result; 630 #else 631 float result; /* Should change to double */ 632 #endif 633 thStatus retcode; 634 635 /* printf("%s=",line);*/ 636 codesize = 10+2*strlen(line); 637 codehead = codenext = (CODEPTR) malloc(sizeof(CODE)*codesize); 638 codelimit = codehead + codesize; 639 #ifdef RDOUBLE 640 *codenext++ = OPPUSHPDOUBLE; 641 #ifdef USEMEMCPY 642 { 643 saw 1.1 void *resultp; 644 resultp = &result; 645 memcpy(((void **)codenext)++, (void *) &resultp, sizeof(void *)); 646 } 647 #else | ||
648 jones 1.5 *((void **) codenext) = (void *) &result; /*phil*/ 649 codenext = (CODEPTR) (void **) ((void **)codenext +1); | ||
650 saw 1.1 #endif 651 /* printf("%x\n",codenext);*/ 652 #else 653 *codenext++ = OPPUSHPFLOAT; /* Should change to double */ 654 *((void **) codenext)++ = (void *) &result; 655 #endif 656 retcode = S_SUCCESS; 657 if(thBookaTest(line,&codehead,&codenext,&codelimit,&codelastop,0)!=S_SUCCESS) { 658 fprintf(STDERR,"Failure interpreting expression |%s|\n",line); 659 result = 0.0; 660 retcode = S_FAILURE; 661 } else { 662 int exptype; 663 CODE lastop; 664 #if 0 665 printf("%x-%x=%d\n",codenext,codehead,codenext-codehead); 666 { 667 CODEPTR code; 668 for(code=codehead;code < codenext; code++) 669 if(code==codelastop) printf("* %x\n",*code); 670 else printf(" %x\n",*code); 671 saw 1.1 } 672 #endif 673 codenext = codelastop; 674 exptype = *codenext++ & OPRESTYPEMASK; 675 lastop = *codelastop & OPCODEMASK; 676 if(lastop == OPPUSHPINT || lastop == OPPUSHINTP) { | ||
677 jones 1.5 codenext = (CODEPTR) (DAINT **) ((DAINT **)codenext + 1);/*phil*/ | ||
678 saw 1.1 } else if(lastop == OPPUSHINT) { 679 if(exptype == OPRDOUBLE) { | ||
680 jones 1.5 codenext = (CODEPTR) (DADOUBLE **) ((DADOUBLE **)codenext + 1);/*phil*/ | ||
681 saw 1.1 } else { /* Assume ints, floats have size */ | ||
682 jones 1.6 codenext = (CODEPTR) (DAINT *) ((DAINT *)codenext + 1);/*phil*/ | ||
683 saw 1.1 } 684 } 685 #ifdef RDOUBLE 686 *codenext++ = OPEQUAL | 0x202 | (exptype<<4); 687 #else 688 *codenext++ = OPEQUAL | 0x101 | (exptype<<4); 689 #endif 690 #ifdef RDOUBLE 691 *codenext++ = OPEOL | (OPRDOUBLE<<4); 692 #else 693 *codenext++ = OPEOL; 694 #endif 695 if(thExecuteCode("IMMED",codehead,codenext)!=S_SUCCESS){ 696 fprintf(STDERR,"Failure evaluating expression |%s|\n",line); 697 result = 0.0; 698 retcode = S_FAILURE; 699 } 700 } 701 /* printf("%f\n",result);*/ 702 free(codehead); 703 if(d) *d = result; 704 saw 1.1 if(i) { | ||
705 jones 1.5 if(result>=INT_MAX || result <=-INT_MAX) { | ||
706 saw 1.1 if(retcode==S_SUCCESS) 707 retcode=S_INTOVF; 708 } else { 709 *i = floatToLong(result); 710 } 711 } 712 return(retcode); 713 } 714 715 thStatus thBookaTest(char *line, CODEPTR *codeheadp, CODEPTR *codenextp, 716 CODEPTR *codelimitp, CODEPTR *codelastop, daVarStructList **vlisthead) 717 /* if expflag != 0, still treat as an expression even if there is no 718 equal sign in the line. 719 Return codes: 720 S_SUCCESS = Line OK 721 S_FAILURE = Line not executable 722 */ 723 { 724 /* int type;*/ 725 char *args[20]; 726 int nargs; 727 saw 1.1 thTokenType toktyp; 728 daVarStruct var, *varp; 729 thTestType test_type; 730 int forcefloat; 731 int iarg; 732 char *token; 733 CODEPTR codenext; 734 int index; /* Used for index into arrays */ 735 thStatus status; 736 int expflag; 737 738 if(codelastop) expflag = 1; else expflag = 0; 739 status = S_SUCCESS; 740 if(*codenextp + 2*strlen(line) > *codelimitp) { 741 CODEPTR src,dst,newhead; 742 int newsize; 743 /* printf("Increasing the size of the code stack from %d ", 744 *codelimitp-*codeheadp);*/ 745 src = *codeheadp; 746 newsize = max((*codelimitp-*codeheadp)+CODEGROWSIZE 747 ,(*codenextp-*codeheadp)+2*strlen(line)); 748 saw 1.1 newhead = dst = (CODEPTR) malloc(sizeof(CODE)*newsize); 749 while(src < *codenextp) *dst++ = *src++; 750 if(*codeheadp) free(*codeheadp); 751 *codelimitp = newhead + newsize; 752 *codeheadp = newhead; 753 *codenextp = *codenextp + (dst - src); 754 755 /*printf("to %d, using %d\n",*codelimitp-*codeheadp,*codenextp - *codeheadp);*/ 756 } 757 codenext = *codenextp; 758 759 /* printf("Booking \"%s\"\n",line);*/ 760 if(strchr(line,'=')||expflag) { 761 char *linep; 762 int TOKEN,TOKCOMP; 763 char *tokstr; CODE tokval; 764 void *tokptr; 765 CODE *osp, *tsp, opcode; 766 CODE rightoptype,leftoptype,resultoptype; 767 768 osp = opstack; /* Stack of pending operators */ 769 saw 1.1 *osp = '\0'; 770 771 tsp = typstack; /* Stack of Current result type */ 772 /* Like the stack in the executor but only */ 773 /* contains the data types */ 774 linep = line; 775 do { 776 /* Get tokens until there are no more (last token will be OPEOL) */ 777 linep = thGetTok(linep,&TOKEN, &tokstr, &tokval, &tokptr, expflag, vlisthead); 778 if(tokstr) { /* Operand */ 779 /* printf("Operand %s |",tokstr);*/ 780 if(codelastop) *codelastop = codenext; /* HACK for thImmed: Save ptr to last operator */ 781 if(TOKEN) { 782 if(tokptr == 0) { /* Value operand - 4 bytes */ 783 *codenext++ = TOKEN; /* String not put on stack at moment */ 784 *codenext++ = tokval; 785 } else { /* Pointer operand - maybe 8 bytes */ 786 *codenext++ = TOKEN; 787 #ifdef USEMEMCPY 788 memcpy(((void **)codenext)++,&tokptr,sizeof(void *)); 789 #else | ||
790 jones 1.5 *(void **)codenext = tokptr;/*phil*/ 791 codenext = (CODEPTR) (void **) ((void **)codenext +1); | ||
792 saw 1.1 #endif 793 } 794 /* If TOKEN is push function, then tokval is an index into a list of 795 functions. We put this index on tsp instead of the result type. */ 796 if(TOKEN==OPPUSHFUNCTION) { 797 *tsp++ = tokval; 798 } else { 799 *tsp++ = TOKEN & OPRESTYPEMASK; 800 } 801 } else { 802 fprintf(STDERR,"thTest: Unregistered variable %s\n",tokstr); 803 status = S_TH_UNREG; 804 *codenext++ = OPPUSHINT; 805 *codenext++ = 0; 806 *tsp++ = OPPUSHINT & OPRESTYPEMASK; 807 } 808 } else { /* Operator */ 809 switch(TOKEN) 810 { 811 case 0: 812 fprintf(STDERR,"thTest: Bad token\n"); 813 saw 1.1 return(S_FAILURE); 814 break; 815 case OPLP: 816 *++osp = TOKEN; 817 break; 818 default: 819 /* printf("OSP:"); 820 {CODE *sp; for(sp=opstack;sp<=osp;sp++) 821 printf("%x:",*sp);} 822 printf("\n"); 823 */ 824 /* Generate code for all operators of equal or higher precedence 825 that are pending on the operator stack. */ 826 if((TOKEN & OPGROUPMASK) == OPLINDEXGROUP) 827 TOKCOMP = 0xFFFFFFF; /* Nothing higher in precedence */ 828 else 829 TOKCOMP = TOKEN & OPPRECMASK; 830 while((*osp & OPPRECMASK) >= TOKCOMP){ 831 /* if((*osp & OPPRECMASK) == OPLINDEX){*/ 832 if((*osp & OPGROUPMASK) == OPLINDEXGROUP){ 833 if(TOKEN == OPRP) { 834 saw 1.1 if(*osp == OPLFARG) TOKEN = OPRFARG; 835 else TOKEN = OPRINDEX; /* Break from case */ 836 } 837 TOKCOMP = 0xFFFFFFF; /* Terminate osp rundown */ 838 } 839 rightoptype = *--tsp; 840 leftoptype = ((*osp & OPPRECMASK) == OPUNARY) ? 0 : (*--tsp); 841 /* If the Operator is "evaluate function", we need to find out 842 what the function is so that we can get the correct 843 result type. leftoptype should be an index into 844 "intrinsic_functions". We can use that and rightoptype 845 to look up the resulttype. */ 846 if(*osp==OPLFARG) { 847 resultoptype = 848 intrinsic_functions[leftoptype].result[rightoptype]; 849 } else { 850 resultoptype = thGetResultType(*osp,leftoptype,rightoptype); 851 } 852 opcode = *osp--; 853 opcode |= (leftoptype << 8) | (rightoptype << 4) 854 | resultoptype; 855 saw 1.1 if(codelastop) if((opcode&&OPCODEMASK) !=OPEOL) *codelastop = codenext; /* HACK for thImmed: Save ptr to last operator */ 856 *codenext++ = opcode; 857 *tsp++ = resultoptype; /* Keep a rpn stack of the data type */ 858 } 859 if(TOKEN == OPRINDEX || TOKEN == OPRFARG) break; /* No clean up needed */ 860 861 if(TOKEN == OPRP) { 862 if(*osp == OPLP) osp--; /* ) removes matching ( */ 863 else { 864 fprintf(STDERR,"Right paren not matched by left\n"); 865 return(S_FAILURE); 866 } 867 } else if(TOKEN == OPEOL || TOKEN == OPCOMMA) { 868 if(codelastop) if(TOKEN==OPCOMMA) *codelastop = codenext; /* HACK for thImmed: Save ptr to last operator */ 869 *codenext++ = TOKEN | (*--tsp) << 4; /* Leave type in Right type field */ 870 } else { 871 *++osp = TOKEN; 872 } 873 break; 874 } 875 } 876 saw 1.1 /* Token processed */ 877 } while (linep); 878 /* Check that stacks are OK. Need to add some clean up of allocated memory. */ 879 if(tsp != typstack) { 880 fprintf(STDERR,"%d items left on type stack\n",tsp-typstack); 881 return(S_FAILURE); 882 } 883 if(osp != opstack) { 884 fprintf(STDERR,"%d items left on operand stack\n",osp-opstack); 885 return(S_FAILURE); 886 } 887 } else { /* Old style test lines */ 888 int i; 889 nargs = thCommas(line,args); 890 for(i=0;i<nargs;i++){ 891 args[i] = thSpaceStrip(args[i]); /* Remove all space from the argument */ 892 } 893 894 if(nargs <= 1) return(S_FAILURE); 895 896 { /* Interpret the test type. */ 897 saw 1.1 898 for(test_type=0;test_type<tBAD;test_type++){ 899 if(testCodes[test_type][0] == toupper(args[1][0]) && 900 testCodes[test_type][1] == toupper(args[1][1])) break; 901 } 902 if(test_type == tBAD) return(S_FAILURE); 903 /* printf("%s\n",testCodes[test_type]);*/ 904 } 905 if(test_type == tGATE || test_type == tEQ) { 906 forcefloat = 1; 907 } else forcefloat = 0; 908 for(iarg=2;iarg<nargs;iarg++){ 909 DAFLOAT f; /* Should do double here */ 910 token = args[iarg]; 911 toktyp = thIDToken(token); 912 switch((toktyp = thIDToken(token))) 913 { 914 case TOKINT: 915 *codenext++ = PUSHI; 916 if(forcefloat) { 917 f = atof(token); 918 saw 1.1 *codenext++ = *(DAINT *)&f; 919 } else { 920 DAINT i; | ||
921 jones 1.6 /* Used to be %li and %ld, but that makes 8 byte result 922 stuffed into 4 byte i */ | ||
923 saw 1.2 if(token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) { | ||
924 jones 1.6 sscanf(token,"%i",&i); /* Treat as Hex */ | ||
925 saw 1.2 } else { | ||
926 jones 1.6 sscanf(token,"%d",&i); /* Treat as decimal */ | ||
927 saw 1.2 } | ||
928 saw 1.1 *codenext++ = i; 929 } 930 break; 931 case TOKFLOAT: /* Should Do all floats as doubles */ 932 *codenext++ = PUSHI; 933 if(forcefloat) { 934 f = atof(token); 935 *codenext++ = *(DAINT *)&f; 936 } else { 937 *codenext++ = (DAINT) floatToLong(atof(token)); 938 } 939 break; 940 case TOKARRAY: 941 case TOKVAR: 942 { 943 char *p; int index; char leftp; 944 if(toktyp == TOKARRAY) { 945 p = thTokenArray(token,&index); 946 leftp = *p; *p = 0; /* Save ( or [ then null terminate */ 947 } else 948 index = 0; 949 saw 1.1 if(daVarLookup(token,&var)!=S_SUCCESS) { 950 fprintf(STDERR,"(thTest) %s not registered\n",token); 951 *codenext++ = PUSHI; 952 if(forcefloat) { 953 f = 0.0; 954 *codenext++ = *(DAINT *)&f; 955 } else 956 *codenext++ = 0; 957 } else { 958 if(forcefloat) 959 if(var.type == DAVARINT) 960 *codenext++ = PUSHITOFS; /* Push converting to float and skip */ 961 else if(var.type == DAVARFLOAT) 962 *codenext++ = PUSHS; 963 else 964 *codenext++ = PUSHI; /* Push immediate */ 965 else 966 if(var.type == DAVARINT) 967 *codenext++ = PUSHS; /* Push and skip */ 968 else if(var.type == DAVARFLOAT) 969 *codenext++ = PUSHFTOIS; 970 saw 1.1 else 971 *codenext++ = PUSHI; /* Push immediate */ 972 if(toktyp == TOKARRAY) 973 *p = leftp; 974 if(var.type == DAVARINT || var.type == DAVARFLOAT) { | ||
975 jones 1.5 *(void **)codenext = ((DAINT *) var.varptr+index);/*phil*/ 976 codenext = (CODEPTR) (void **) ((void **)codenext + 1); | ||
977 saw 1.1 *((void **)codenext) = (void *) malloc(sizeof(token)+1); | ||
978 jones 1.5 strcpy((char *) *(void **)codenext,token); 979 codenext = (CODEPTR) (void **) ((void **)codenext + 1); | ||
980 saw 1.1 } else { 981 if(forcefloat) { 982 f = 0.0; 983 *codenext++ = *(DAINT *)&f; 984 } else 985 *codenext++ = 0; 986 } 987 } 988 } 989 break; 990 } 991 } 992 *codenext++ = test_type; /* Operation to do on pushed args */ 993 *codenext++ = nargs-2; /* # of args pushed on stack for this op */ 994 995 /* Now push test result on stack */ 996 *codenext++ = POPS; 997 998 token = args[0]; 999 toktyp = thIDToken(token); 1000 index = 0; 1001 saw 1.1 switch((toktyp = thIDToken(token))) 1002 { 1003 case TOKINT: 1004 case TOKFLOAT: 1005 fprintf(STDERR,"(thTest) Test result must be a variable name\n"); 1006 return(S_FAILURE); /* No test is added to program */ 1007 case TOKARRAY: 1008 /* First check if variable with index has been already registered 1009 perhaps from a previous booking of histograms */ 1010 if(daVarLookup(token,&var) != S_SUCCESS){ 1011 char *p; char leftp; 1012 p = thTokenArray(token,&index); 1013 leftp = *p; *p = 0; /* Save ( or [ then null terminate */ 1014 if(daVarLookup(token,&var) != S_SUCCESS){ 1015 fprintf(STDERR, 1016 "(thTest) Arrays %s must be registered\n",token); 1017 return(S_FAILURE); 1018 } 1019 *p = leftp; /* Restore the left ( or [ */ 1020 if(index >= var.size) { 1021 fprintf(STDERR, 1022 saw 1.1 "(thTest) Array size for %s exceeded\n",token); 1023 return(S_FAILURE); 1024 } 1025 if(var.type != DAVARINT) { 1026 fprintf(STDERR, 1027 "(thTest) Array %s must be of integer*4\n",token); 1028 return(S_FAILURE); 1029 } 1030 var.varptr = (DAINT *) var.varptr + index; 1031 var.name = token; 1032 var.opaque = 0; 1033 } 1034 var.title = token; /* Eventually be the input line */ 1035 break; 1036 case TOKVAR: 1037 if(daVarLookup(token,&var)!=S_SUCCESS) { 1038 var.name = token; 1039 var.varptr = (void *) malloc(sizeof(DAINT)); 1040 var.opaque = 0; | ||
1041 saw 1.4 var.rhook = 0; 1042 var.whook = 0; | ||
1043 saw 1.1 var.type = DAVARINT; 1044 var.flag = DAVAR_READONLY | DAVAR_REPOINTOK; 1045 /* Do I need to set the size to 1 here??? */ 1046 } 1047 var.title = token; 1048 break; 1049 } 1050 daVarRegister((int) 0, &var); /* Create or replace variable */ | ||
1051 jones 1.5 *(void **)codenext = ((DAINT *) var.varptr);/*phil*/ 1052 codenext = (CODEPTR) (void **) ((void **)codenext + 1); | ||
1053 saw 1.1 /* Save the token string for future reference */ | ||
1054 saw 1.2 *((void **)codenext) = ((void *) malloc(strlen(token)+1)); | ||
1055 jones 1.5 strcpy((char *) *(void **)codenext,token); 1056 codenext = (CODEPTR) (void **) ((void **)codenext + 1); | ||
1057 saw 1.1 } 1058 *codenextp = codenext; 1059 return(status); 1060 1061 } | ||
1062 saw 1.3 int thevalchk_(char *A1,unsigned C1) | ||
1063 saw 1.1 /* Check if an expression is valid. Return's zero if valid */ 1064 { | ||
1065 saw 1.3 int A0; | ||
1066 saw 1.1 char *B1; 1067 thStatus status; 1068 1069 status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1: 1070 (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0' 1071 ,kill_trailing(B1,' ')),0,0); 1072 if(B1) free(B1); 1073 return(status); 1074 } 1075 | ||
1076 saw 1.3 int itheval_(char *A1,unsigned C1) | ||
1077 saw 1.1 { | ||
1078 saw 1.3 int A0; | ||
1079 saw 1.1 char *B1; 1080 DAINT i; 1081 double d; 1082 thStatus status; 1083 1084 status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1: 1085 (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0' 1086 ,kill_trailing(B1,' ')),0,&i); 1087 if(B1) free(B1); 1088 return i; 1089 } 1090 double dtheval_(char *A1,unsigned C1) 1091 { 1092 char *B1; 1093 double d; 1094 thStatus status; 1095 1096 status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1: 1097 (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0' 1098 ,kill_trailing(B1,' ')),&d,0); 1099 if(B1) free(B1); 1100 saw 1.1 return d; 1101 } 1102 float ftheval_(char *A1,unsigned C1) 1103 { 1104 char *B1; 1105 DAINT i; 1106 double d; 1107 float f; 1108 thStatus status; 1109 1110 status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1: 1111 (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0' 1112 ,kill_trailing(B1,' ')),&d,0); 1113 if(B1) free(B1); 1114 f = d; 1115 return f; | ||
1116 saw 1.3 } 1117 | ||
1118 saw 1.4 daVarStatus thTestRHandler(char *name, daVarStruct *varclass, any *retval) | ||
1119 saw 1.3 /* The default Read handler */ 1120 { 1121 daVarStruct *varp; 1122 char *attribute; 1123 daVarStatus status; 1124 int index; 1125 1126 status = daVarAttributeFind(name, varclass, &varp, &attribute, &index); 1127 status = daVarRegRatr(varp, attribute, index, retval); 1128 if(status == S_SUCCESS) { 1129 if(strcasecmp(attribute,DAVAR_RATR) == 0){ 1130 retval->any_u.s = realloc(retval->any_u.s,strlen(retval->any_u.s) 1131 +strlen(TH_SCALER) + 2); 1132 strcat(retval->any_u.s,TH_SCALER); 1133 strcat(retval->any_u.s,"\n"); 1134 } 1135 } else { 1136 if(strcasecmp(attribute,TH_SCALER) == 0){ 1137 int i; 1138 if(varp->opaque){ 1139 retval->valtype = DAVARINT_RPC; 1140 saw 1.3 if(index == DAVAR_NOINDEX) { 1141 retval->any_u.i.i_len = varp->size; 1142 retval->any_u.i.i_val = (int *) malloc(varp->size*sizeof(int)); 1143 for(i=0;i<varp->size;i++) { 1144 retval->any_u.i.i_val[i] = ((DAINT *)varp->opaque)[i]; 1145 } 1146 } else { 1147 retval->any_u.i.i_len = 1; 1148 retval->any_u.i.i_val = (int *) malloc(sizeof(int)); 1149 retval->any_u.i.i_val[0] = ((DAINT *)varp->opaque)[index]; 1150 } 1151 } else { 1152 retval->valtype = DAVARERROR_RPC; 1153 retval->any_u.error = S_SUCCESS; 1154 } 1155 } 1156 } 1157 /* A special handler would check more attributes if status != SUCCESS */ | ||
1158 saw 1.4 return(status); | ||
1159 saw 1.1 } |
Analyzer/Replay: Mark Jones, Documents: Stephen Wood |
Powered by ViewCVS 0.9.2-cvsgraph-1.4.0 |