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