GnuCOBOL  2.0
A free COBOL compiler
config.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003-2012, 2014-2016 Free Software Foundation, Inc.
3  Written by Keisuke Nishida, Roger While, Simon Sobisch
4 
5  This file is part of GnuCOBOL.
6 
7  The GnuCOBOL compiler is free software: you can redistribute it
8  and/or modify it under the terms of the GNU General Public License
9  as published by the Free Software Foundation, either version 3 of the
10  License, or (at your option) any later version.
11 
12  GnuCOBOL is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with GnuCOBOL. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 
22 #include "config.h"
23 #include "defaults.h"
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stddef.h>
28 #include <string.h>
29 #include <ctype.h>
30 
31 #include "cobc.h"
32 
34  CB_ANY = 0,
35  CB_INT, /* integer */
36  CB_STRING, /* "..." */
37  CB_BOOLEAN, /* 'yes', 'no' */
38  CB_SUPPORT /* 'ok', 'archaic', 'obsolete',
39  'skip', 'ignore', 'unconformable' */
40 };
41 
42 /* Global variables */
43 
44 #undef CB_CONFIG_ANY
45 #undef CB_CONFIG_INT
46 #undef CB_CONFIG_STRING
47 #undef CB_CONFIG_BOOLEAN
48 #undef CB_CONFIG_SUPPORT
49 
50 #define CB_CONFIG_ANY(type,var,name) type var = (type)0;
51 #define CB_CONFIG_INT(var,name) unsigned int var = 0;
52 #define CB_CONFIG_STRING(var,name) const char *var = NULL;
53 #define CB_CONFIG_BOOLEAN(var,name) unsigned int var = 0;
54 #define CB_CONFIG_SUPPORT(var,name) enum cb_support var = CB_OK;
55 
56 #include "config.def"
57 
58 #undef CB_CONFIG_ANY
59 #undef CB_CONFIG_INT
60 #undef CB_CONFIG_STRING
61 #undef CB_CONFIG_BOOLEAN
62 #undef CB_CONFIG_SUPPORT
63 
64 #define CB_CONFIG_ANY(type,var,name) , {CB_ANY, name, (void *)&var, NULL}
65 #define CB_CONFIG_INT(var,name) , {CB_INT, name, (void *)&var, NULL}
66 #define CB_CONFIG_STRING(var,name) , {CB_STRING, name, (void *)&var, NULL}
67 #define CB_CONFIG_BOOLEAN(var,name) , {CB_BOOLEAN, name, (void *)&var, NULL}
68 #define CB_CONFIG_SUPPORT(var,name) , {CB_SUPPORT, name, (void *)&var, NULL}
69 
70 /* Local variables */
71 
72 static struct config_struct {
73  const enum cb_config_type type;
74  const char *name;
75  void *var;
76  char *val;
77 } config_table[] = {
78  {CB_STRING, "include", NULL, NULL},
79  {CB_STRING, "includeif", NULL, NULL},
80  {CB_STRING, "not-reserved", NULL, NULL},
81  {CB_STRING, "reserved", NULL, NULL}
82 #include "config.def"
83 };
84 
85 /* Configuration includes */
86 static struct includelist {
87  struct includelist *next;
88  const char *name;
89 } *conf_includes = NULL;
90 
91 #undef CB_CONFIG_ANY
92 #undef CB_CONFIG_INT
93 #undef CB_CONFIG_STRING
94 #undef CB_CONFIG_BOOLEAN
95 #undef CB_CONFIG_SUPPORT
96 
97 #define CB_CONFIG_SIZE sizeof(config_table) / sizeof(struct config_struct)
98 
99 /* Local functions */
100 
101 static char *
102 read_string (const char *text)
103 {
104  char *p;
105  char *s;
106 
107  s = cobc_main_strdup (text);
108  if (*s == '\"') {
109  s++;
110  }
111  for (p = s; *p; p++) {
112  if (*p == '\"') {
113  *p = '\0';
114  }
115  }
116  return s;
117 }
118 
119 static void
120 invalid_value (const char *fname, const int line, const char *name, const char *val,
121  const char *str, const int max, const int min)
122 {
123  configuration_error (fname, line, 0,
124  _("Invalid value '%s' for configuration tag '%s'"), val, name);
125  if (str) {
126  configuration_error (fname, line, 1,
127  _("should be one of the following values: %s"), str);
128  } else if (max == min && max == 0) {
129  configuration_error (fname, line, 1, _("must be numeric"));
130  } else if (max) {
131  configuration_error (fname, line, 1, _("maximum value: %lu"), (unsigned long)max);
132  } else {
133  configuration_error (fname, line, 1, _("minimum value: %lu"), (unsigned long)min);
134  }
135 }
136 
137 static void
138 unsupported_value (const char *fname, const int line, const char *name, const char *val)
139 {
140  configuration_error (fname, line, 1,
141  _("Unsupported value '%s' for configuration tag '%s'"), val, name);
142 }
143 
144 /* Global functions */
145 
146 int
147 cb_load_std (const char *name)
148 {
149  return cb_load_conf (name, 1);
150 }
151 
152 int
153 cb_config_entry (char *buff, const char *fname, const int line)
154 {
155  char *s;
156  const char *name;
157  char *e;
158  const char *val;
159  void *var;
160  size_t i;
161  size_t j;
162  int v;
163 
164  /* Get tag */
165  s = strpbrk (buff, " \t:=");
166  if (!s) {
167  for (j=strlen(buff); buff[j-1] == '\r' || buff[j-1] == '\n'; ) /* Remove CR LF */
168  buff[--j] = 0;
169  configuration_error (fname, line, 1,
170  _("Invalid configuration tag '%s'"), buff);
171  return -1;
172  }
173  *s = 0;
174 
175  /* Find entry */
176  for (i = 0; i < CB_CONFIG_SIZE; i++) {
177  if (strcmp (buff, config_table[i].name) == 0) {
178  break;
179  }
180  }
181  if (i == CB_CONFIG_SIZE) {
182  configuration_error (fname, line, 1, _("Unknown configuration tag '%s'"), buff);
183  return -1;
184  }
185 
186  /* Get value */
187  /* Move pointer to beginning of value */
188  for (s++; *s && strchr (" \t:=", *s); s++) {
189  ;
190  }
191  /* Set end pointer to first # (comment) or end of value */
192  for (e = s + 1; *e && !strchr ("#", *e); e++) {
193  ;
194  }
195  /* Remove trailing white-spaces */
196  for (--e; e >= s && strchr (" \t\r\n", *e); e--) {
197  ;
198  }
199  e[1] = 0;
200  config_table[i].val = s;
201 
202  /* Set value */
203  name = config_table[i].name;
204  var = config_table[i].var;
205  val = config_table[i].val;
206  switch (config_table[i].type) {
207  case CB_ANY:
208  if (strcmp (name, "assign-clause") == 0) {
209  if (strcmp (val, "cobol2002") == 0) {
210  unsupported_value (fname, line, name, val);
211  return -1;
212  } else if (strcmp (val, "mf") == 0) {
213  cb_assign_clause = CB_ASSIGN_MF;
214  } else if (strcmp (val, "ibm") == 0) {
215  cb_assign_clause = CB_ASSIGN_IBM;
216  } else {
217  invalid_value (fname, line, name, val, "cobol2002, mf, ibm", 0, 0);
218  return -1;
219  }
220  } else if (strcmp (name, "binary-size") == 0) {
221  if (strcmp (val, "2-4-8") == 0) {
222  cb_binary_size = CB_BINARY_SIZE_2_4_8;
223  } else if (strcmp (val, "1-2-4-8") == 0) {
224  cb_binary_size = CB_BINARY_SIZE_1_2_4_8;
225  } else if (strcmp (val, "1--8") == 0) {
226  cb_binary_size = CB_BINARY_SIZE_1__8;
227  } else {
228  invalid_value (fname, line, name, val, "2-4-8, 1-2-4-8, 1--8", 0, 0);
229  return -1;
230  }
231  } else if (strcmp (name, "binary-byteorder") == 0) {
232  if (strcmp (val, "native") == 0) {
233  cb_binary_byteorder = CB_BYTEORDER_NATIVE;
234  } else if (strcmp (val, "big-endian") == 0) {
235  cb_binary_byteorder = CB_BYTEORDER_BIG_ENDIAN;
236  } else {
237  invalid_value (fname, line, name, val, "native, big-endian", 0, 0);
238  return -1;
239  }
240  }
241  break;
242  case CB_INT:
243  for (j = 0; val[j]; j++) {
244  if (val[j] < '0' || val[j] > '9') {
245  invalid_value (fname, line, name, val, NULL, 0, 0);
246  return -1;
247  break;
248  }
249  }
250  v = atoi (val);
251  if (strcmp (name, "tab-width") == 0) {
252  if (v < 1) {
253  invalid_value (fname, line, name, val, NULL, 1, 0);
254  return -1;
255  }
256  if (v > 8) {
257  invalid_value (fname, line, name, val, NULL, 0, 8);
258  return -1;
259  }
260  } else if (strcmp (name, "text-column") == 0) {
261  if (v < 72) {
262  invalid_value (fname, line, name, val, NULL, 72, 0);
263  return -1;
264  }
265  if (v > 255) {
266  invalid_value (fname, line, name, val, NULL, 0, 255);
267  return -1;
268  }
269  } else if (strcmp (name, "word-length") == 0) {
270  if (v < 1) {
271  invalid_value (fname, line, name, val, NULL, 1, 0);
272  return -1;
273  }
274  if (v > COB_MAX_WORDLEN) {
275  invalid_value (fname, line, name, val, NULL, 0, COB_MAX_WORDLEN);
276  return -1;
277  }
278  }
279  *((int *)var) = v;
280  break;
281  case CB_STRING:
282  val = read_string (val);
283 
284  if (strcmp (name, "include") == 0 ||
285  strcmp (name, "includeif") == 0) {
286  if (fname) {
287  /* Include another conf file */
288  s = cob_expand_env_string((char *)val);
289  strcpy (buff, s);
290  cob_free (s);
291  if (strcmp (name, "includeif") == 0) {
292  return 3;
293  } else {
294  return 1;
295  }
296  } else {
297  configuration_error (NULL, 0, 1,
298  _("'%s' not supported with -cb_conf"), name);
299  return -1;
300  }
301  } else if (strcmp (name, "not-reserved") == 0) {
302  remove_reserved_word (val);
303  } else if (strcmp (name, "reserved") == 0) {
304  add_reserved_word (val, fname, line);
305  } else {
306  *((const char **)var) = val;
307  }
308 
309  break;
310  case CB_BOOLEAN:
311  if (strcmp (val, "yes") == 0) {
312  *((int *)var) = 1;
313  } else if (strcmp (val, "no") == 0) {
314  *((int *)var) = 0;
315  } else {
316  invalid_value (fname, line, name, val, "yes, no", 0, 0);
317  return -1;
318  }
319  break;
320  case CB_SUPPORT:
321  if (strcmp (val, "ok") == 0) {
322  *((enum cb_support *)var) = CB_OK;
323  } else if (strcmp (val, "warning") == 0) {
324  *((enum cb_support *)var) = CB_WARNING;
325  } else if (strcmp (val, "archaic") == 0) {
326  *((enum cb_support *)var) = CB_ARCHAIC;
327  } else if (strcmp (val, "obsolete") == 0) {
328  *((enum cb_support *)var) = CB_OBSOLETE;
329  } else if (strcmp (val, "skip") == 0) {
330  *((enum cb_support *)var) = CB_SKIP;
331  } else if (strcmp (val, "ignore") == 0) {
332  *((enum cb_support *)var) = CB_IGNORE;
333  } else if (strcmp (val, "error") == 0) {
334  *((enum cb_support *)var) = CB_ERROR;
335  } else if (strcmp (val, "unconformable") == 0) {
336  *((enum cb_support *)var) = CB_UNCONFORMABLE;
337  } else {
338  invalid_value (fname, line, name, val,
339  "ok, warning, archaic, obsolete, skip, ignore, error, unconformable", 0, 0);
340  return -1;
341  }
342  break;
343  default:
344  configuration_error (fname, line, 1, _("Invalid type for '%s'"), name);
345  return -1;
346  }
347  return 0;
348 }
349 
350 static int
351 cb_load_conf_file (const char *conf_file, int isoptional)
352 {
354  struct includelist *c, *cc;
355  const unsigned char *x;
356  FILE *fp;
357  int sub_ret, ret;
358  int i, line;
359  char buff[COB_SMALL_BUFF];
360 
361  for (i=0; conf_file[i] != 0 && conf_file[i] != SLASH_CHAR; i++);
362  if (conf_file[i] == 0) { /* Just a name, No directory */
363  if (access(conf_file, F_OK) != 0) { /* and file does not exist */
364  /* check for path of previous configuration file (for includes) */
365  c = conf_includes;
366  if (c) {
367  while (c->next != NULL) {
368  c = c->next;
369  }
370  }
371  filename[0] = 0;
372  if (c && c->name) {
373  strcpy(buff, conf_includes->name);
374  for (i = (int)strlen(buff); i != 0 && buff[i] != SLASH_CHAR; i--);
375  if (i != 0) {
376  buff[i] = 0;
377  snprintf(filename, (size_t)COB_NORMAL_MAX, "%s%c%s", buff, SLASH_CHAR, conf_file);
378  if (access(filename, F_OK) == 0) { /* and prefixed file exist */
379  conf_file = filename; /* Prefix last directory */
380  } else {
381  filename[0] = 0;
382  }
383  }
384  }
385  if (filename[0] == 0) {
386  /* check for COB_CONFIG_DIR (use default if not in environment) */
387  snprintf (filename, (size_t)COB_NORMAL_MAX, "%s%c%s", cob_config_dir, SLASH_CHAR, conf_file);
388  filename[COB_NORMAL_MAX] = 0;
389  if (access(filename, F_OK) == 0) { /* and prefixed file exist */
390  conf_file = filename; /* Prefix COB_CONFIG_DIR */
391  }
392  }
393  }
394  }
395 
396  /* check for recursion */
397  c = cc = conf_includes;
398  while (c != NULL) {
399  if (c->name /* <- silence warnings */ && strcmp(c->name, conf_file) == 0) {
400  configuration_error (conf_file, 0, 1, _("Recursive inclusion"));
401  return -2;
402  }
403  cc = c;
404  c = c->next;
405  }
406 
407  /* Open the configuration file */
408  fp = fopen (conf_file, "r");
409  if (fp == NULL) {
410  if (!isoptional) {
411  fflush (stderr);
412  configuration_error (conf_file, 0, 1, _("No such file or directory"));
413  return -1;
414  } else {
415  return 0;
416  }
417  }
418 
419  /* add current entry to list*/
420  c = cob_malloc (sizeof(struct includelist));
421  c->next = NULL;
422  c->name = conf_file;
423  if (cc != NULL) {
424  cc->next = c;
425  } else {
426  conf_includes = c;
427  }
428 
429  /* Read the configuration file */
430  ret = 0;
431  line = 0;
432  while (fgets (buff, COB_SMALL_BUFF, fp)) {
433  line++;
434 
435  /* Skip line comments, empty lines */
436  if (buff[0] == '#' || buff[0] == '\n') {
437  continue;
438  }
439 
440  /* Skip blank lines */
441  for (x = (const unsigned char *)buff; *x; x++) {
442  if (isgraph (*x)) {
443  break;
444  }
445  }
446  if (!*x) {
447  continue;
448  }
449 
450  sub_ret = cb_config_entry (buff, conf_file, line);
451  if (sub_ret == 1 || sub_ret == 3) {
452  sub_ret = cb_load_conf_file (buff, sub_ret == 3);
453  if (sub_ret < 0) {
454  ret = -1;
455  configuration_error (conf_file, line, 1,
456  _("Configuration file was included here"));
457  break;
458  }
459  }
460  if (sub_ret != 0) ret = sub_ret;
461  }
462  fclose (fp);
463 
464  /* remove current entry from memory and list*/
465  if (cc) {
466  cc->next = NULL;
467  } else {
469  }
470  cob_free (c);
471 
472  return ret;
473 }
474 
475 int
476 cb_load_conf (const char *fname, const int prefix_dir)
477 {
478  const char *name;
479  int ret;
480  size_t i;
481  char buff[COB_NORMAL_BUFF];
482 
483  /* Warn if we drop the configuration read already */
484  if (unlikely(cb_config_name != NULL)) {
485  configuration_warning (fname, 0,
486  _("The previous loaded configuration '%s' will be discarded"),
487  cb_config_name);
488  }
489 
490  /* Initialize the configuration table */
491  for (i = 0; i < CB_CONFIG_SIZE; i++) {
492  config_table[i].val = NULL;
493  }
494 
495  /* Get the name for the configuration file */
496  if (prefix_dir) {
497  snprintf (buff, (size_t)COB_NORMAL_MAX,
498  "%s%c%s", cob_config_dir, SLASH_CHAR, fname);
499  name = buff;
500  } else {
501  name = fname;
502  }
503 
504  ret = cb_load_conf_file (name, 0);
505 
506  /* Checks for missing definitions */
507  if (ret == 0) {
508  for (i = 4U; i < CB_CONFIG_SIZE; i++) {
509  if (config_table[i].val == NULL) {
510  /* as there are likely more than one definition missing group it */
511  if (ret == 0) {
512  configuration_error (fname, 0, 1, _("Missing definitions:"));
513  }
514  configuration_error (fname, 0, 1, _("\tNo definition of '%s'"),
515  config_table[i].name);
516  ret = -1;
517  }
518  }
519  }
520 
521  return ret;
522 }
void cob_free(void *mptr)
Definition: common.c:1284
const char * cob_config_dir
Definition: cobc.c:155
Definition: cobc.h:139
void * var
Definition: config.c:75
const char * name
Definition: config.c:88
static int cb_load_conf_file(const char *conf_file, int isoptional)
Definition: config.c:351
Definition: cobc.h:141
#define CB_ASSIGN_IBM
Definition: cobc.h:78
#define COB_NORMAL_BUFF
Definition: common.h:541
#define COB_SMALL_BUFF
Definition: common.h:540
int cb_config_entry(char *buff, const char *fname, const int line)
Definition: config.c:153
void remove_reserved_word(const char *)
Definition: reserved.c:2882
#define CB_CONFIG_SIZE
Definition: config.c:97
void configuration_warning(const char *, const int, const char *,...) COB_A_FORMAT34
Definition: error.c:144
static void unsupported_value(const char *fname, const int line, const char *name, const char *val)
Definition: config.c:138
Definition: cobc.h:135
#define COB_MAX_WORDLEN
Definition: common.h:574
cb_support
Definition: cobc.h:134
#define _(s)
Definition: cobcrun.c:59
#define CB_BINARY_SIZE_2_4_8
Definition: cobc.h:88
const char * name
Definition: config.c:74
#define unlikely(x)
Definition: common.h:437
char * val
Definition: config.c:76
#define F_OK
Definition: cobc.h:46
EC ARGUMENT EC EC BOUND EC BOUND EC BOUND EC BOUND TABLE EC DATA EC DATA EC DATA PTR NULL
Definition: exception.def:95
#define CB_BYTEORDER_BIG_ENDIAN
Definition: cobc.h:82
#define SLASH_CHAR
Definition: common.h:505
#define COB_NORMAL_MAX
Definition: common.h:547
static struct includelist * conf_includes
Definition: config.c:35
static struct config_struct config_table[]
#define CB_BYTEORDER_NATIVE
Definition: cobc.h:83
void * cobc_main_strdup(const char *dupstr)
Definition: cobc.c:720
#define CB_ASSIGN_MF
Definition: cobc.h:77
#define CB_BINARY_SIZE_1_2_4_8
Definition: cobc.h:86
static char * read_string(const char *text)
Definition: config.c:102
struct includelist * next
Definition: config.c:87
Definition: config.c:34
cb_config_type
Definition: config.c:33
char * cob_expand_env_string(char *strval)
Definition: common.c:4406
void configuration_error(const char *, const int, const int, const char *,...) COB_A_FORMAT45
Definition: error.c:178
if fold fold static computed alternate extra correct stack on syntax debugging line
Definition: flag.def:90
static void invalid_value(const char *fname, const int line, const char *name, const char *val, const char *str, const int max, const int min)
Definition: config.c:120
int cb_load_std(const char *name)
Definition: config.c:147
void add_reserved_word(const char *, const char *, const int)
Definition: reserved.c:2903
void * cob_malloc(const size_t size)
Definition: common.c:1250
#define CB_BINARY_SIZE_1__8
Definition: cobc.h:87
int cb_load_conf(const char *fname, const int prefix_dir)
Definition: config.c:476
Definition: cobc.h:195
enum cb_config_type type
Definition: config.c:73