d82e0f9c8893e7336686c4bf354d300f24e41271
[expresskeys.git] / src-expresskeys / config_read.c
1 /*
2  expresskeys - Support ExpressKeys, Touch Strips, Scroll Wheel on Wacom tablets.
3
4  Copyright (C) 2005-2006 - Mats Johannesson
5
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License along
17  with this program; if not, write to the Free Software Foundation, Inc.,
18  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h> /* NULL, FILE, sprintf, fgets, fopen, fclose, ftell */
22 #include <stdlib.h> /* malloc, free, atoi */
23 #include <string.h> /* strlen, strstr, strchr, strspn, strcspn */
24 #include <ctype.h> /* isdigit */
25
26 #include "tablet.h"
27
28 /* Globals: */
29
30 /* Flag if having at _at least_ one valid configuration file: */
31 int ok_config;
32
33 /* 'Internal' Globals: */
34
35 /* Flags used to keep track of state and reverting actions: */
36 static int revert_config;
37 static int pgr_recname_malloced;
38 static int st1_prcurve_malloced;
39 static int st2_prcurve_malloced;
40
41 /* Externals: */
42
43 extern int be_verbose;
44 extern int reread_config;
45
46 extern const int i3;
47 extern const int i3s;
48 extern const int g4;
49 extern const int g4b;
50 extern const int nop;
51
52 extern const char* padstr;
53 extern const char* sty1str;
54 extern const char* sty2str;
55
56 extern const char* our_prog_name;
57 extern const char* configstring;
58 extern const char* configversion;
59
60 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
61  Try to find a boolean 1/0 switch and write it to a structure place:
62  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
63
64 static void transfer_boolean(int address[], char* write_buffer)
65 {
66         int k = 0;
67         char* end_pos = write_buffer + strlen(write_buffer);
68
69         if (reread_config || revert_config) {
70                 address[0] = 0;
71         }
72
73         for (; write_buffer < end_pos; write_buffer++) {
74                 if (isdigit(write_buffer[0])) {
75                         write_buffer[1] = '\0';
76                         k = atoi(write_buffer);
77                         if (k == 0 || k == 1) {
78                                 address[0] = k;
79                         } else {
80                                 address[0] = 0;
81                                 if (be_verbose) {
82                                         fprintf(stderr, "Only boolean 1 or 0 \
83 allowed as switch <-- RESETTING T0 ZERO\n");
84                                 }
85                         }
86                         break;
87                 }
88         }
89
90 }
91
92 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
93  Try to find digits for a time value and write it to a structure place.
94  We allow a max of 10 in full seconds, and 99 as a part second (10.99).
95  "Be liberal with what you accept but conservative with what you reject"
96  has been the guiding thought here. Hence the extreme ugliness of the code:
97  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
98
99 static void transfer_timevalue(int address[], char* write_buffer)
100 {
101         int i;
102         int k = 0;
103         int m = 0;
104         int min_digit = 0;
105         int max_sec = 10;
106         int max_nsec = 99;
107         int max_val = 3;
108 /* Pad means 'padding' here: */
109         int max_pad = 10;
110         char val_buf[max_val];
111         char pad_buf[max_pad];
112         char* end_pos = write_buffer + strlen(write_buffer);
113
114         if (reread_config || revert_config) {
115                 address[0] = 0;
116                 address[1] = 0;
117         }
118
119         for (i = 0; m < max_val && write_buffer < end_pos;) {
120                 if (i) {
121                         i--;
122                         for (k = 0; k < i; k++) {
123                                 val_buf[k] = write_buffer[k];
124                         }
125                         val_buf[k] = '\0';
126                         if ((k = atoi(val_buf)) >= min_digit) {
127                                 if (m == 0) {
128                                         if (k <= max_sec) {
129                                                 address[m] = k;
130                                         } else {
131                                                 address[m] = 0;
132                                         }
133                                         m++;
134                                 } else if (m == 1) {
135                                         if (k <= max_nsec) {
136                                                 address[m] = k;
137                                                 sprintf(pad_buf, "%c",
138                                                                 *write_buffer);
139                                         } else {
140                                                 address[m] = 0;
141                                         }
142                                         m++;
143                                 }
144                         }
145                         write_buffer = write_buffer+i;
146                 }
147                 for (i = 0; i < max_val && write_buffer < end_pos; i++) {
148                         if (!isdigit(write_buffer[i])) {
149                                 write_buffer[i] = '\0';
150                                 if ((k = atoi(write_buffer)) >= min_digit) {
151                                         if (m == 0) {
152                                                 if (k <= max_sec) {
153                                                         address[m] = k;
154                                                 } else {
155                                                         address[m] = 0;
156                                                 }
157                                                 m++;
158                                         } else if (m == 1) {
159                                                 if (k <= max_nsec) {
160                                                         address[m] = k;
161                                                         sprintf(pad_buf, "%c",
162                                                                 *write_buffer);
163                                                 } else {
164                                                         address[m] = 0;
165                                                 }
166                                                 m++;
167                                         }
168                                 }
169                                 write_buffer = write_buffer+i+1;
170                                 i = 0;
171                                 break;
172                         }
173                 }
174         }
175
176 /* Pad the nsec value with correct number of zeros for the nanosleep(2) call: */
177
178         if (atoi(pad_buf) == 0 || address[1] >= 10) {
179                 sprintf(pad_buf, "%i%s", *(address+1), "0000000");
180         } else {
181                 sprintf(pad_buf, "%i%s", *(address+1), "00000000");
182         }
183         address[1] = atoi(pad_buf);
184
185 }
186
187 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
188  Try to find digits for keycodes and write them to a structure place. We allow
189  a max of four digits per keycode (to accommodate our fake ones, eg 1009).
190  "Be liberal with what you accept but conservative with what you reject"
191  has been the guiding thought here. Hence the ugliness of the code:
192  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
193
194 static void transfer_keycode(int address[], char* write_buffer)
195 {
196         int i;
197         int k = 0;
198         int m = 0;
199 /* Filter out anything below keycode 9 (ESC): */
200         int min_keycode = 9;
201 /* Filter out anything above keycode 1023. Other
202  'out-of-bounds' areas are checked in the loops: */
203         int max_keycode = 1023;
204         int max_buf = 5;
205         char buf[max_buf];
206         char* end_pos = write_buffer + strlen(write_buffer);
207
208         if (reread_config || revert_config) {
209                 for (i = 0; i < MAXKEYS; i++) {
210                         address[i] = 0;
211                 }
212         }
213
214         for (i = 0; m < MAXKEYS && write_buffer < end_pos;) {
215                 if (i) {
216                         i--;
217                         for (k = 0; k < i; k++) {
218                                 buf[k] = write_buffer[k];
219                         }
220                         buf[k] = '\0';
221                         k = atoi(buf);
222                         if ((k >= min_keycode && k <= max_keycode)
223                                 && (k < 256 || k > 263)
224                                 && (k < 512 || k > 519)
225                                 && (k < 768 || k > 775)) {
226                                 address[m] = k;
227                                 m++;
228                         }
229                         write_buffer = write_buffer+i;
230                 }
231                 for (i = 0; i < max_buf && write_buffer < end_pos; i++) {
232                         if (!isdigit(write_buffer[i])) {
233                                 write_buffer[i] = '\0';
234                                 k = atoi(write_buffer);
235                                 if ((k >= min_keycode && k <= max_keycode)
236                                         && (k < 256 || k > 263)
237                                         && (k < 512 || k > 519)
238                                         && (k < 768 || k > 775)) {
239                                         if (m < MAXKEYS) {
240                                                 address[m] = k;
241                                                 m++;
242                                         }
243                                 }
244                                 write_buffer = write_buffer+i+1;
245                                 i = 0;
246                                 break;
247                         }
248                 }
249         }
250
251 }
252
253 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
254  Allocate memory for strings (ProgramName, Stylus1PressCurve, Stylus2PressCurve)
255  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
256
257 static char* field_malloc(FILE* errorfp, char* write_buffer)
258 {
259         char* address = NULL;
260         int len = 0;
261
262         len = strlen(write_buffer)+1;
263         if ((address = malloc(len)) == NULL) {
264                 exit_on_error(errorfp,
265 "\n%s ERROR: Memory allocation trouble at field_malloc()\n", our_prog_name, "");
266         }
267         sprintf(address, "%s", write_buffer);
268
269         return address;
270
271 }
272
273 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
274  Chop away leading and trailing text in a record field:
275  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
276
277 static void prune_field(char* field_begin, char* write_buffer)
278 {
279         int flen = 0;
280         char* quote = NULL;
281
282         flen = strcspn(field_begin, " \t");
283         field_begin = (field_begin+flen);
284         field_begin = (field_begin+(strspn(field_begin, " \t\"")));
285         if ((quote = (strchr(field_begin, '\"'))) != NULL) {
286                 flen = (quote - field_begin);
287         } else {
288                 flen = strcspn(field_begin, "\n#");
289         }
290         strncpy(write_buffer, field_begin, flen);
291         strncpy(write_buffer + flen, "\0", 1);
292
293 }
294
295 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
296  Try to find a field keyword in the supplied string. If found, hand it over
297  for pruning and transfer of data to the correct structure place:
298  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
299
300 static void handle_field(FILE* errorfp, char* read_buffer, void* address,
301                                                                 const int model)
302 {
303         struct i3_program* pi3;
304         struct i3s_program* pi3s;
305         struct g4_program* pg4;
306         struct g4b_program* pg4b;
307         struct nop_program* pnop;
308         struct common_data* cdp = NULL;
309         struct touch_data* tdp = NULL;
310         struct wheel_data* wdp = NULL;
311         struct button_data* bdp = NULL;
312         struct i3_configstrings* ci3;
313         struct i3s_configstrings* ci3s;
314         struct g4_configstrings* cg4;
315         struct g4b_configstrings* cg4b;
316         struct nop_configstrings* cnop;
317         struct common_string* csp = NULL;
318         struct touch_string* tsp = NULL;
319         struct wheel_string* wsp = NULL;
320         struct button_string* bsp = NULL;
321
322         if (model == i3) {
323                 pi3 = address;
324                 cdp = &pi3->common_data;
325                 tdp = &pi3->touch_data;
326                 bdp = &pi3->button_data;
327                 ci3 = i3_configstrings;
328                 csp = &ci3->common_string;
329                 tsp = &ci3->touch_string;
330                 bsp = &ci3->button_string;
331         } else if (model == i3s) {
332                 pi3s = address;
333                 cdp = &pi3s->common_data;
334                 tdp = &pi3s->touch_data;
335                 bdp = &pi3s->button_data;
336                 ci3s = i3s_configstrings;
337                 csp = &ci3s->common_string;
338                 tsp = &ci3s->touch_string;
339                 bsp = &ci3s->button_string;
340         } else if (model == g4) {
341                 pg4 = address;
342                 cdp = &pg4->common_data;
343                 wdp = &pg4->wheel_data;
344                 bdp = &pg4->button_data;
345                 cg4 = g4_configstrings;
346                 csp = &cg4->common_string;
347                 wsp = &cg4->wheel_string;
348                 bsp = &cg4->button_string;
349         } else if (model == g4b) {
350                 pg4b = address;
351                 cdp = &pg4b->common_data;
352                 bdp = &pg4b->button_data;
353                 cg4b = g4b_configstrings;
354                 csp = &cg4b->common_string;
355                 bsp = &cg4b->button_string;
356         } else if (model == nop) {
357                 pnop = address;
358                 cdp = &pnop->common_data;
359                 cnop = nop_configstrings;
360                 csp = &cnop->common_string;
361         }
362
363         char write_buffer[MAXBUFFER];
364
365         char* comment = NULL;
366         char* field = NULL;
367
368 /* ProgramName */
369         if (((field = (strstr(read_buffer, csp->class_name))) != NULL)
370                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
371                                                 || (field < comment))) {
372                 prune_field(field, write_buffer);
373                 if ((cdp->class_name) && (reread_config)
374                         && (!pgr_recname_malloced)) {
375                         free(cdp->class_name);
376                         cdp->class_name = NULL;
377                 }
378                 if (!pgr_recname_malloced) {
379                         cdp->class_name = field_malloc(errorfp, write_buffer);
380                         pgr_recname_malloced = 1;
381                         if (be_verbose) {
382                                 fprintf(stderr, "PGR RECNAME = \"%s\"\n",
383                                                         cdp->class_name);
384                         }
385                 }
386                 return;
387         }
388 /* Stylus1PressCurve */
389         if (((field = (strstr(read_buffer, csp->stylus1_presscurve))) != NULL)
390                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
391                                                 || (field < comment))) {
392                 prune_field(field, write_buffer);
393                 if ((cdp->stylus1_presscurve) && (reread_config)
394                         && (!st1_prcurve_malloced)) {
395                         free(cdp->stylus1_presscurve);
396                         cdp->stylus1_presscurve = NULL;
397                 }
398                 if (!st1_prcurve_malloced) {
399                         cdp->stylus1_presscurve = field_malloc(errorfp,
400                                                                 write_buffer);
401                         st1_prcurve_malloced = 1;
402                         if (be_verbose && cdp->class_name != NULL) {
403                                 fprintf(stderr, "ST1 PRCURVE = \"%s\"\n",
404                                                 cdp->stylus1_presscurve);
405                         }
406                 }
407                 return;
408         }
409 /* Stylus2PressCurve */
410         if (((field = (strstr(read_buffer, csp->stylus2_presscurve))) != NULL)
411                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
412                                                 || (field < comment))) {
413                 prune_field(field, write_buffer);
414                 if ((cdp->stylus2_presscurve) && (reread_config)
415                         && (!st2_prcurve_malloced)) {
416                         free(cdp->stylus2_presscurve);
417                         cdp->stylus2_presscurve = NULL;
418                 }
419                 if (!st2_prcurve_malloced) {
420                         cdp->stylus2_presscurve = field_malloc(errorfp,
421                                                                 write_buffer);
422                         st2_prcurve_malloced = 1;
423                         if (be_verbose && cdp->class_name != NULL) {
424                                 fprintf(stderr, "ST2 PRCURVE = \"%s\"\n",
425                                                 cdp->stylus2_presscurve);
426                         }
427                 }
428                 return;
429         }
430 /* DelayEachKeycode */
431         if (model != nop) {
432                 if (((field = (strstr(read_buffer, csp->keycode_delay)))!= NULL)
433                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
434                                                 || (field < comment))) {
435                         prune_field(field, write_buffer);
436                         transfer_timevalue(cdp->keycode_delay, write_buffer);
437                         return;
438                 }
439         }
440 /* HandleTouchStrips TouchRepeatAfter DelayTouchRepeat
441  LeftPadTouchUp LeftPadTouchDown RepeatLeftUp RepeatLeftDown */
442         if (model == i3s || model == i3) {
443                 if (((field = (strstr(read_buffer, tsp->handle_touch))) != NULL)
444                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
445                                                 || (field < comment))) {
446                         prune_field(field, write_buffer);
447                         transfer_boolean(tdp->handle_touch, write_buffer);
448                         return;
449                 }
450                 if (((field = (strstr(read_buffer, tsp->repeat_after)))!= NULL)
451                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
452                                                 || (field < comment))) {
453                         prune_field(field, write_buffer);
454                         transfer_timevalue(tdp->repeat_after, write_buffer);
455                         return;
456                 }
457                 if (((field = (strstr(read_buffer, tsp->repeat_delay)))!= NULL)
458                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
459                                                 || (field < comment))) {
460                         prune_field(field, write_buffer);
461                         transfer_timevalue(tdp->repeat_delay, write_buffer);
462                         return;
463                 }
464                 if (((field = (strstr(read_buffer, tsp->left_touch_up)))
465                                                                 != NULL)
466                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
467                                                 || (field < comment))) {
468                         prune_field(field, write_buffer);
469                         transfer_keycode(tdp->left_touch_up, write_buffer);
470                         return;
471                 }
472                 if (((field = (strstr(read_buffer, tsp->left_touch_down)))
473                                                                 != NULL)
474                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
475                                                 || (field < comment))) {
476                         prune_field(field, write_buffer);
477                         transfer_keycode(tdp->left_touch_down, write_buffer);
478                         return;
479                 }
480                 if (((field = (strstr(read_buffer, tsp->repeat_left_up)))
481                                                                 != NULL)
482                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
483                                                 || (field < comment))) {
484                         prune_field(field, write_buffer);
485                         transfer_boolean(tdp->repeat_left_up, write_buffer);
486                         return;
487                 }
488                 if (((field = (strstr(read_buffer, tsp->repeat_left_down)))
489                                                                 != NULL)
490                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
491                                                 || (field < comment))) {
492                         prune_field(field, write_buffer);
493                         transfer_boolean(tdp->repeat_left_down, write_buffer);
494                         return;
495                 }
496         }
497 /* HandleScrollWheel ScrollWheelUp ScrollWheelDown */
498         if (model == g4) {
499                 if (((field = (strstr(read_buffer, wsp->handle_wheel))) != NULL)
500                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
501                                                 || (field < comment))) {
502                         prune_field(field, write_buffer);
503                         transfer_boolean(wdp->handle_wheel, write_buffer);
504                         return;
505                 }
506                 if (((field = (strstr(read_buffer, wsp->scroll_wheel_up)))
507                                                                 != NULL)
508                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
509                                                 || (field < comment))) {
510                         prune_field(field, write_buffer);
511                         transfer_keycode(wdp->scroll_wheel_up, write_buffer);
512                         return;
513                 }
514                 if (((field = (strstr(read_buffer, wsp->scroll_wheel_down)))
515                                                                 != NULL)
516                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
517                                                 || (field < comment))) {
518                         prune_field(field, write_buffer);
519                         transfer_keycode(wdp->scroll_wheel_down, write_buffer);
520                         return;
521                 }
522         }
523 /* ButtonRepeatAfter DelayButtonRepeat
524  LeftPadButton9/LeftButton LeftPadButton10/RightButton
525  RepeatButton9/RepeatLeft RepeatButton10/RepeatRight */
526         if (model == i3s || model == i3 || model == g4 || model == g4b) {
527                 if (((field = (strstr(read_buffer, bsp->repeat_after)))!= NULL)
528                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
529                                                 || (field < comment))) {
530                         prune_field(field, write_buffer);
531                         transfer_timevalue(bdp->repeat_after, write_buffer);
532                         return;
533                 }
534                 if (((field = (strstr(read_buffer, bsp->repeat_delay)))!= NULL)
535                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
536                                                 || (field < comment))) {
537                         prune_field(field, write_buffer);
538                         transfer_timevalue(bdp->repeat_delay, write_buffer);
539                         return;
540                 }
541                 if (((field = (strstr(read_buffer, bsp->button9))) != NULL)
542                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
543                                                 || (field < comment))) {
544                         prune_field(field, write_buffer);
545                         transfer_keycode(bdp->button9, write_buffer);
546                         return;
547                 }
548                 if (((field = (strstr(read_buffer, bsp->button10))) != NULL)
549                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
550                                                 || (field < comment))) {
551                         prune_field(field, write_buffer);
552                         transfer_keycode(bdp->button10, write_buffer);
553                         return;
554                 }
555                 if (((field = (strstr(read_buffer, bsp->repeat9))) != NULL)
556                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
557                                                 || (field < comment))) {
558                         prune_field(field, write_buffer);
559                         transfer_boolean(bdp->repeat9, write_buffer);
560                         return;
561                 }
562                 if (((field = (strstr(read_buffer, bsp->repeat10))) != NULL)
563                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
564                                                 || (field < comment))) {
565                         prune_field(field, write_buffer);
566                         transfer_boolean(bdp->repeat10, write_buffer);
567                         return;
568                 }
569         }
570 /* LeftPadButton11 LeftPadButton12 RepeatButton11 RepeatButton12 */
571         if (model == i3s || model == i3) {
572                 if (((field = (strstr(read_buffer, bsp->button11))) != NULL)
573                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
574                                                 || (field < comment))) {
575                         prune_field(field, write_buffer);
576                         transfer_keycode(bdp->button11, write_buffer);
577                         return;
578                 }
579                 if (((field = (strstr(read_buffer, bsp->button12))) != NULL)
580                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
581                                                 || (field < comment))) {
582                         prune_field(field, write_buffer);
583                         transfer_keycode(bdp->button12, write_buffer);
584                         return;
585                 }
586                 if (((field = (strstr(read_buffer, bsp->repeat11))) != NULL)
587                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
588                                                 || (field < comment))) {
589                         prune_field(field, write_buffer);
590                         transfer_boolean(bdp->repeat11, write_buffer);
591                         return;
592                 }
593                 if (((field = (strstr(read_buffer, bsp->repeat12))) != NULL)
594                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
595                                                 || (field < comment))) {
596                         prune_field(field, write_buffer);
597                         transfer_boolean(bdp->repeat12, write_buffer);
598                         return;
599                 }
600         }
601 /* RightPadTouchUp RightPadTouchDown RepeatRightUp RepeatRightDown
602  RightPadButton13 RightPadButton14 RightPadButton15 RightPadButton16
603  RepeatButton13 RepeatButton14 RepeatButton15 RepeatButton16 */
604         if (model == i3) {
605                 if (((field = (strstr(read_buffer, tsp->right_touch_up)))
606                                                                 != NULL)
607                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
608                                                 || (field < comment))) {
609                         prune_field(field, write_buffer);
610                         transfer_keycode(tdp->right_touch_up, write_buffer);
611                         return;
612                 }
613                 if (((field = (strstr(read_buffer, tsp->right_touch_down)))
614                                                                 != NULL)
615                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
616                                                 || (field < comment))) {
617                         prune_field(field, write_buffer);
618                         transfer_keycode(tdp->right_touch_down, write_buffer);
619                         return;
620                 }
621                 if (((field = (strstr(read_buffer, tsp->repeat_right_up)))
622                                                                 != NULL)
623                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
624                                                 || (field < comment))) {
625                         prune_field(field, write_buffer);
626                         transfer_boolean(tdp->repeat_right_up, write_buffer);
627                         return;
628                 }
629                 if (((field = (strstr(read_buffer, tsp->repeat_right_down)))
630                                                                 != NULL)
631                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
632                                                 || (field < comment))) {
633                         prune_field(field, write_buffer);
634                         transfer_boolean(tdp->repeat_right_down, write_buffer);
635                         return;
636                 }
637                 if (((field = (strstr(read_buffer, bsp->button13))) != NULL)
638                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
639                                                 || (field < comment))) {
640                         prune_field(field, write_buffer);
641                         transfer_keycode(bdp->button13, write_buffer);
642                         return;
643                 }
644                 if (((field = (strstr(read_buffer, bsp->button14))) != NULL)
645                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
646                                                 || (field < comment))) {
647                         prune_field(field, write_buffer);
648                         transfer_keycode(bdp->button14, write_buffer);
649                         return;
650                 }
651                 if (((field = (strstr(read_buffer, bsp->button15))) != NULL)
652                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
653                                                 || (field < comment))) {
654                         prune_field(field, write_buffer);
655                         transfer_keycode(bdp->button15, write_buffer);
656                         return;
657                 }
658                 if (((field = (strstr(read_buffer, bsp->button16))) != NULL)
659                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
660                                                 || (field < comment))) {
661                         prune_field(field, write_buffer);
662                         transfer_keycode(bdp->button16, write_buffer);
663                         return;
664                 }
665                 if (((field = (strstr(read_buffer, bsp->repeat13))) != NULL)
666                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
667                                                 || (field < comment))) {
668                         prune_field(field, write_buffer);
669                         transfer_boolean(bdp->repeat13, write_buffer);
670                         return;
671                 }
672                 if (((field = (strstr(read_buffer, bsp->repeat14))) != NULL)
673                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
674                                                 || (field < comment))) {
675                         prune_field(field, write_buffer);
676                         transfer_boolean(bdp->repeat14, write_buffer);
677                         return;
678                 }
679                 if (((field = (strstr(read_buffer, bsp->repeat15))) != NULL)
680                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
681                                                 || (field < comment))) {
682                         prune_field(field, write_buffer);
683                         transfer_boolean(bdp->repeat15, write_buffer);
684                         return;
685                 }
686                 if (((field = (strstr(read_buffer, bsp->repeat16))) != NULL)
687                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
688                                                 || (field < comment))) {
689                         prune_field(field, write_buffer);
690                         transfer_boolean(bdp->repeat16, write_buffer);
691                         return;
692                 }
693         }
694
695 }
696
697 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
698  This is primarily a twofold loop that tries to find all the records in a
699  configuration file and hand over each non-empty line to functions further
700  up in the food chain. The reason for it being so long, is that important
701  error handling must be performed right at the end of a record, such as
702  freeing memory allocated to strings. We allow, at a minimum, a configuration
703  file to consist of 1 record seperator %% and 1 keyword ProgramName using
704  the string "default". The program will not accomplish one iota with such
705  a minimalistic file, but we pass it as valid:
706  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
707
708 static void read_body(FILE* errorfp, void* address, const int model,
709                                                         const char* configfile)
710 {
711         const char* def_rec = "default";
712
713 /* Reset status. Better safe than sorry: */
714         revert_config = 0;
715         pgr_recname_malloced = 0;
716         st1_prcurve_malloced = 0;
717         st2_prcurve_malloced = 0;
718
719         struct i3_program* pi3 = NULL;
720         struct i3s_program* pi3s = NULL;
721         struct g4_program* pg4 = NULL;
722         struct g4b_program* pg4b = NULL;
723         struct nop_program* pnop = NULL;
724         struct i3_program* pi3_base = NULL;
725         struct i3s_program* pi3s_base = NULL;
726         struct g4_program* pg4_base = NULL;
727         struct g4b_program* pg4b_base = NULL;
728         struct nop_program* pnop_base = NULL;
729
730         if (model == i3) {
731                 pi3 = address;
732                 pi3_base = pi3;
733                 if (reread_config) {
734                         pi3->default_program = NULL;
735                         pi3->common_data.num_record = 0;
736                 }
737         } else if (model == i3s) {
738                 pi3s = address;
739                 pi3s_base = pi3s;
740                 if (reread_config) {
741                         pi3s->default_program = NULL;
742                         pi3s->common_data.num_record = 0;
743                 }
744         } else if (model == g4) {
745                 pg4 = address;
746                 pg4_base = pg4;
747                 if (reread_config) {
748                         pg4->default_program = NULL;
749                         pg4->common_data.num_record = 0;
750                 }
751         } else if (model == g4b) {
752                 pg4b = address;
753                 pg4b_base = pg4b;
754                 if (reread_config) {
755                         pg4b->default_program = NULL;
756                         pg4b->common_data.num_record = 0;
757                 }
758         } else if (model == nop) {
759                 pnop = address;
760                 pnop_base = pnop;
761                 if (reread_config) {
762                         pnop->default_program = NULL;
763                         pnop->common_data.num_record = 0;
764                 }
765         }
766
767         FILE* fp = NULL;
768
769 /* Endless loop protection variable: */
770         long last_position = 0;
771
772         int num_record = 0;
773         int no_default = 0;
774         int line_limit = 0;
775
776         char read_buffer[MAXBUFFER];
777
778         char* newline = NULL;
779         char* comment = NULL;
780         char* record = NULL;
781
782         if ((fp = fopen(configfile, "r")) == NULL) {
783                 exit_on_error(errorfp,
784                                 "\n%s ERROR: Can not open %s in read mode\n",
785                                                 our_prog_name, configfile);
786         }
787
788 /* Find the very first record separator %% outside a comment # */
789
790         while ((fgets(read_buffer, MAXBUFFER, fp) != NULL)
791                 && (line_limit < MAXRECORDS * LINELIMIT)) {
792
793                 line_limit++;
794
795                 if ((newline = strchr(read_buffer, '\n')) == NULL) {
796                         fclose(fp);
797                         exit_on_error(errorfp,
798         "\n%s ERROR: A line was too long to handle in the Config File %s\n",
799                                                 our_prog_name, configfile);
800                 }
801
802                 if (newline == read_buffer) {
803                         continue;
804                 }
805
806                 if (((record = (strstr(read_buffer, "%%"))) != NULL)
807                         && (((comment = (strchr(read_buffer, '#'))) == NULL)
808                                                 || (record < comment))) {
809                         break;
810                 }
811         }
812
813 /* Begin record loop */
814
815         while ((num_record < MAXRECORDS)
816                 && (line_limit < MAXRECORDS * LINELIMIT)
817                 && ((record = (strstr(read_buffer, "%%"))) != NULL)
818                 && (((comment = (strchr(read_buffer, '#'))) == NULL)
819                                         || (record < comment))) {
820
821 /* Protect us from a really broken configuration file (endless loop): */
822                 if (last_position == ftell(fp)) {
823                         break;
824                 }
825                 last_position = ftell(fp);
826
827 /* Begin field loop*/
828
829                 while ((fgets(read_buffer, MAXBUFFER, fp) != NULL)
830                         && (((record = (strstr(read_buffer, "%%"))) == NULL)
831                         || (((comment = (strchr(read_buffer, '#'))) != NULL)
832                                                 && (comment < record)))) {
833
834                         line_limit++;
835                         if (line_limit >= MAXRECORDS * LINELIMIT) {
836                                 break;
837                         }
838
839                         if ((newline = strchr(read_buffer, '\n')) == NULL) {
840                                 fclose(fp);
841                                 exit_on_error(errorfp,
842         "\n%s ERROR: A line was too long to handle in the Config File %s\n",
843                                                 our_prog_name, configfile);
844                         }
845
846                         if (newline == read_buffer) {
847                                 continue;
848                         }
849
850                         if (pi3) {
851                                 handle_field(errorfp, read_buffer, pi3, model);
852                         } else if (pi3s) {
853                                 handle_field(errorfp, read_buffer, pi3s, model);
854                         } else if (pg4) {
855                                 handle_field(errorfp, read_buffer, pg4, model);
856                         } else if (pg4b) {
857                                 handle_field(errorfp, read_buffer, pg4b, model);
858                         } else if (pnop) {
859                                 handle_field(errorfp, read_buffer, pnop, model);
860                         }
861                 }
862
863 /* End field loop*/
864
865                 if (pi3) {
866                         if (pi3->common_data.class_name == NULL) {
867                                 revert_config = 1;
868                                 if (pi3->common_data.stylus1_presscurve
869                                                                 != NULL) {
870                                 free(pi3->common_data.stylus1_presscurve);
871                                 st1_prcurve_malloced = 0;
872                                 pi3->common_data.stylus1_presscurve = NULL;
873                                 }
874                                 if (pi3->common_data.stylus2_presscurve
875                                                                 != NULL) {
876                                 free(pi3->common_data.stylus2_presscurve);
877                                 st2_prcurve_malloced = 0;
878                                 pi3->common_data.stylus2_presscurve = NULL;
879                                 }
880                         }
881                         if ((pi3->common_data.class_name != NULL)
882                                 && (strcmp(pi3->common_data.class_name,
883                                                         def_rec) == 0)) {
884                                 pi3_base->default_program = pi3;
885                         }
886                         if (pi3->common_data.class_name != NULL) {
887                                 pgr_recname_malloced = 0;
888                                 revert_config = 0;
889                                 num_record++;
890                                 if (pi3->common_data.stylus1_presscurve
891                                                                 != NULL) {
892                                         st1_prcurve_malloced = 0;
893                                 }
894                                 if (pi3->common_data.stylus2_presscurve
895                                                                 != NULL) {
896                                         st2_prcurve_malloced = 0;
897                                 }
898                                 pi3++;
899                         }
900                 } else if (pi3s) {
901                         if (pi3s->common_data.class_name == NULL) {
902                                 revert_config = 1;
903                                 if (pi3s->common_data.stylus1_presscurve
904                                                                 != NULL) {
905                                 free(pi3s->common_data.stylus1_presscurve);
906                                 st1_prcurve_malloced = 0;
907                                 pi3s->common_data.stylus1_presscurve = NULL;
908                                 }
909                                 if (pi3s->common_data.stylus2_presscurve
910                                                                 != NULL) {
911                                 free(pi3s->common_data.stylus2_presscurve);
912                                 st2_prcurve_malloced = 0;
913                                 pi3s->common_data.stylus2_presscurve = NULL;
914                                 }
915                         }
916                         if ((pi3s->common_data.class_name != NULL)
917                                 && (strcmp(pi3s->common_data.class_name,
918                                                         def_rec) == 0)) {
919                                 pi3s_base->default_program = pi3s;
920                         }
921                         if (pi3s->common_data.class_name != NULL) {
922                                 pgr_recname_malloced = 0;
923                                 revert_config = 0;
924                                 num_record++;
925                                 if (pi3s->common_data.stylus1_presscurve
926                                                                 != NULL) {
927                                         st1_prcurve_malloced = 0;
928                                 }
929                                 if (pi3s->common_data.stylus2_presscurve
930                                                                 != NULL) {
931                                         st2_prcurve_malloced = 0;
932                                 }
933                                 pi3s++;
934                         }
935                 } else if (pg4) {
936                         if (pg4->common_data.class_name == NULL) {
937                                 revert_config = 1;
938                                 if (pg4->common_data.stylus1_presscurve
939                                                                 != NULL) {
940                                 free(pg4->common_data.stylus1_presscurve);
941                                 st1_prcurve_malloced = 0;
942                                 pg4->common_data.stylus1_presscurve = NULL;
943                                 }
944                                 if (pg4->common_data.stylus2_presscurve
945                                                                 != NULL) {
946                                 free(pg4->common_data.stylus2_presscurve);
947                                 st2_prcurve_malloced = 0;
948                                 pg4->common_data.stylus2_presscurve = NULL;
949                                 }
950                         }
951                         if ((pg4->common_data.class_name != NULL)
952                                 && (strcmp(pg4->common_data.class_name,
953                                                         def_rec) == 0)) {
954                                 pg4_base->default_program = pg4;
955                         }
956                         if (pg4->common_data.class_name != NULL) {
957                                 pgr_recname_malloced = 0;
958                                 revert_config = 0;
959                                 num_record++;
960                                 if (pg4->common_data.stylus1_presscurve
961                                                                 != NULL) {
962                                         st1_prcurve_malloced = 0;
963                                 }
964                                 if (pg4->common_data.stylus2_presscurve
965                                                                 != NULL) {
966                                         st2_prcurve_malloced = 0;
967                                 }
968                                 pg4++;
969                         }
970                 } else if (pg4b) {
971                         if (pg4b->common_data.class_name == NULL) {
972                                 revert_config = 1;
973                                 if (pg4b->common_data.stylus1_presscurve
974                                                                 != NULL) {
975                                 free(pg4b->common_data.stylus1_presscurve);
976                                 st1_prcurve_malloced = 0;
977                                 pg4b->common_data.stylus1_presscurve = NULL;
978                                 }
979                                 if (pg4b->common_data.stylus2_presscurve
980                                                                 != NULL) {
981                                 free(pg4b->common_data.stylus2_presscurve);
982                                 st2_prcurve_malloced = 0;
983                                 pg4b->common_data.stylus2_presscurve = NULL;
984                                 }
985                         }
986                         if ((pg4b->common_data.class_name != NULL)
987                                 && (strcmp(pg4b->common_data.class_name,
988                                                         def_rec) == 0)) {
989                                 pg4b_base->default_program = pg4b;
990                         }
991                         if (pg4b->common_data.class_name != NULL) {
992                                 pgr_recname_malloced = 0;
993                                 revert_config = 0;
994                                 num_record++;
995                                 if (pg4b->common_data.stylus1_presscurve
996                                                                 != NULL) {
997                                         st1_prcurve_malloced = 0;
998                                 }
999                                 if (pg4b->common_data.stylus2_presscurve
1000                                                                 != NULL) {
1001                                         st2_prcurve_malloced = 0;
1002                                 }
1003                                 pg4b++;
1004                         }
1005                 } else if (pnop) {
1006                         if (pnop->common_data.class_name == NULL) {
1007                                 revert_config = 1;
1008                                 if (pnop->common_data.stylus1_presscurve
1009                                                                 != NULL) {
1010                                 free(pnop->common_data.stylus1_presscurve);
1011                                 st1_prcurve_malloced = 0;
1012                                 pnop->common_data.stylus1_presscurve = NULL;
1013                                 }
1014                                 if (pnop->common_data.stylus2_presscurve
1015                                                                 != NULL) {
1016                                 free(pnop->common_data.stylus2_presscurve);
1017                                 st2_prcurve_malloced = 0;
1018                                 pnop->common_data.stylus2_presscurve = NULL;
1019                                 }
1020                         }
1021                         if ((pnop->common_data.class_name != NULL)
1022                                 && (strcmp(pnop->common_data.class_name,
1023                                                         def_rec) == 0)) {
1024                                 pnop_base->default_program = pnop;
1025                         }
1026                         if (pnop->common_data.class_name != NULL) {
1027                                 pgr_recname_malloced = 0;
1028                                 revert_config = 0;
1029                                 num_record++;
1030                                 if (pnop->common_data.stylus1_presscurve
1031                                                                 != NULL) {
1032                                         st1_prcurve_malloced = 0;
1033                                 }
1034                                 if (pnop->common_data.stylus2_presscurve
1035                                                                 != NULL) {
1036                                         st2_prcurve_malloced = 0;
1037                                 }
1038                                 pnop++;
1039                         }
1040                 }
1041         }
1042
1043 /* End record loop */
1044
1045         fclose(fp);
1046
1047         if (model == i3) {
1048                 pi3 = address;
1049                 if (pi3->default_program == NULL) {
1050                         no_default = 1;
1051                 }
1052                 pi3->common_data.num_record = num_record;
1053         } else if (model == i3s) {
1054                 pi3s = address;
1055                 if (pi3s->default_program == NULL) {
1056                         no_default = 1;
1057                 }
1058                 pi3s->common_data.num_record = num_record;
1059         } else if (model == g4) {
1060                 pg4 = address;
1061                 if (pg4->default_program == NULL) {
1062                         no_default = 1;
1063                 }
1064                 pg4->common_data.num_record = num_record;
1065         } else if (model == g4b) {
1066                 pg4b = address;
1067                 if (pg4b->default_program == NULL) {
1068                         no_default = 1;
1069                 }
1070                 pg4b->common_data.num_record = num_record;
1071         } else if (model == nop) {
1072                 pnop = address;
1073                 if (pnop->default_program == NULL) {
1074                         no_default = 1;
1075                 }
1076                 pnop->common_data.num_record = num_record;
1077         }
1078
1079         if (no_default) {
1080 exit_on_error(errorfp, "\n%s ERROR: A program record named \"default\" must \
1081 exist in\n%s\n", our_prog_name, configfile);
1082         }
1083
1084         if (be_verbose) {
1085                 fprintf(stderr, "PGR RECORDS = %i (of max %i)\n\n",
1086                                                         num_record, MAXRECORDS);
1087         }
1088
1089 }
1090
1091 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1092  If running in verbose mode we print out the names of all devices:
1093  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
1094
1095 static void print_device(FILE* statusfp, const char* padname,
1096                                 const char* sty1name, const char* sty2name)
1097 {
1098         fprintf(statusfp, "%s  = %s\n", padstr, (padname?padname :"LACKING"));
1099         fprintf(statusfp, "%s = %s\n", sty1str, (sty1name?sty1name :"LACKING"));
1100         fprintf(statusfp, "%s = %s\n", sty2str, (sty2name?sty2name :"LACKING"));
1101
1102 }
1103
1104 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1105  Try to find a digit representing the ConfigVersion in a configuration file:
1106  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
1107
1108 static int read_header(FILE* errorfp, char* write_buffer,const char* configfile)
1109 {
1110         FILE* fp = NULL;
1111
1112         char read_buffer[MAXBUFFER];
1113
1114         int k = 0;
1115         int line_limit = 0;
1116
1117         char* end_pos = NULL;
1118         char* newline = NULL;
1119         char* comment = NULL;
1120         char* record = NULL;
1121         char* field = NULL;
1122
1123         if ((fp = fopen(configfile, "r")) == NULL) {
1124                 exit_on_error(errorfp,
1125                                 "\n%s ERROR: Can not open %s in read mode\n",
1126                                                 our_prog_name, configfile);
1127         }
1128
1129         while ((fgets(read_buffer, MAXBUFFER, fp) != NULL)
1130                 && (!k)
1131                 && (line_limit < MAXRECORDS * LINELIMIT)
1132                 && (((record = (strstr(read_buffer, "%%"))) == NULL)
1133                 || (((comment = (strchr(read_buffer, '#'))) != NULL)
1134                                         && (comment < record)))) {
1135
1136                 line_limit++;
1137
1138                 if ((newline = strchr(read_buffer, '\n')) == NULL) {
1139                         fclose(fp);
1140                         exit_on_error(errorfp,
1141         "\n%s ERROR: A line was too long to handle in the Config File %s\n",
1142                                                 our_prog_name, configfile);
1143                 }
1144
1145                 if (newline == read_buffer) {
1146                         continue;
1147                 }
1148
1149                 if (((field = (strstr(read_buffer, configstring)))
1150                                                                 != NULL)
1151                         && (((comment = (strchr(read_buffer, '#')))
1152                                                                 == NULL)
1153                                                 || (field < comment))) {
1154                         prune_field(field, write_buffer);
1155                         end_pos = write_buffer + strlen(write_buffer);
1156                         for (; write_buffer < end_pos; write_buffer++) {
1157                                 if (isdigit(write_buffer[0])) {
1158                                         write_buffer[1] = '\0';
1159                                         k = atoi(write_buffer);
1160                                         break;
1161                                 }
1162                         }
1163                 }
1164         }
1165
1166         fclose(fp);
1167
1168         if (k && be_verbose) {
1169                 fprintf(stderr, "%s-user = %s\n", configstring, write_buffer);
1170                 fprintf(stderr, "%s-ours = %s\n", configstring, configversion);
1171         }
1172
1173         if (!k) {
1174                 fprintf(stderr, "%s-user = %i\n", configstring, k);
1175                 fprintf(stderr, "%s-ours = %s\n", configstring, configversion);
1176                 fprintf(stderr,"ConfigVersion not present. Skipping file:\n");
1177                 fprintf(stderr, "%s\n\n", configfile);
1178                 return 0;
1179         }
1180
1181         if (k != atoi(configversion)) {
1182         fprintf(stderr,"ConfigVersion %i is unsupported. Skipping file:\n",k);
1183                 fprintf(stderr, "%s\n\n", configfile);
1184                 return 0;
1185         }
1186
1187         ok_config = 1;
1188         return k;
1189
1190 }
1191
1192 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1193  Hand over all the associated configuration files for further processing:
1194  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
1195
1196 void read_config(FILE* errorfp)
1197 {
1198         int i, k;
1199         const char* our_cnffile = "OUR CNFFILE =";
1200         char write_buffer[MAXBUFFER];
1201
1202         ok_config = 0;
1203
1204         struct model_index* mip;
1205         mip = model_list;
1206
1207         for (i = 0; i < MAXPAD; i++, mip++) {
1208                 if (mip->i3->common_data.configfile) {
1209                         if (be_verbose) {
1210                                 fprintf(stderr, "%s %s\n", our_cnffile,
1211                                 mip->i3->common_data.configfile);
1212                         }
1213
1214                         if ((k = read_header(errorfp, write_buffer,
1215                                         mip->i3->common_data.configfile))) {
1216                                 mip->i3->common_data.userconfigversion = k;
1217                                 if (be_verbose) {
1218                                         print_device(stderr,
1219                                                 mip->i3->common_data.padname,
1220                                                 mip->i3->common_data.sty1name,
1221                                                 mip->i3->common_data.sty2name);
1222                                 }
1223                                 read_body(errorfp, mip->i3, i3,
1224                                         mip->i3->common_data.configfile);
1225                         }
1226                 }
1227                 if (mip->i3s->common_data.configfile) {
1228                         if (be_verbose) {
1229                                 fprintf(stderr, "%s %s\n", our_cnffile,
1230                                 mip->i3s->common_data.configfile);
1231                         }
1232                         if ((k = read_header(errorfp, write_buffer,
1233                                         mip->i3s->common_data.configfile))) {
1234                                 mip->i3s->common_data.userconfigversion = k;
1235                                 if (be_verbose) {
1236                                         print_device(stderr,
1237                                                 mip->i3s->common_data.padname,
1238                                                 mip->i3s->common_data.sty1name,
1239                                                 mip->i3s->common_data.sty2name);
1240                                 }
1241                                 read_body(errorfp, mip->i3s, i3s,
1242                                         mip->i3s->common_data.configfile);
1243                         }
1244                 }
1245                 if (mip->g4->common_data.configfile) {
1246                         if (be_verbose) {
1247                                 fprintf(stderr, "%s %s\n", our_cnffile,
1248                                 mip->g4->common_data.configfile);
1249                         }
1250                         if ((k = read_header(errorfp, write_buffer,
1251                                         mip->g4->common_data.configfile))) {
1252                                 mip->g4->common_data.userconfigversion = k;
1253                                 if (be_verbose) {
1254                                         print_device(stderr,
1255                                                 mip->g4->common_data.padname,
1256                                                 mip->g4->common_data.sty1name,
1257                                                 mip->g4->common_data.sty2name);
1258                                 }
1259                                 read_body(errorfp, mip->g4, g4,
1260                                         mip->g4->common_data.configfile);
1261                         }
1262                 }
1263                 if (mip->g4b->common_data.configfile) {
1264                         if (be_verbose) {
1265                                 fprintf(stderr, "%s %s\n", our_cnffile,
1266                                 mip->g4b->common_data.configfile);
1267                         }
1268                         if ((k = read_header(errorfp, write_buffer,
1269                                         mip->g4b->common_data.configfile))) {
1270                                 mip->g4b->common_data.userconfigversion = k;
1271                                 if (be_verbose) {
1272                                         print_device(stderr,
1273                                                 mip->g4b->common_data.padname,
1274                                                 mip->g4b->common_data.sty1name,
1275                                                 mip->g4b->common_data.sty2name);
1276                                 }
1277                                 read_body(errorfp, mip->g4b, g4b,
1278                                         mip->g4b->common_data.configfile);
1279                         }
1280                 }
1281                 if (mip->nop->common_data.configfile) {
1282                         if (be_verbose) {
1283                                 fprintf(stderr, "%s %s\n", our_cnffile,
1284                                 mip->nop->common_data.configfile);
1285                         }
1286                         if ((k = read_header(errorfp, write_buffer,
1287                                         mip->nop->common_data.configfile))) {
1288                                 mip->nop->common_data.userconfigversion = k;
1289                                 if (be_verbose) {
1290                                         print_device(stderr, NULL,
1291                                                 mip->nop->common_data.sty1name,
1292                                                 mip->nop->common_data.sty2name);
1293                                 }
1294                                 read_body(errorfp, mip->nop, nop,
1295                                         mip->nop->common_data.configfile);
1296                         }
1297                 }
1298         }
1299
1300 }
1301
1302 /* End Code */
1303