1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <errno.h>
5
6 #include "commonlib.h"
7 #include "lp_lib.h"
8 #include "lp_report.h"
9 #include "ini.h"
10
11 typedef int (__WINAPI int_get_function)(lprec *lp);
12 typedef long (__WINAPI long_get_function)(lprec *lp);
13 typedef MYBOOL (__WINAPI MYBOOL_get_function)(lprec *lp);
14 typedef REAL (__WINAPI REAL_get_function)(lprec *lp);
15 typedef void (__WINAPI int_set_function)(lprec *lp, int value);
16 typedef void (__WINAPI long_set_function)(lprec *lp, long value);
17 typedef void (__WINAPI MYBOOL_set_function)(lprec *lp, MYBOOL value);
18 typedef void (__WINAPI REAL_set_function)(lprec *lp, REAL value);
19
20 #define intfunction 1
21 #define longfunction 2
22 #define MYBOOLfunction 3
23 #define REALfunction 4
24
25 #define setvalues(values, basemask) values, sizeof(values) / sizeof(*values), basemask
26 #define setNULLvalues NULL, 0, 0
27 #define setvalue(value) value, #value
28 #define setintfunction(get_function, set_function) get_function, set_function, intfunction
29 #define setlongfunction(get_function, set_function) (int_get_function *) get_function, (int_set_function *) set_function, longfunction
30 #define setMYBOOLfunction(get_function, set_function) (int_get_function *) get_function, (int_set_function *) set_function, MYBOOLfunction
31 #define setREALfunction(get_function, set_function) (int_get_function *) get_function, (int_set_function *) set_function, REALfunction
32
33 #define WRITE_COMMENTED 0
34 #define WRITE_ACTIVE 1
35
36 struct _values {
37 int value;
38 char *svalue;
39 };
40
41 struct _functions {
42 char *par; /* name of parameter in ini file */
43 union {
44 int_get_function *int_get_function; /* set via setintfunction */
45 long_get_function *long_get_function; /* set via setlongfunction */
46 MYBOOL_get_function *MYBOOL_get_function; /* set via setMYBOOLfunction */
47 REAL_get_function *REAL_get_function; /* set via setREALfunction */
48 } get_function;
49 union {
50 int_set_function *int_set_function; /* set via setintfunction */
51 long_set_function *long_set_function; /* set via setlongfunction */
52 MYBOOL_set_function *MYBOOL_set_function; /* set via setMYBOOLfunction */
53 REAL_set_function *REAL_set_function; /* set via setREALfunction */
54 } set_function;
55 int type; /* set via set*function */
56 struct _values *values; /* set via setvalues to a structure of _values */
57 int elements; /* or via setNULLvalues if the value is shown as is */
58 unsigned int basemask;
59 int mask; /* WRITE_ACTIVE or WRITE_COMMENTED */
60 };
61
62 static struct _values anti_degen[] =
63 {
64 { setvalue(ANTIDEGEN_NONE) },
65 { setvalue(ANTIDEGEN_FIXEDVARS) },
66 { setvalue(ANTIDEGEN_COLUMNCHECK) },
67 { setvalue(ANTIDEGEN_STALLING) },
68 { setvalue(ANTIDEGEN_NUMFAILURE) },
69 { setvalue(ANTIDEGEN_LOSTFEAS) },
70 { setvalue(ANTIDEGEN_INFEASIBLE) },
71 { setvalue(ANTIDEGEN_DYNAMIC) },
72 { setvalue(ANTIDEGEN_DURINGBB) },
73 { setvalue(ANTIDEGEN_RHSPERTURB) },
74 { setvalue(ANTIDEGEN_BOUNDFLIP) },
75 };
76
77 static struct _values basiscrash[] =
78 {
79 { setvalue(CRASH_NONE) },
80 /* { setvalue(CRASH_NONBASICBOUNDS) }, */ /* not yet implemented */
81 { setvalue(CRASH_MOSTFEASIBLE) },
82 { setvalue(CRASH_LEASTDEGENERATE) },
83 };
84
85 static struct _values bb_floorfirst[] =
86 {
87 { setvalue(BRANCH_CEILING) },
88 { setvalue(BRANCH_FLOOR) },
89 { setvalue(BRANCH_AUTOMATIC) },
90 };
91
92 static struct _values bb_rule[] =
93 {
94 { setvalue(NODE_FIRSTSELECT) },
95 { setvalue(NODE_GAPSELECT) },
96 { setvalue(NODE_RANGESELECT) },
97 { setvalue(NODE_FRACTIONSELECT) },
98 { setvalue(NODE_PSEUDOCOSTSELECT) },
99 { setvalue(NODE_PSEUDONONINTSELECT) },
100 { setvalue(NODE_PSEUDORATIOSELECT) },
101 { setvalue(NODE_USERSELECT) },
102 { setvalue(NODE_WEIGHTREVERSEMODE) },
103 { setvalue(NODE_BRANCHREVERSEMODE) },
104 { setvalue(NODE_GREEDYMODE) },
105 { setvalue(NODE_PSEUDOCOSTMODE) },
106 { setvalue(NODE_DEPTHFIRSTMODE) },
107 { setvalue(NODE_RANDOMIZEMODE) },
108 { setvalue(NODE_GUBMODE) },
109 { setvalue(NODE_DYNAMICMODE) },
110 { setvalue(NODE_RESTARTMODE) },
111 { setvalue(NODE_BREADTHFIRSTMODE) },
112 { setvalue(NODE_AUTOORDER) },
113 { setvalue(NODE_RCOSTFIXING) },
114 { setvalue(NODE_STRONGINIT) },
115 };
116
117 static struct _values improve[] =
118 {
119 { setvalue(IMPROVE_NONE) },
120 { setvalue(IMPROVE_SOLUTION) },
121 { setvalue(IMPROVE_DUALFEAS) },
122 { setvalue(IMPROVE_THETAGAP) },
123 { setvalue(IMPROVE_BBSIMPLEX) },
124 };
125
get_mip_gap_abs(lprec * lp)126 static REAL __WINAPI get_mip_gap_abs(lprec *lp)
127 {
128 return(get_mip_gap(lp, TRUE));
129 }
130
get_mip_gap_rel(lprec * lp)131 static REAL __WINAPI get_mip_gap_rel(lprec *lp)
132 {
133 return(get_mip_gap(lp, FALSE));
134 }
135
set_mip_gap_abs(lprec * lp,REAL mip_gap)136 static void __WINAPI set_mip_gap_abs(lprec *lp, REAL mip_gap)
137 {
138 set_mip_gap(lp, TRUE, mip_gap);
139 }
140
set_mip_gap_rel(lprec * lp,REAL mip_gap)141 static void __WINAPI set_mip_gap_rel(lprec *lp, REAL mip_gap)
142 {
143 set_mip_gap(lp, FALSE, mip_gap);
144 }
145
146 static struct _values pivoting[] =
147 {
148 { setvalue(PRICER_FIRSTINDEX) },
149 { setvalue(PRICER_DANTZIG) },
150 { setvalue(PRICER_DEVEX) },
151 { setvalue(PRICER_STEEPESTEDGE) },
152 { setvalue(PRICE_PRIMALFALLBACK) },
153 { setvalue(PRICE_MULTIPLE) },
154 { setvalue(PRICE_PARTIAL) },
155 { setvalue(PRICE_ADAPTIVE) },
156 { setvalue(PRICE_RANDOMIZE) },
157 { setvalue(PRICE_AUTOPARTIAL) },
158 { setvalue(PRICE_LOOPLEFT) },
159 { setvalue(PRICE_LOOPALTERNATE) },
160 { setvalue(PRICE_HARRISTWOPASS) },
161 { setvalue(PRICE_TRUENORMINIT) },
162 };
163
164 static struct _values presolving[] =
165 {
166 { setvalue(PRESOLVE_NONE) },
167 { setvalue(PRESOLVE_ROWS) },
168 { setvalue(PRESOLVE_COLS) },
169 { setvalue(PRESOLVE_LINDEP) },
170 { setvalue(PRESOLVE_AGGREGATE) },
171 { setvalue(PRESOLVE_SPARSER) },
172 { setvalue(PRESOLVE_SOS) },
173 { setvalue(PRESOLVE_REDUCEMIP) },
174 { setvalue(PRESOLVE_KNAPSACK) },
175 { setvalue(PRESOLVE_ELIMEQ2) },
176 { setvalue(PRESOLVE_IMPLIEDFREE) },
177 { setvalue(PRESOLVE_REDUCEGCD) },
178 { setvalue(PRESOLVE_PROBEFIX) },
179 { setvalue(PRESOLVE_PROBEREDUCE) },
180 { setvalue(PRESOLVE_ROWDOMINATE) },
181 { setvalue(PRESOLVE_COLDOMINATE) },
182 { setvalue(PRESOLVE_MERGEROWS) },
183 { setvalue(PRESOLVE_IMPLIEDSLK) },
184 { setvalue(PRESOLVE_COLFIXDUAL) },
185 { setvalue(PRESOLVE_BOUNDS) },
186 { setvalue(PRESOLVE_DUALS) },
187 { setvalue(PRESOLVE_SENSDUALS) },
188 };
189
STRLWR(char * str)190 static char *STRLWR(char *str)
191 {
192 char *ptr;
193
194 for(ptr = str; *ptr; ptr++)
195 *ptr = (char) tolower((unsigned char) *ptr);
196
197 return(str);
198 }
199
STRUPR(char * str)200 static char *STRUPR(char *str)
201 {
202 char *ptr;
203
204 for(ptr = str; *ptr; ptr++)
205 *ptr = (char) toupper((unsigned char) *ptr);
206
207 return(str);
208 }
209
set_presolve1(lprec * lp,int do_presolve)210 static void __WINAPI set_presolve1(lprec *lp, int do_presolve)
211 {
212 set_presolve(lp, do_presolve, get_presolveloops(lp));
213 }
214
set_presolve2(lprec * lp,int maxloops)215 static void __WINAPI set_presolve2(lprec *lp, int maxloops)
216 {
217 set_presolve(lp, get_presolve(lp), maxloops);
218 }
219
220 static struct _values print_sol[] =
221 {
222 { FALSE, "0" },
223 { TRUE, "1" },
224 { setvalue(AUTOMATIC) },
225 };
226
227 static struct _values scaling[] =
228 {
229 { setvalue(SCALE_NONE) },
230 { setvalue(SCALE_EXTREME) },
231 { setvalue(SCALE_RANGE) },
232 { setvalue(SCALE_MEAN) },
233 { setvalue(SCALE_GEOMETRIC) },
234 { setvalue(SCALE_CURTISREID) },
235 { setvalue(SCALE_QUADRATIC) },
236 { setvalue(SCALE_LOGARITHMIC) },
237 { setvalue(SCALE_USERWEIGHT) },
238 { setvalue(SCALE_POWER2) },
239 { setvalue(SCALE_EQUILIBRATE) },
240 { setvalue(SCALE_INTEGERS) },
241 { setvalue(SCALE_DYNUPDATE) },
242 { setvalue(SCALE_ROWSONLY) },
243 { setvalue(SCALE_COLSONLY) },
244 };
245
246 static struct _values simplextype[] =
247 {
248 { setvalue(SIMPLEX_PRIMAL_PRIMAL) },
249 { setvalue(SIMPLEX_DUAL_PRIMAL) },
250 { setvalue(SIMPLEX_PRIMAL_DUAL) },
251 { setvalue(SIMPLEX_DUAL_DUAL) },
252 };
253
254 static struct _values verbose[] =
255 {
256 { setvalue(NEUTRAL) },
257 { setvalue(CRITICAL) },
258 { setvalue(SEVERE) },
259 { setvalue(IMPORTANT) },
260 { setvalue(NORMAL) },
261 { setvalue(DETAILED) },
262 { setvalue(FULL) },
263 };
264
265 static struct _functions functions[] =
266 {
267 /* solve options */
268 { "ANTI_DEGEN", setintfunction(get_anti_degen, set_anti_degen), setvalues(anti_degen, ~0), WRITE_ACTIVE },
269 { "BASISCRASH", setintfunction(get_basiscrash, set_basiscrash), setvalues(basiscrash, ~0), WRITE_ACTIVE },
270 { "IMPROVE", setintfunction(get_improve, set_improve), setvalues(improve, ~0), WRITE_ACTIVE },
271 { "MAXPIVOT", setintfunction(get_maxpivot, set_maxpivot), setNULLvalues, WRITE_ACTIVE },
272 { "NEGRANGE", setREALfunction(get_negrange, set_negrange), setNULLvalues, WRITE_ACTIVE },
273 { "PIVOTING", setintfunction(get_pivoting, set_pivoting), setvalues(pivoting, PRICER_LASTOPTION), WRITE_ACTIVE },
274 { "PRESOLVE", setintfunction(get_presolve, set_presolve1), setvalues(presolving, ~0), WRITE_ACTIVE },
275 { "PRESOLVELOOPS", setintfunction(get_presolveloops, set_presolve2), setNULLvalues, WRITE_ACTIVE },
276 { "SCALELIMIT", setREALfunction(get_scalelimit, set_scalelimit), setNULLvalues, WRITE_ACTIVE },
277 { "SCALING", setintfunction(get_scaling, set_scaling), setvalues(scaling, SCALE_CURTISREID), WRITE_ACTIVE },
278 { "SIMPLEXTYPE", setintfunction(get_simplextype, set_simplextype), setvalues(simplextype, ~0), WRITE_ACTIVE },
279 { "OBJ_IN_BASIS", setMYBOOLfunction(is_obj_in_basis, set_obj_in_basis), setNULLvalues, WRITE_COMMENTED },
280
281 /* B&B options */
282 { "BB_DEPTHLIMIT", setintfunction(get_bb_depthlimit, set_bb_depthlimit), setNULLvalues, WRITE_ACTIVE },
283 { "BB_FLOORFIRST", setintfunction(get_bb_floorfirst, set_bb_floorfirst), setvalues(bb_floorfirst, ~0), WRITE_ACTIVE },
284 { "BB_RULE", setintfunction(get_bb_rule, set_bb_rule), setvalues(bb_rule, NODE_STRATEGYMASK), WRITE_ACTIVE },
285 { "BREAK_AT_FIRST", setMYBOOLfunction(is_break_at_first, set_break_at_first), setNULLvalues, WRITE_COMMENTED },
286 { "BREAK_AT_VALUE", setREALfunction(get_break_at_value, set_break_at_value), setNULLvalues, WRITE_COMMENTED },
287 { "MIP_GAP_ABS", setREALfunction(get_mip_gap_abs, set_mip_gap_abs), setNULLvalues, WRITE_ACTIVE },
288 { "MIP_GAP_REL", setREALfunction(get_mip_gap_rel, set_mip_gap_rel), setNULLvalues, WRITE_ACTIVE },
289 { "EPSINT", setREALfunction(get_epsint, set_epsint), setNULLvalues, WRITE_ACTIVE },
290
291 /* tolerances, values */
292 { "EPSB", setREALfunction(get_epsb, set_epsb), setNULLvalues, WRITE_ACTIVE },
293 { "EPSD", setREALfunction(get_epsd, set_epsd), setNULLvalues, WRITE_ACTIVE },
294 { "EPSEL", setREALfunction(get_epsel, set_epsel), setNULLvalues, WRITE_ACTIVE },
295 { "EPSPERTURB", setREALfunction(get_epsperturb, set_epsperturb), setNULLvalues, WRITE_ACTIVE },
296 { "EPSPIVOT", setREALfunction(get_epspivot, set_epspivot), setNULLvalues, WRITE_ACTIVE },
297 { "INFINITE", setREALfunction(get_infinite, set_infinite), setNULLvalues, WRITE_ACTIVE },
298
299 /* read-only options */
300 { "DEBUG", setMYBOOLfunction(is_debug, set_debug), setNULLvalues, WRITE_COMMENTED },
301 { "OBJ_BOUND", setREALfunction(get_obj_bound, set_obj_bound), setNULLvalues, WRITE_COMMENTED },
302 { "PRINT_SOL", setintfunction(get_print_sol, set_print_sol), setvalues(print_sol, ~0), WRITE_COMMENTED },
303 { "TIMEOUT", setlongfunction(get_timeout, set_timeout), setNULLvalues, WRITE_COMMENTED },
304 { "TRACE", setMYBOOLfunction(is_trace, set_trace), setNULLvalues, WRITE_COMMENTED },
305 { "VERBOSE", setintfunction(get_verbose, set_verbose), setvalues(verbose, ~0), WRITE_COMMENTED }
306 };
307
write_params1(lprec * lp,FILE * fp,char * header,int newline)308 static void write_params1(lprec *lp, FILE *fp, char *header, int newline)
309 {
310 int ret = 0, ret2, i, j, k, value, value2, elements, majorversion, minorversion, release, build;
311 unsigned int basemask;
312 REAL a = 0;
313 char buf[4096], par[20];
314
315 ini_writeheader(fp, header, newline);
316 lp_solve_version(&majorversion, &minorversion, &release, &build);
317 sprintf(buf, "lp_solve version %d.%d settings\n", majorversion, minorversion);
318 ini_writecomment(fp, buf);
319 for(i = 0; i < sizeof(functions) / sizeof(*functions); i++) {
320 switch(functions[i].type) {
321 case intfunction:
322 if(functions[i].get_function.int_get_function == NULL)
323 continue;
324 ret = functions[i].get_function.int_get_function(lp);
325 break;
326 case longfunction:
327 if(functions[i].get_function.long_get_function == NULL)
328 continue;
329 ret = functions[i].get_function.long_get_function(lp);
330 break;
331 case MYBOOLfunction:
332 if(functions[i].get_function.MYBOOL_get_function == NULL)
333 continue;
334 ret = (int) functions[i].get_function.MYBOOL_get_function(lp);
335 break;
336 case REALfunction:
337 if(functions[i].get_function.REAL_get_function == NULL)
338 continue;
339 a = functions[i].get_function.REAL_get_function(lp);
340 break;
341 }
342 buf[0] = 0;
343 if(functions[i].values == NULL) {
344 switch(functions[i].type) {
345 case intfunction:
346 case longfunction:
347 case MYBOOLfunction:
348 sprintf(buf, "%d", ret);
349 break;
350 case REALfunction:
351 sprintf(buf, "%g", a);
352 break;
353 }
354 }
355 else {
356 elements = functions[i].elements;
357 basemask = functions[i].basemask;
358 for(j = 0; j < elements; j++) {
359 value = functions[i].values[j].value;
360 ret2 = ret;
361 if(((unsigned int) value) < basemask)
362 ret2 &= basemask;
363 if(value == 0) {
364 if(ret2 == 0) {
365 if(*buf)
366 strcat(buf, " + ");
367 strcat(buf, functions[i].values[j].svalue);
368 }
369 }
370 else if((ret2 & value) == value) {
371 for(k = 0; k < elements; k++) {
372 value2 = functions[i].values[k].value;
373 if((k != j) && (value2 > value) && ((value2 & value) == value) && ((ret2 & value2) == value2))
374 break;
375 }
376 if(k == elements) {
377 if(*buf)
378 strcat(buf, " + ");
379 strcat(buf, functions[i].values[j].svalue);
380 }
381 }
382 }
383 }
384 if(functions[i].mask & WRITE_ACTIVE)
385 par[0] = 0;
386 else
387 strcpy(par, ";");
388 strcat(par, functions[i].par);
389 ini_writedata(fp, STRLWR(par), buf);
390 }
391 }
392
readoptions(char * options,char ** header)393 static void readoptions(char *options, char **header)
394 {
395 char *ptr1, *ptr2;
396
397 if(options != NULL) {
398 ptr1 = options;
399 while(*ptr1) {
400 ptr2 = strchr(ptr1, '-');
401 if(ptr2 == NULL)
402 break;
403 ptr2++;
404 if(tolower((unsigned char) *ptr2) == 'h') {
405 for(++ptr2; (*ptr2) && (isspace(*ptr2)); ptr2++);
406 for(ptr1 = ptr2; (*ptr1) && (!isspace(*ptr1)); ptr1++);
407 *header = (char *) calloc(1 + (int) (ptr1 - ptr2), 1);
408 memcpy(*header, ptr2, (int) (ptr1 - ptr2));
409 }
410 }
411 }
412
413 if(*header == NULL)
414 *header = strdup("Default");
415 }
416
write_params(lprec * lp,char * filename,char * options)417 MYBOOL __WINAPI write_params(lprec *lp, char *filename, char *options)
418 {
419 int k, ret, params_written;
420 FILE *fp, *fp0;
421 int state = 0, looping, newline;
422 char buf[4096], *filename0, *ptr1, *ptr2, *header = NULL;
423
424 readoptions(options, &header);
425
426 k = strlen(filename);
427 filename0 = (char *) malloc(k + 1 + 1);
428 strcpy(filename0, filename);
429 ptr1 = strrchr(filename0, '.');
430 ptr2 = strrchr(filename0, '\\');
431 if((ptr1 == NULL) || ((ptr2 != NULL) && (ptr1 < ptr2)))
432 ptr1 = filename0 + k;
433 memmove(ptr1 + 1, ptr1, k + 1 - (int) (ptr1 - filename0));
434 ptr1[0] = '_';
435 if(rename(filename, filename0)) {
436 switch(errno) {
437 case ENOENT: /* File or path specified by oldname not found */
438 FREE(filename0);
439 filename0 = NULL;
440 break;
441 case EACCES: /* File or directory specified by newname already exists or could not be created (invalid path); or oldname is a directory and newname specifies a different path. */
442 FREE(filename0);
443 FREE(header);
444 return(FALSE);
445 break;
446 }
447 }
448
449 if((fp = ini_create(filename)) == NULL)
450 ret = FALSE;
451 else {
452 params_written = FALSE;
453 newline = TRUE;
454 if(filename0 != NULL) {
455 fp0 = ini_open(filename0);
456 if(fp0 == NULL) {
457 rename(filename0, filename);
458 FREE(filename0);
459 FREE(header);
460 return(FALSE);
461 }
462 looping = TRUE;
463 while(looping) {
464 switch(ini_readdata(fp0, buf, sizeof(buf), TRUE)) {
465 case 0: /* End of file */
466 looping = FALSE;
467 break;
468 case 1: /* header */
469 ptr1 = strdup(buf);
470 STRUPR(buf);
471 ptr2 = strdup(header);
472 STRUPR(ptr2);
473 if(strcmp(buf, ptr2) == 0) {
474 write_params1(lp, fp, ptr1, newline);
475 params_written = TRUE;
476 newline = TRUE;
477 state = 1;
478 }
479 else {
480 state = 0;
481 ini_writeheader(fp, ptr1, newline);
482 newline = TRUE;
483 }
484 FREE(ptr2);
485 FREE(ptr1);
486 break;
487 case 2: /* data */
488 if(state == 0) {
489 ini_writedata(fp, NULL, buf);
490 newline = (*buf != 0);
491 }
492 break;
493 }
494 }
495 ini_close(fp0);
496 }
497
498 if(!params_written)
499 write_params1(lp, fp, header, newline);
500
501 ini_close(fp);
502 ret = TRUE;
503 }
504
505 if(filename0 != NULL) {
506 remove(filename0);
507 FREE(filename0);
508 }
509
510 FREE(header);
511
512 return( (MYBOOL) ret );
513 }
514
515
read_params(lprec * lp,char * filename,char * options)516 MYBOOL __WINAPI read_params(lprec *lp, char *filename, char *options)
517 {
518 int ret, looping, line;
519 FILE *fp;
520 hashtable *hashfunctions, *hashparameters;
521 hashelem *hp;
522 int i, j, elements, n, intvalue, state = 0;
523 REAL REALvalue;
524 char buf[4096], *header = NULL, *ptr, *ptr1, *ptr2;
525
526 if((fp = ini_open(filename)) == NULL)
527 ret = FALSE;
528 else {
529 /* create hashtable of all callable commands to find them quickly */
530 hashfunctions = create_hash_table(sizeof(functions) / sizeof(*functions), 0);
531 for (n = 0, i = 0; i < (int) (sizeof(functions)/sizeof(*functions)); i++) {
532 puthash(functions[i].par, i, NULL, hashfunctions);
533 if(functions[i].values != NULL)
534 n += functions[i].elements;
535 }
536 /* create hashtable of all arguments to find them quickly */
537 hashparameters = create_hash_table(n, 0);
538 for (n = 0, i = 0; i < (int) (sizeof(functions)/sizeof(*functions)); i++) {
539 if(functions[i].values != NULL) {
540 elements = functions[i].elements;
541 for(j = 0; j < elements; j++)
542 if((strcmp(functions[i].values[j].svalue, "0") != 0) &&
543 (strcmp(functions[i].values[j].svalue, "1") != 0))
544 puthash(functions[i].values[j].svalue, j, NULL, hashparameters);
545 }
546 }
547
548 readoptions(options, &header);
549
550 STRUPR(header);
551 ret = looping = TRUE;
552 line = 0;
553 while((ret) && (looping)) {
554 line++;
555 switch(ini_readdata(fp, buf, sizeof(buf), FALSE)) {
556 case 0: /* End of file */
557 looping = FALSE;
558 break;
559 case 1: /* header */
560 switch(state) {
561 case 0:
562 STRUPR(buf);
563 if(strcmp(buf, header) == 0)
564 state = 1;
565 break;
566 case 1:
567 looping = FALSE;
568 break;
569 }
570 break;
571 case 2: /* data */
572 if(state == 1) {
573 for(ptr = buf; (*ptr) && (isspace(*ptr)); ptr++);
574 }
575 else
576 ptr = NULL;
577 if((ptr != NULL) && (*ptr)) {
578 STRUPR(buf);
579 ptr = strchr(buf, '=');
580 if(ptr == NULL) {
581 report(lp, IMPORTANT, "read_params: No equal sign on line %d\n", line);
582 ret = FALSE;
583 }
584 else {
585 *ptr = 0;
586 for(ptr1 = buf; isspace(*ptr1); ptr1++);
587 for(ptr2 = ptr - 1; (ptr2 >= ptr1) && (isspace(*ptr2)); ptr2--);
588 if(ptr2 <= ptr1) {
589 report(lp, IMPORTANT, "read_params: No parameter name before equal sign on line %d\n", line);
590 ret = FALSE;
591 }
592 else {
593 ptr2[1] = 0;
594 hp = findhash(ptr1, hashfunctions);
595 if(hp == NULL) {
596 report(lp, IMPORTANT, "read_params: Unknown parameter name (%s) before equal sign on line %d\n", ptr1, line);
597 ret = FALSE;
598 }
599 else {
600 i = hp->index;
601 ptr1 = ++ptr;
602 intvalue = 0;
603 REALvalue = 0;
604 if(functions[i].values == NULL) {
605 switch(functions[i].type) {
606 case intfunction:
607 case longfunction:
608 case MYBOOLfunction:
609 intvalue = strtol(ptr1, &ptr2, 10);
610 while((*ptr2) && (isspace(*ptr2)))
611 ptr2++;
612 if(*ptr2) {
613 report(lp, IMPORTANT, "read_params: Invalid integer value on line %d\n", line);
614 ret = FALSE;
615 }
616 break;
617 case REALfunction:
618 REALvalue = strtod(ptr1, &ptr2);
619 while((*ptr2) && (isspace(*ptr2)))
620 ptr2++;
621 if(*ptr2) {
622 report(lp, IMPORTANT, "read_params: Invalid real value on line %d\n", line);
623 ret = FALSE;
624 }
625 break;
626 }
627 }
628 else {
629 while(ret) {
630 ptr = strchr(ptr1, '+');
631 if(ptr == NULL)
632 ptr = ptr1 + strlen(ptr1);
633 for(; isspace(*ptr1); ptr1++);
634 for(ptr2 = ptr - 1; (ptr2 >= ptr1) && (isspace(*ptr2)); ptr2--);
635 if(ptr2 <= ptr1)
636 break;
637 else {
638 ptr2[1] = 0;
639 hp = findhash(ptr1, hashparameters);
640 if (hp == NULL) {
641 report(lp, IMPORTANT, "read_params: Invalid parameter name (%s) on line %d\n", ptr1, line);
642 ret = FALSE;
643 }
644 else {
645 j = hp->index;
646 if((j >= functions[i].elements) ||
647 (strcmp(functions[i].values[j].svalue, ptr1))) {
648 report(lp, IMPORTANT, "read_params: Inappropriate parameter name (%s) on line %d\n", ptr1, line);
649 ret = FALSE;
650 }
651 else {
652 intvalue += functions[i].values[j].value;
653 }
654 }
655 ptr1 = ptr + 1;
656 }
657 }
658 }
659 if(ret) {
660 switch(functions[i].type) {
661 case intfunction:
662 functions[i].set_function.int_set_function(lp, intvalue);
663 break;
664 case longfunction:
665 functions[i].set_function.long_set_function(lp, intvalue);
666 break;
667 case MYBOOLfunction:
668 functions[i].set_function.MYBOOL_set_function(lp, (MYBOOL) intvalue);
669 break;
670 case REALfunction:
671 functions[i].set_function.REAL_set_function(lp, REALvalue);
672 break;
673 }
674 }
675 }
676 }
677 }
678 }
679 break;
680 }
681 }
682
683 FREE(header);
684 free_hash_table(hashfunctions);
685 free_hash_table(hashparameters);
686
687 ini_close(fp);
688 }
689
690 return( (MYBOOL) ret );
691 }
692