summaryrefslogtreecommitdiff
path: root/Build/source/utils/dialog/rc.c
blob: 6b956a662551faca02061583f979e111d9671f0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
/*
 *  rc.c -- routines for processing the configuration file
 *
 *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_NCURSES

#include "dialog.h"
#include "colors.h"
#include "rc.h"


static char *attr_to_str(int fg, int bg, int hl);
static int str_to_attr(char *str, int *fg, int *bg, int *hl);
static int parse_line(char *line, char **var, char **value);


/*
 * Create the configuration file
 */
void create_rc(char *filename)
{
  int i;
  FILE *rc_file;

  if ((rc_file = fopen(filename, "wt")) == NULL) {
    fprintf(stderr, "\nError opening file for writing in create_rc().\n");
    exit(-1);
  }

  fprintf(rc_file, "#\
\n# Run-time configuration file for dialog\
\n#\
\n# Automatically generated by \"dialog --create-rc <file>\"\
\n#\
\n#\
\n# Types of values:\
\n#\
\n# Number     -  <number>\
\n# String     -  \"string\"\
\n# Boolean    -  <ON|OFF>\
\n# Attribute  -  (foreground,background,highlight?)\
\n#\n\n");

  /* Print an entry for each configuration variable */
  for (i = 0; i < VAR_COUNT; i++) {
    fprintf(rc_file, "\n# %s\n", vars[i].comment);    /* print comment */
    switch (vars[i].type) {
      case VAL_INT:
        fprintf(rc_file, "%s = %d\n", vars[i].name, *((int *) vars[i].var));
        break;
      case VAL_STR:
        fprintf(rc_file, "%s = \"%s\"\n", vars[i].name, (char *) vars[i].var);
        break;
      case VAL_BOOL:
        fprintf(rc_file, "%s = %s\n", vars[i].name, *((bool *) vars[i].var) ? "ON" : "OFF");
        break;
      case VAL_ATTR:
        fprintf(rc_file, "%s = %s\n", vars[i].name, attr_to_str(((int *) vars[i].var)[0], ((int *) vars[i].var)[1], ((int *) vars[i].var)[2]));
        break;
    }
  }

  fclose(rc_file);
}
/* End of create_rc() */


/*
 * Parse the configuration file and set up variables
 */
int parse_rc(void)
{
  int i, l = 1, parse, fg, bg, hl;
  char str[MAX_LEN+1], *var, *value, *tempptr;
  FILE *rc_file;

  /*
   *
   *  At start, 'dialog' determines the settings to use as follows:
   *
   *  a) if environment variable DIALOGRC is set, it's value determines the
   *     name of the configuration file.
   *
   *  b) if the file in (a) can't be found, use the file $HOME/.dialogrc
   *     as the configuration file.
   *
   *  c) if the file in (b) can't be found, use compiled in defaults.
   *
   */

  if ((tempptr = getenv("DIALOGRC")) != NULL)
    rc_file = fopen(tempptr, "rt");

  if (tempptr == NULL || rc_file == NULL) {    /* step (a) failed? */
    /* try step (b) */
    if ((tempptr = getenv("HOME")) == NULL)
      return 0;    /* step (b) failed, use default values */

    if (tempptr[0] == '\0' || lastch(tempptr) == '/')
      sprintf(str, "%s%s", tempptr, DIALOGRC);
    else
      sprintf(str, "%s/%s", tempptr, DIALOGRC);

    if ((rc_file = fopen(str, "rt")) == NULL)
      return 0;    /* step (b) failed, use default values */
  }

  /* Scan each line and set variables */
  while (fgets(str, MAX_LEN, rc_file) != NULL) {
    if (lastch(str) != '\n') {    /* ignore rest of file if line too long */
      fprintf(stderr, "\nParse error: line %d of configuration file too long.\n", l);
      fclose(rc_file);
      return -1;    /* parse aborted */
    }
    else {
      lastch(str) = '\0';
      parse = parse_line(str, &var, &value);    /* parse current line */

      switch (parse) {
	case LINE_BLANK:    /* ignore blank lines and comments */
        case LINE_COMMENT:
          break;
        case LINE_OK:
          /* search table for matching config variable name */
          for (i = 0; i < VAR_COUNT && strcmp(vars[i].name, var); i++);

          if (i == VAR_COUNT) {    /* no match */
            fprintf(stderr, "\nParse error: unknown variable at line %d of configuration file.\n", l);
            return -1;    /* parse aborted */
          }
          else {    /* variable found in table, set run time variables */
            switch (vars[i].type) {
              case VAL_INT:
                *((int *) vars[i].var) = atoi(value);
                break;
              case VAL_STR:
                if (!isquote(value[0]) || !isquote(lastch(value)) || strlen(value) < 2) {
                  fprintf(stderr, "\nParse error: string value expected at line %d of configuration file.\n", l);
                  return -1;    /* parse aborted */
                }
                else {
                  /* remove the (") quotes */
                  value++;
                  lastch(value) = '\0';
                  strcpy((char *) vars[i].var, value);
		}
                break;
              case VAL_BOOL:
                if (!strcasecmp(value, "ON"))
                  *((bool *) vars[i].var) = TRUE;
                else if (!strcasecmp(value, "OFF"))
                  *((bool *) vars[i].var) = FALSE;
                else {
                  fprintf(stderr, "\nParse error: boolean value expected at line %d of configuration file.\n", l);
                  return -1;    /* parse aborted */
                }
                break;
              case VAL_ATTR:
                if (str_to_attr(value, &fg, &bg, &hl) == -1) {
                  fprintf(stderr, "\nParse error: attribute value expected at line %d of configuration file.\n", l);
                  return -1;    /* parse aborted */
                }
                ((int *) vars[i].var)[0] = fg;
                ((int *) vars[i].var)[1] = bg;
                ((int *) vars[i].var)[2] = hl;
                break;
            }
          }
          break;
        case LINE_ERROR:
          fprintf(stderr, "\nParse error: syntax error at line %d of configuration file.\n", l);
          return -1;    /* parse aborted */
      }
    }

    l++;    /* next line */
  }

  fclose(rc_file);
  return 0;    /* parse successful */
}
/* End of parse_rc() */


/*
 * Convert an attribute to a string representation like this:
 *
 * "(foreground,background,highlight)"
 */
static char *attr_to_str(int fg, int bg, int hl)
{
  int i;
  static char str[MAX_LEN+1];

  strcpy(str, "(");
  /* foreground */
  for (i = 0; fg != color_names[i].value; i++);
  strcat(str, color_names[i].name);
  strcat(str, ",");

  /* background */
  for (i = 0; bg != color_names[i].value; i++);
  strcat(str, color_names[i].name);

  /* highlight */
  strcat(str, hl ? ",ON)" : ",OFF)");

  return str;
}
/* End of attr_to_str() */


/*
 * Extract the foreground, background and highlight values from an attribute
 * represented as a string in this form:
 *
 * "(foreground,background,highlight)"
 */
static int str_to_attr(char *str, int *fg, int *bg, int *hl)
{
  int i = 0, j, get_fg = 1;
  char tempstr[MAX_LEN+1], *part;

  if (str[0] != '(' || lastch(str) != ')')
    return -1;    /* invalid representation */

  /* remove the parenthesis */
  strcpy(tempstr, str + 1);
  lastch(tempstr) = '\0';


  /* get foreground and background */

  while (1) {
    /* skip white space before fg/bg string */
    while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
    if (tempstr[i] == '\0')
      return -1;    /* invalid representation */
    part = tempstr + i;    /* set 'part' to start of fg/bg string */

    /* find end of fg/bg string */
    while(!whitespace(tempstr[i]) && tempstr[i] != ',' && tempstr[i] != '\0') i++;

    if (tempstr[i] == '\0')
      return -1;    /* invalid representation */
    else if (whitespace(tempstr[i])) {   /* not yet ',' */
      tempstr[i++] = '\0';

      /* skip white space before ',' */
      while(whitespace(tempstr[i]) && tempstr[i] != '\0') i++;

      if (tempstr[i] != ',')
        return -1;    /* invalid representation */
    }

    tempstr[i++] = '\0';    /* skip the ',' */
    for (j = 0; j < COLOR_COUNT && strcasecmp(part, color_names[j].name); j++);
    if (j == COLOR_COUNT)    /* invalid color name */
      return -1;
    if (get_fg) {
      *fg = color_names[j].value;
      get_fg = 0;    /* next we have to get the background */
    }
    else {
      *bg = color_names[j].value;
      break;
    }
  }   /* got foreground and background */


  /* get highlight */

  /* skip white space before highlight string */
  while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
  if (tempstr[i] == '\0')
    return -1;    /* invalid representation */
  part = tempstr + i;    /* set 'part' to start of highlight string */

  /* trim trailing white space from highlight string */
  i = strlen(part) - 1;
  while(whitespace(part[i])) i--;
  part[i+1] = '\0';

  if (!strcasecmp(part, "ON"))
    *hl = TRUE;
  else if (!strcasecmp(part, "OFF"))
    *hl = FALSE;
  else
    return -1;    /* invalid highlight value */

  return 0;
}
/* End of str_to_attr() */


/*
 * Parse a line in the configuration file
 *
 * Each line is of the form:  "variable = value". On exit, 'var' will contain
 * the variable name, and 'value' will contain the value string.
 *
 * Return values:
 *
 * LINE_BLANK   - line is blank
 * LINE_COMMENT - line is comment
 * LINE_OK      - line is ok
 * LINE_ERROR   - syntax error in line
 */
static int parse_line(char *line, char **var, char **value)
{
  int i = 0;

  /* ignore white space at beginning of line */
  while(whitespace(line[i]) && line[i] != '\0') i++;

  if (line[i] == '\0')    /* line is blank */
    return LINE_BLANK;
  else if (line[i] == '#')    /* line is comment */
    return LINE_COMMENT;
  else if (line[i] == '=')    /* variables names can't strart with a '=' */
    return LINE_ERROR;

  /* set 'var' to variable name */
  *var = line + i++;    /* skip to next character */

  /* find end of variable name */
  while(!whitespace(line[i]) && line[i] != '=' && line[i] != '\0') i++;

  if (line[i] == '\0')    /* syntax error */
    return LINE_ERROR;
  else if (line[i] == '=')
    line[i++] = '\0';
  else {
    line[i++] = '\0';

    /* skip white space before '=' */
    while(whitespace(line[i]) && line[i] != '\0') i++;

    if (line[i] != '=')    /* syntax error */
      return LINE_ERROR;
    else
      i++;    /* skip the '=' */
  }

  /* skip white space after '=' */
  while(whitespace(line[i]) && line[i] != '\0') i++;

  if (line[i] == '\0')
    return LINE_ERROR;
  else
    *value = line + i;    /* set 'value' to value string */

  /* trim trailing white space from 'value' */
  i = strlen(*value) - 1;
  while(whitespace((*value)[i])) i--;
  (*value)[i+1] = '\0';

  return LINE_OK;    /* no syntax error in line */
}
/* End of parse_line() */
#endif