LIRC libraries
LinuxInfraredRemoteControl
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Groups Pages
config_file.c
Go to the documentation of this file.
1 /****************************************************************************
2 ** config_file.c ***********************************************************
3 ****************************************************************************
4 *
5 *
6 * Copyright (C) 1998 Pablo d'Angelo <pablo@ag-trek.allgaeu.org>
7 *
8 */
9 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 
21 #include <dirent.h>
22 #include <errno.h>
23 #include <glob.h>
24 #include <limits.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <libgen.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 
37 #include "include/media/lirc.h"
38 #include "lirc/lirc_log.h"
39 #include "lirc/lirc_options.h"
40 #include "lirc/ir_remote.h"
41 #include "lirc/config_file.h"
42 #include "lirc/transmit.h"
43 #include "lirc/config_flags.h"
44 
45 
46 enum directive { ID_none, ID_remote, ID_codes, ID_raw_codes, ID_raw_name };
47 
48 struct ptr_array {
49  void** ptr;
50  size_t nr_items;
51  size_t chunk_size;
52 };
53 
54 struct void_array {
55  void* ptr;
56  size_t item_size;
57  size_t nr_items;
58  size_t chunk_size;
59 };
60 
61 
63 typedef void* (*array_guest_func)(void* item, void* arg);
64 
65 
66 #define LINE_LEN 1024
67 #define MAX_INCLUDES 10
68 
69 const char* whitespace = " \t";
70 
71 static int line;
72 static int parse_error;
73 
74 static struct ir_remote* read_config_recursive(FILE* f, const char* name, int depth);
75 static void calculate_signal_lengths(struct ir_remote* remote);
76 
77 void** init_void_array(struct void_array* ar, size_t chunk_size, size_t item_size)
78 {
79  ar->chunk_size = chunk_size;
80  ar->item_size = item_size;
81  ar->nr_items = 0;
82  ar->ptr = calloc(chunk_size, ar->item_size);
83  if (!ar->ptr) {
84  logprintf(LIRC_ERROR, "out of memory");
85  parse_error = 1;
86  return NULL;
87  }
88  return ar->ptr;
89 }
90 
91 const struct flaglist all_flags[] = {
92  { "RAW_CODES", RAW_CODES },
93  { "RC5", RC5 },
94  { "SHIFT_ENC", SHIFT_ENC }, /* obsolete */
95  { "RC6", RC6 },
96  { "RCMM", RCMM },
97  { "SPACE_ENC", SPACE_ENC },
98  { "SPACE_FIRST", SPACE_FIRST },
99  { "GOLDSTAR", GOLDSTAR },
100  { "GRUNDIG", GRUNDIG },
101  { "BO", BO },
102  { "SERIAL", SERIAL },
103  { "XMP", XMP },
104 
105  { "REVERSE", REVERSE },
106  { "NO_HEAD_REP", NO_HEAD_REP },
107  { "NO_FOOT_REP", NO_FOOT_REP },
108  { "CONST_LENGTH", CONST_LENGTH }, /* remember to adapt warning
109  * message when changing this */
110  { "REPEAT_HEADER", REPEAT_HEADER },
111  { NULL, 0 },
112 };
113 
114 
116 int add_void_array(struct void_array* ar, void* dataptr)
117 {
118  void* ptr;
119 
120  if ((ar->nr_items % ar->chunk_size) == (ar->chunk_size) - 1) {
121  /* I hope this works with the right alignment,
122  * if not we're screwed */
123  ptr = realloc(ar->ptr,
124  ar->item_size *
125  (ar->nr_items + ar->chunk_size + 1));
126  if (!ptr) {
127  logprintf(LIRC_ERROR, "out of memory");
128  parse_error = 1;
129  return 0;
130  }
131  ar->ptr = ptr;
132  }
133  memcpy((ar->ptr) + (ar->item_size * ar->nr_items), dataptr, ar->item_size);
134  ar->nr_items = (ar->nr_items) + 1;
135  memset((ar->ptr) + (ar->item_size * ar->nr_items), 0, ar->item_size);
136  return 1;
137 }
138 
139 
141 void* get_void_array(struct void_array* ar)
142 {
143  return ar->ptr;
144 }
145 
146 
151 static void*
152 foreach_void_array(struct void_array* ar, array_guest_func func, void* arg)
153 {
154  void* r;
155  int i;
156 
157  for (i = 0; i < ar->nr_items; i += 1) {
158  r = func(ar->ptr + (i * ar->item_size), arg);
159  if (r != NULL)
160  return r;
161  }
162  return NULL;
163 }
164 
165 
166 static int
167 ir_code_node_equals(struct ir_code_node* node1, struct ir_code_node* node2)
168 {
169  if (node1 == NULL || node2 == NULL)
170  return node1 == node2;
171  return node1->code == node2->code;
172 }
173 
174 
179 static void* array_guest_code_equals(void* arg1, void* arg2)
180 {
181 
182  struct ir_ncode* code1 = (struct ir_ncode*) arg1;
183  struct ir_ncode* code2 = (struct ir_ncode*) arg2;
184  struct ir_code_node* next1;
185  struct ir_code_node* next2;
186 
187  if (code1 == NULL || code2 == NULL)
188  return code1 == code2 ? arg1 : NULL;
189  if (code1->code != code2->code)
190  return NULL;
191  next1 = code1->next;
192  next2 = code2->next;
193  while (code1->next != NULL) {
194  if (!ir_code_node_equals(next1, next2))
195  return NULL;
196  next1 = code1->next;
197  next2 = code2->next;
198  }
199  return arg1;
200 }
201 
202 
207 static void* array_guest_ncode_cmp(void* item, void* arg)
208 {
209 
210  struct ir_ncode* code1 = (struct ir_ncode*) item;
211  struct ir_ncode* code2 = (struct ir_ncode*) arg;
212 
213  if (strcmp(code1->name, code2->name) == 0)
214  return item;
215  return NULL;
216 }
217 
218 
219 void* s_malloc(size_t size)
220 {
221  void* ptr;
222 
223  ptr = malloc(size);
224  if (ptr == NULL) {
225  logprintf(LIRC_ERROR, "out of memory");
226  parse_error = 1;
227  return NULL;
228  }
229  memset(ptr, 0, size);
230  return ptr;
231 }
232 
233 char* s_strdup(char* string)
234 {
235  char* ptr;
236 
237  ptr = strdup(string);
238  if (!ptr) {
239  logprintf(LIRC_ERROR, "out of memory");
240  parse_error = 1;
241  return NULL;
242  }
243  return ptr;
244 }
245 
246 ir_code s_strtocode(const char* val)
247 {
248  ir_code code = 0;
249  char* endptr;
250 
251  errno = 0;
252  code = strtoull(val, &endptr, 0);
253  if ((code == (__u64) -1 && errno == ERANGE) || strlen(endptr) != 0 || strlen(val) == 0) {
254  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
255  logprintf(LIRC_ERROR, "\"%s\": must be a valid (__u64) number", val);
256  parse_error = 1;
257  return 0;
258  }
259  return code;
260 }
261 
262 __u32 s_strtou32(char* val)
263 {
264  __u32 n;
265  char* endptr;
266 
267  n = strtoul(val, &endptr, 0);
268  if (!*val || *endptr) {
269  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
270  logprintf(LIRC_ERROR, "\"%s\": must be a valid (__u32) number", val);
271  parse_error = 1;
272  return 0;
273  }
274  return n;
275 }
276 
277 int s_strtoi(char* val)
278 {
279  char* endptr;
280  long n;
281  int h;
282 
283  n = strtol(val, &endptr, 0);
284  h = (int)n;
285  if (!*val || *endptr || n != ((long)h)) {
286  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
287  logprintf(LIRC_ERROR, "\"%s\": must be a valid (int) number", val);
288  parse_error = 1;
289  return 0;
290  }
291  return h;
292 }
293 
294 unsigned int s_strtoui(char* val)
295 {
296  char* endptr;
297  __u32 n;
298  unsigned int h;
299 
300  n = strtoul(val, &endptr, 0);
301  h = (unsigned int)n;
302  if (!*val || *endptr || n != ((__u32)h)) {
303  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
304  logprintf(LIRC_ERROR, "\"%s\": must be a valid (unsigned int) number", val);
305  parse_error = 1;
306  return 0;
307  }
308  return h;
309 }
310 
311 lirc_t s_strtolirc_t(char* val)
312 {
313  __u32 n;
314  lirc_t h;
315  char* endptr;
316 
317  n = strtoul(val, &endptr, 0);
318  h = (lirc_t)n;
319  if (!*val || *endptr || n != ((__u32)h)) {
320  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
321  logprintf(LIRC_ERROR, "\"%s\": must be a valid (lirc_t) number", val);
322  parse_error = 1;
323  return 0;
324  }
325  if (h < 0) {
326  logprintf(LIRC_WARNING, "error in configfile line %d:", line);
327  logprintf(LIRC_WARNING, "\"%s\" is out of range", val);
328  }
329  return h;
330 }
331 
332 int checkMode(int is_mode, int c_mode, char* error)
333 {
334  if (is_mode != c_mode) {
335  logprintf(LIRC_ERROR, "fatal error in configfile line %d:", line);
336  logprintf(LIRC_ERROR, "\"%s\" isn't valid at this position", error);
337  parse_error = 1;
338  return 0;
339  }
340  return 1;
341 }
342 
343 int addSignal(struct void_array* signals, char* val)
344 {
345  unsigned int t;
346 
347  t = s_strtoui(val);
348  if (parse_error)
349  return 0;
350  if (!add_void_array(signals, &t))
351  return 0;
352 
353  return 1;
354 }
355 
356 struct ir_ncode* defineCode(char* key, char* val, struct ir_ncode* code)
357 {
358  memset(code, 0, sizeof(*code));
359  code->name = s_strdup(key);
360  code->code = s_strtocode(val);
361  LOGPRINTF(3, " %-20s 0x%016llX", code->name, code->code);
362  return code;
363 }
364 
365 struct ir_code_node* defineNode(struct ir_ncode* code, const char* val)
366 {
367  struct ir_code_node* node;
368 
369  node = s_malloc(sizeof(*node));
370  if (node == NULL)
371  return NULL;
372 
373  node->code = s_strtocode(val);
374  node->next = NULL;
375 
376  LOGPRINTF(3, " 0x%016llX", node->code);
377 
378  if (code->current == NULL) {
379  code->next = node;
380  code->current = node;
381  } else {
382  code->current->next = node;
383  code->current = node;
384  }
385  return node;
386 }
387 
388 int parseFlags(char* val)
389 {
390  const struct flaglist* flaglptr;
391  int flags = 0;
392  char* flag;
393  char* help;
394 
395  flag = help = val;
396  while (flag != NULL) {
397  while (*help != '|' && *help != 0)
398  help++;
399  if (*help == '|') {
400  *help = 0;
401  help++;
402  } else {
403  help = NULL;
404  }
405 
406  flaglptr = all_flags;
407  while (flaglptr->name != NULL) {
408  if (strcasecmp(flaglptr->name, flag) == 0) {
409  if (flaglptr->flag & IR_PROTOCOL_MASK && flags & IR_PROTOCOL_MASK) {
410  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
411  logprintf(LIRC_ERROR, "multiple protocols given in flags: \"%s\"", flag);
412  parse_error = 1;
413  return 0;
414  }
415  flags = flags | flaglptr->flag;
416  LOGPRINTF(3, "flag %s recognized", flaglptr->name);
417  break;
418  }
419  flaglptr++;
420  }
421  if (flaglptr->name == NULL) {
422  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
423  logprintf(LIRC_ERROR, "unknown flag: \"%s\"", flag);
424  parse_error = 1;
425  return 0;
426  }
427  flag = help;
428  }
429  LOGPRINTF(2, "flags value: %d", flags);
430 
431  return flags;
432 }
433 
434 int defineRemote(char* key, char* val, char* val2, struct ir_remote* rem)
435 {
436  if ((strcasecmp("name", key)) == 0) {
437  if (rem->name != NULL)
438  free((void*)(rem->name));
439  rem->name = s_strdup(val);
440  logprintf(LIRC_INFO, "Using remote: %s.", val);
441  return 1;
442  }
443  if (options_getboolean("lircd:dynamic-codes")) {
444  if ((strcasecmp("dyncodes_name", key)) == 0) {
445  if (rem->dyncodes_name != NULL)
446  free(rem->dyncodes_name);
447  rem->dyncodes_name = s_strdup(val);
448  return 1;
449  }
450  } else if (strcasecmp("driver", key) == 0) {
451  if (rem->driver != NULL)
452  free((void*)(rem->driver));
453  rem->driver = s_strdup(val);
454  return 1;
455  } else if ((strcasecmp("bits", key)) == 0) {
456  rem->bits = s_strtoi(val);
457  return 1;
458  } else if (strcasecmp("flags", key) == 0) {
459  rem->flags |= parseFlags(val);
460  return 1;
461  } else if (strcasecmp("eps", key) == 0) {
462  rem->eps = s_strtoi(val);
463  return 1;
464  } else if (strcasecmp("aeps", key) == 0) {
465  rem->aeps = s_strtoi(val);
466  return 1;
467  } else if (strcasecmp("plead", key) == 0) {
468  rem->plead = s_strtolirc_t(val);
469  return 1;
470  } else if (strcasecmp("ptrail", key) == 0) {
471  rem->ptrail = s_strtolirc_t(val);
472  return 1;
473  } else if (strcasecmp("pre_data_bits", key) == 0) {
474  rem->pre_data_bits = s_strtoi(val);
475  return 1;
476  } else if (strcasecmp("pre_data", key) == 0) {
477  rem->pre_data = s_strtocode(val);
478  return 1;
479  } else if (strcasecmp("post_data_bits", key) == 0) {
480  rem->post_data_bits = s_strtoi(val);
481  return 1;
482  } else if (strcasecmp("post_data", key) == 0) {
483  rem->post_data = s_strtocode(val);
484  return 1;
485  } else if (strcasecmp("gap", key) == 0) {
486  if (val2 != NULL)
487  rem->gap2 = s_strtou32(val2);
488  rem->gap = s_strtou32(val);
489  return val2 != NULL ? 2 : 1;
490  } else if (strcasecmp("repeat_gap", key) == 0) {
491  rem->repeat_gap = s_strtou32(val);
492  return 1;
493  } else if (strcasecmp("repeat_mask", key) == 0) {
494  rem->repeat_mask = s_strtocode(val);
495  return 1;
496  }
497  /* obsolete: use toggle_bit_mask instead */
498  else if (strcasecmp("toggle_bit", key) == 0) {
499  rem->toggle_bit = s_strtoi(val);
500  return 1;
501  } else if (strcasecmp("toggle_bit_mask", key) == 0) {
502  rem->toggle_bit_mask = s_strtocode(val);
503  return 1;
504  } else if (strcasecmp("toggle_mask", key) == 0) {
505  rem->toggle_mask = s_strtocode(val);
506  return 1;
507  } else if (strcasecmp("rc6_mask", key) == 0) {
508  rem->rc6_mask = s_strtocode(val);
509  return 1;
510  } else if (strcasecmp("ignore_mask", key) == 0) {
511  rem->ignore_mask = s_strtocode(val);
512  return 1;
513  } else if (strcasecmp("manual_sort", key) == 0) {
514  rem->manual_sort = s_strtoi(val);
515  return 1;
516  }
517  /* obsolete name */
518  else if (strcasecmp("repeat_bit", key) == 0) {
519  rem->toggle_bit = s_strtoi(val);
520  return 1;
521  } else if (strcasecmp("suppress_repeat", key) == 0) {
522  rem->suppress_repeat = s_strtoi(val);
523  return 1;
524  } else if (strcasecmp("min_repeat", key) == 0) {
525  rem->min_repeat = s_strtoi(val);
526  return 1;
527  } else if (strcasecmp("min_code_repeat", key) == 0) {
528  rem->min_code_repeat = s_strtoi(val);
529  return 1;
530  } else if (strcasecmp("frequency", key) == 0) {
531  rem->freq = s_strtoui(val);
532  return 1;
533  } else if (strcasecmp("duty_cycle", key) == 0) {
534  rem->duty_cycle = s_strtoui(val);
535  return 1;
536  } else if (strcasecmp("baud", key) == 0) {
537  rem->baud = s_strtoui(val);
538  return 1;
539  } else if (strcasecmp("serial_mode", key) == 0) {
540  if (val[0] < '5' || val[0] > '9') {
541  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
542  logprintf(LIRC_ERROR, "bad bit count");
543  parse_error = 1;
544  return 0;
545  }
546  rem->bits_in_byte = val[0] - '0';
547  switch (toupper(val[1])) {
548  case 'N':
549  rem->parity = IR_PARITY_NONE;
550  break;
551  case 'E':
552  rem->parity = IR_PARITY_EVEN;
553  break;
554  case 'O':
555  rem->parity = IR_PARITY_ODD;
556  break;
557  default:
558  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
559  logprintf(LIRC_ERROR, "unsupported parity mode");
560  parse_error = 1;
561  return 0;
562  }
563  if (strcmp(val + 2, "1.5") == 0)
564  rem->stop_bits = 3;
565  else
566  rem->stop_bits = s_strtoui(val + 2) * 2;
567  return 1;
568  } else if (val2 != NULL) {
569  if (strcasecmp("header", key) == 0) {
570  rem->phead = s_strtolirc_t(val);
571  rem->shead = s_strtolirc_t(val2);
572  return 2;
573  } else if (strcasecmp("three", key) == 0) {
574  rem->pthree = s_strtolirc_t(val);
575  rem->sthree = s_strtolirc_t(val2);
576  return 2;
577  } else if (strcasecmp("two", key) == 0) {
578  rem->ptwo = s_strtolirc_t(val);
579  rem->stwo = s_strtolirc_t(val2);
580  return 2;
581  } else if (strcasecmp("one", key) == 0) {
582  rem->pone = s_strtolirc_t(val);
583  rem->sone = s_strtolirc_t(val2);
584  return 2;
585  } else if (strcasecmp("zero", key) == 0) {
586  rem->pzero = s_strtolirc_t(val);
587  rem->szero = s_strtolirc_t(val2);
588  return 2;
589  } else if (strcasecmp("foot", key) == 0) {
590  rem->pfoot = s_strtolirc_t(val);
591  rem->sfoot = s_strtolirc_t(val2);
592  return 2;
593  } else if (strcasecmp("repeat", key) == 0) {
594  rem->prepeat = s_strtolirc_t(val);
595  rem->srepeat = s_strtolirc_t(val2);
596  return 2;
597  } else if (strcasecmp("pre", key) == 0) {
598  rem->pre_p = s_strtolirc_t(val);
599  rem->pre_s = s_strtolirc_t(val2);
600  return 2;
601  } else if (strcasecmp("post", key) == 0) {
602  rem->post_p = s_strtolirc_t(val);
603  rem->post_s = s_strtolirc_t(val2);
604  return 2;
605  }
606  }
607  if (val2) {
608  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
609  logprintf(LIRC_ERROR, "unknown definiton: \"%s %s %s\"", key, val, val2);
610  } else {
611  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
612  logprintf(LIRC_ERROR, "unknown definiton or too few arguments: \"%s %s\"", key, val);
613  }
614  parse_error = 1;
615  return 0;
616 }
617 
618 static int sanityChecks(struct ir_remote* rem, const char* path)
619 {
620  struct ir_ncode* codes;
621  struct ir_code_node* node;
622 
623  path = path != NULL ? path : "unknown file";
624 
625  if (!rem->name) {
626  logprintf(LIRC_ERROR,
627  "%s: %s: Missing remote name", path, rem);
628  return 0;
629  }
630  if (rem->gap == 0) {
631  logprintf(LIRC_WARNING, "%s: %s: Gap value missing or invalid",
632  path, rem->name);
633  }
634  if (has_repeat_gap(rem) && is_const(rem)) {
635  logprintf(LIRC_WARNING,
636  "%s: %s: Repeat_gap ignored (CONST_LENGTH is set)",
637  path, rem->name);
638  }
639 
640  if (is_raw(rem))
641  return 1;
642 
643  if ((rem->pre_data & gen_mask(rem->pre_data_bits)) != rem->pre_data) {
644  logprintf(LIRC_WARNING,
645  "%s: %s: Invalid pre_data", path, rem->name);
646  rem->pre_data &= gen_mask(rem->pre_data_bits);
647  }
648  if ((rem->post_data & gen_mask(rem->post_data_bits)) != rem->post_data) {
649  logprintf(LIRC_WARNING, "%s: %s: Invalid post_data",
650  path, rem->name);
651  rem->post_data &= gen_mask(rem->post_data_bits);
652  }
653  for (codes = rem->codes; codes->name != NULL; codes++) {
654  if ((codes->code & gen_mask(rem->bits)) != codes->code) {
655  logprintf(LIRC_WARNING, "%s: %s: Invalid code : %s",
656  path, rem->name, codes->name);
657  codes->code &= gen_mask(rem->bits);
658  }
659  for (node = codes->next; node != NULL; node = node->next) {
660  if ((node->code & gen_mask(rem->bits)) != node->code) {
661  logprintf(LIRC_WARNING, "%s: %s: Invalid code %s: %s",
662  path, rem->name, codes->name);
663  node->code &= gen_mask(rem->bits);
664  }
665  }
666  }
667  return 1;
668 }
669 
676 static int remote_bits_cmp(struct ir_remote* r1, struct ir_remote* r2)
677 {
678  int r1_size;
679  int r2_size;
680  struct ir_ncode* c;
681 
682  int r1_is_raw = is_raw(r1);
683  int r2_is_raw = is_raw(r2);
684 
685  if (!r1_is_raw && r2_is_raw)
686  return -1;
687  if (r1_is_raw && !r2_is_raw)
688  return 1;
689 
690  if (r1_is_raw && r2_is_raw) {
691  for (c = r1->codes, r1_size = 0; c->name != NULL; c++)
692  r1_size += 1;
693  for (c = r2->codes, r2_size = 0; c->name != NULL; c++)
694  r2_size += 1;
695  } else {
696  r1_size = bit_count(r1);
697  r2_size = bit_count(r2);
698  }
699  if (r1_size == r2_size)
700  return 0;
701  return r1_size < r2_size ? -1 : 1;
702 }
703 
704 
709 static struct ir_remote* sort_by_bit_count(struct ir_remote* remotes)
710 {
711  struct ir_remote* top;
712  struct ir_remote* rem;
713  struct ir_remote* next;
714  struct ir_remote* prev;
715  struct ir_remote* scan;
716  struct ir_remote* r;
717 
718  for (r = remotes; r != NULL && r != (void*)-1; r = r->next)
719  if (r->manual_sort)
720  return remotes;
721  rem = remotes;
722  top = NULL;
723  while (rem != NULL && rem != (void*)-1) {
724  next = rem->next;
725 
726  scan = top;
727  prev = NULL;
728  while (scan && remote_bits_cmp(scan, rem) <= 0) {
729  prev = scan;
730  scan = scan->next;
731  }
732  if (prev)
733  prev->next = rem;
734  else
735  top = rem;
736  if (scan)
737  rem->next = scan;
738  else
739  rem->next = NULL;
740 
741  rem = next;
742  }
743 
744  return top;
745 }
746 
747 static const char* lirc_parse_include(char* s)
748 {
749  char* last;
750  size_t len;
751 
752  len = strlen(s);
753  if (len < 2)
754  return NULL;
755  last = s + len - 1;
756  while (last > s && strchr(whitespace, *last) != NULL)
757  last--;
758  if (last <= s)
759  return NULL;
760  if (*s != '"' && *s != '<')
761  return NULL;
762  if (*s == '"' && *last != '"')
763  return NULL;
764  else if (*s == '<' && *last != '>')
765  return NULL;
766  *last = 0;
767  memmove(s, s + 1, len - 2 + 1); /* terminating 0 is copied, and
768  * maybe more, but we don't care */
769  return s;
770 }
771 
772 
774 static const char* lirc_parse_relative(char* dst,
775  size_t dst_size,
776  const char* child,
777  const char* current)
778 {
779  char* dir;
780  size_t dirlen;
781 
782  if (!current)
783  return child;
784 
785  /* Not a relative path */
786  if (*child == '/')
787  return child;
788 
789  if (strlen(current) >= dst_size)
790  return NULL;
791  strcpy(dst, current);
792  dir = dirname(dst);
793  dirlen = strlen(dir);
794  if (dir != dst)
795  memmove(dst, dir, dirlen + 1);
796 
797  if (dirlen + 1 + strlen(child) + 1 > dst_size)
798  return NULL;
799  strcat(dst, "/");
800  strcat(dst, child);
801 
802  return dst;
803 }
804 
805 
807 static struct ir_remote*
808 ir_remotes_append(struct ir_remote* root, struct ir_remote* what)
809 {
810  struct ir_remote* r;
811 
812  if (root == (struct ir_remote*)-1)
813  root = NULL;
814  if (what == (struct ir_remote*)-1)
815  what = NULL;
816  if (root == NULL && what != NULL)
817  return what;
818  if (what == NULL)
819  return root;
820  for (r = root; r->next != NULL; r = r->next)
821  ;
822  r->next = what;
823  what->next = NULL;
824  return root;
825 }
826 
827 
828 struct ir_remote* read_config(FILE* f, const char* name)
829 {
830  struct ir_remote* head;
831 
832  head = read_config_recursive(f, name, 0);
833  head = sort_by_bit_count(head);
834  return head;
835 }
836 
837 
848 static struct ir_remote*
849 read_included(const char* name, int depth, char* val, struct ir_remote* top_rem)
850 {
851  FILE* childFile;
852  const char* childName;
853  struct ir_remote* rem = NULL;
854 
855  if (depth > MAX_INCLUDES) {
856  logprintf(LIRC_ERROR, "error opening child file defined at %s:%d", name, line);
857  logprintf(LIRC_ERROR, "too many files included");
858  return top_rem;
859  }
860  childName = lirc_parse_include(val);
861  if (!childName) {
862  logprintf(LIRC_ERROR, "error parsing child file value defined at line %d:", line);
863  logprintf(LIRC_ERROR, "invalid quoting");
864  return top_rem;
865  }
866  childFile = fopen(childName, "r");
867  if (childFile == NULL) {
868  logprintf(LIRC_ERROR, "error opening child file '%s' defined at line %d:",
869  childName, line);
870  logprintf(LIRC_ERROR, "ignoring this child file for now.");
871  return NULL;
872  }
873  rem = read_config_recursive(childFile, childName, depth + 1);
874  top_rem = ir_remotes_append(top_rem, rem);
875  fclose(childFile);
876  return top_rem;
877 }
878 
879 
890 static struct ir_remote* read_all_included(const char* name,
891  int depth,
892  char* val,
893  struct ir_remote* top_rem)
894 {
895  int i;
896  glob_t globbuf;
897  char buff[256] = { '\0' };
898 
899  memset(&globbuf, 0, sizeof(globbuf));
900  val = val + 1; // Strip quotes
901  val[strlen(val) - 1] = '\0';
902  lirc_parse_relative(buff, sizeof(buff), val, name);
903  glob(buff, 0, NULL, &globbuf);
904  for (i = 0; i < globbuf.gl_pathc; i += 1) {
905  snprintf(buff, sizeof(buff), "\"%s\"", globbuf.gl_pathv[i]);
906  top_rem = read_included(name, depth, buff, top_rem);
907  }
908  globfree(&globbuf);
909  return top_rem;
910 }
911 
912 
913 static void check_ncode_dups(const char* path,
914  const char* name,
915  struct void_array* ar,
916  struct ir_ncode* code)
917 {
918  if (foreach_void_array(ar, array_guest_ncode_cmp, code) != NULL) {
919  logprintf(LIRC_WARNING,
920  "%s: %s: Duplicate codes: %s",
921  path, name, code->name);
922  }
923  if (foreach_void_array(ar, array_guest_code_equals, code) != NULL) {
924  logprintf(LIRC_WARNING,
925  "%s: %s: Duplicate values: %s",
926  path, name, code->name);
927  }
928 }
929 
930 
931 static struct ir_remote*
932 read_config_recursive(FILE* f, const char* name, int depth)
933 {
934  char buf[LINE_LEN + 1];
935  char* key;
936  char* val;
937  char* val2;
938  int len, argc;
939  struct ir_remote* top_rem = NULL;
940  struct ir_remote* rem = NULL;
941  struct void_array codes_list, raw_codes, signals;
942  struct ir_ncode raw_code = { NULL, 0, 0, NULL };
943  struct ir_ncode name_code = { NULL, 0, 0, NULL };
944  struct ir_ncode* code;
945  int mode = ID_none;
946 
947  line = 0;
948  parse_error = 0;
949  LOGPRINTF(2, "parsing '%s'", name);
950 
951  while (fgets(buf, LINE_LEN, f) != NULL) {
952  line++;
953  len = strlen(buf);
954  if (len == LINE_LEN && buf[len - 1] != '\n') {
955  logprintf(LIRC_ERROR, "line %d too long in config file", line);
956  parse_error = 1;
957  break;
958  }
959 
960  if (len > 0) {
961  len--;
962  if (buf[len] == '\n')
963  buf[len] = 0;
964  }
965  if (len > 0) {
966  len--;
967  if (buf[len] == '\r')
968  buf[len] = 0;
969  }
970  /* ignore comments */
971  if (buf[0] == '#')
972  continue;
973  key = strtok(buf, whitespace);
974  /* ignore empty lines */
975  if (key == NULL)
976  continue;
977  val = strtok(NULL, whitespace);
978  if (val != NULL) {
979  val2 = strtok(NULL, whitespace);
980  LOGPRINTF(3, "Tokens: \"%s\" \"%s\" \"%s\"", key, val, (val2 == NULL ? "(null)" : val));
981  if (strcasecmp("include", key) == 0) {
982  int save_line = line;
983 
984  top_rem = read_all_included(name,
985  depth,
986  val,
987  top_rem);
988  line = save_line;
989  } else if (strcasecmp("begin", key) == 0) {
990  if (strcasecmp("codes", val) == 0) {
991  /* init codes mode */
992  LOGPRINTF(2, " begin codes");
993  if (!checkMode(mode, ID_remote, "begin codes"))
994  break;
995  if (rem->codes) {
996  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
997  logprintf(LIRC_ERROR, "codes are already defined");
998  parse_error = 1;
999  break;
1000  }
1001 
1002  init_void_array(&codes_list, 30, sizeof(struct ir_ncode));
1003  mode = ID_codes;
1004  } else if (strcasecmp("raw_codes", val) == 0) {
1005  /* init raw_codes mode */
1006  LOGPRINTF(2, " begin raw_codes");
1007  if (!checkMode(mode, ID_remote, "begin raw_codes"))
1008  break;
1009  if (rem->codes) {
1010  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
1011  logprintf(LIRC_ERROR, "codes are already defined");
1012  parse_error = 1;
1013  break;
1014  }
1015  set_protocol(rem, RAW_CODES);
1016  raw_code.code = 0;
1017  init_void_array(&raw_codes, 30, sizeof(struct ir_ncode));
1018  mode = ID_raw_codes;
1019  } else if (strcasecmp("remote", val) == 0) {
1020  /* create new remote */
1021  LOGPRINTF(1, "parsing remote");
1022  if (!checkMode(mode, ID_none, "begin remote"))
1023  break;
1024  mode = ID_remote;
1025  if (!top_rem) {
1026  /* create first remote */
1027  LOGPRINTF(2, "creating first remote");
1028  rem = top_rem = s_malloc(sizeof(struct ir_remote));
1029  } else {
1030  /* create new remote */
1031  LOGPRINTF(2, "creating next remote");
1032  rem = s_malloc(sizeof(struct ir_remote));
1033  ir_remotes_append(top_rem, rem);
1034  }
1035  } else if (mode == ID_codes) {
1036  code = defineCode(key, val, &name_code);
1037  while (!parse_error && val2 != NULL) {
1038  if (val2[0] == '#')
1039  break; /* comment */
1040  defineNode(code, val2);
1041  val2 = strtok(NULL, whitespace);
1042  }
1043  code->current = NULL;
1044  check_ncode_dups(name, rem->name, &codes_list, code);
1045  add_void_array(&codes_list, code);
1046  } else {
1047  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
1048  logprintf(LIRC_ERROR, "unknown section \"%s\"", val);
1049  parse_error = 1;
1050  }
1051  if (!parse_error && val2 != NULL) {
1052  logprintf(LIRC_WARNING,
1053  "%s: garbage after '%s' token "
1054  "in line %d ignored",
1055  rem->name, val, line);
1056  }
1057  } else if (strcasecmp("end", key) == 0) {
1058  if (strcasecmp("codes", val) == 0) {
1059  /* end Codes mode */
1060  LOGPRINTF(2, " end codes");
1061  if (!checkMode(mode, ID_codes, "end codes"))
1062  break;
1063  rem->codes = get_void_array(&codes_list);
1064  mode = ID_remote; /* switch back */
1065  } else if (strcasecmp("raw_codes", val) == 0) {
1066  /* end raw codes mode */
1067  LOGPRINTF(2, " end raw_codes");
1068 
1069  if (mode == ID_raw_name) {
1070  raw_code.signals = get_void_array(&signals);
1071  raw_code.length = signals.nr_items;
1072  if (raw_code.length % 2 == 0) {
1073  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
1074  logprintf(LIRC_ERROR, "bad signal length");
1075  parse_error = 1;
1076  }
1077  if (!add_void_array(&raw_codes, &raw_code))
1078  break;
1079  mode = ID_raw_codes;
1080  }
1081  if (!checkMode(mode, ID_raw_codes, "end raw_codes"))
1082  break;
1083  rem->codes = get_void_array(&raw_codes);
1084  mode = ID_remote; /* switch back */
1085  } else if (strcasecmp("remote", val) == 0) {
1086  /* end remote mode */
1087  LOGPRINTF(2, "end remote");
1088  /* print_remote(rem); */
1089  if (!checkMode(mode, ID_remote, "end remote"))
1090  break;
1091  if (!sanityChecks(rem, name)) {
1092  parse_error = 1;
1093  break;
1094  }
1095  if (options_getboolean("lircd:dynamic-codes")) {
1096  if (rem->dyncodes_name == NULL)
1097  rem->dyncodes_name = s_strdup("unknown");
1098  rem->dyncodes[0].name = rem->dyncodes_name;
1099  rem->dyncodes[1].name = rem->dyncodes_name;
1100  }
1101  /* not really necessary because we
1102  * clear the alloced memory */
1103  rem->next = NULL;
1104  rem->last_code = NULL;
1105  mode = ID_none; /* switch back */
1106  } else if (mode == ID_codes) {
1107  code = defineCode(key, val, &name_code);
1108  while (!parse_error && val2 != NULL) {
1109  if (val2[0] == '#')
1110  break; /* comment */
1111  defineNode(code, val2);
1112  val2 = strtok(NULL, whitespace);
1113  }
1114  code->current = NULL;
1115  add_void_array(&codes_list, code);
1116  } else {
1117  logprintf(LIRC_ERROR, "error in configfile line %d:", line);
1118  logprintf(LIRC_ERROR, "unknown section %s", val);
1119  parse_error = 1;
1120  }
1121  if (!parse_error && val2 != NULL) {
1122  logprintf(LIRC_WARNING,
1123  "%s: garbage after '%s'"
1124  " token in line %d ignored",
1125  rem->name, val, line);
1126  }
1127  } else {
1128  switch (mode) {
1129  case ID_remote:
1130  argc = defineRemote(key, val, val2, rem);
1131  if (!parse_error
1132  && ((argc == 1 && val2 != NULL)
1133  || (argc == 2 && val2 != NULL && strtok(NULL, whitespace) != NULL))) {
1134  logprintf(LIRC_WARNING,
1135  "%s: garbage after '%s'"
1136  " token in line %d ignored",
1137  rem->name, key, line);
1138  }
1139  break;
1140  case ID_codes:
1141  code = defineCode(key, val, &name_code);
1142  while (!parse_error && val2 != NULL) {
1143  if (val2[0] == '#')
1144  break; /* comment */
1145  defineNode(code, val2);
1146  val2 = strtok(NULL, whitespace);
1147  }
1148  code->current = NULL;
1149  check_ncode_dups(name,
1150  rem->name,
1151  &codes_list,
1152  code);
1153  add_void_array(&codes_list, code);
1154  break;
1155  case ID_raw_codes:
1156  case ID_raw_name:
1157  if (strcasecmp("name", key) == 0) {
1158  LOGPRINTF(3, "Button: \"%s\"", val);
1159  if (mode == ID_raw_name) {
1160  raw_code.signals = get_void_array(&signals);
1161  raw_code.length = signals.nr_items;
1162  if (raw_code.length % 2 == 0) {
1163  logprintf(LIRC_ERROR, "error in configfile line %d:",
1164  line);
1165  logprintf(LIRC_ERROR, "bad signal length");
1166  parse_error = 1;
1167  }
1168  if (!add_void_array(&raw_codes, &raw_code))
1169  break;
1170  }
1171  raw_code.name = s_strdup(val);
1172  if (!raw_code.name)
1173  break;
1174  raw_code.code++;
1175  init_void_array(&signals, 50, sizeof(lirc_t));
1176  mode = ID_raw_name;
1177  if (!parse_error && val2 != NULL) {
1178  logprintf(LIRC_WARNING,
1179  "%s: garbage after '%s'"
1180  " token in line %d ignored",
1181  rem->name, key, line);
1182  }
1183  } else {
1184  if (mode == ID_raw_codes) {
1185  logprintf(LIRC_ERROR, "no name for signal defined at line %d",
1186  line);
1187  parse_error = 1;
1188  break;
1189  }
1190  if (!addSignal(&signals, key))
1191  break;
1192  if (!addSignal(&signals, val))
1193  break;
1194  if (val2)
1195  if (!addSignal(&signals, val2))
1196  break;
1197  while ((val = strtok(NULL, whitespace)))
1198  if (!addSignal(&signals, val))
1199  break;
1200  }
1201  break;
1202  }
1203  }
1204  } else if (mode == ID_raw_name) {
1205  if (!addSignal(&signals, key))
1206  break;
1207  } else {
1208  logprintf(LIRC_ERROR, "error in configfile line %d", line);
1209  parse_error = 1;
1210  break;
1211  }
1212  if (parse_error)
1213  break;
1214  }
1215  if (mode != ID_none) {
1216  switch (mode) {
1217  case ID_raw_name:
1218  if (raw_code.name != NULL) {
1219  free(raw_code.name);
1220  if (get_void_array(&signals) != NULL)
1221  free(get_void_array(&signals));
1222  }
1223  case ID_raw_codes:
1224  rem->codes = get_void_array(&raw_codes);
1225  break;
1226  case ID_codes:
1227  rem->codes = get_void_array(&codes_list);
1228  break;
1229  }
1230  if (!parse_error) {
1231  logprintf(LIRC_ERROR, "unexpected end of file");
1232  parse_error = 1;
1233  }
1234  }
1235  if (parse_error) {
1236  static int print_error = 1;
1237 
1238  if (print_error) {
1239  logprintf(LIRC_ERROR, "reading of file '%s' failed", name);
1240  print_error = 0;
1241  }
1242  free_config(top_rem);
1243  if (depth == 0)
1244  print_error = 1;
1245  return (void*)-1;
1246  }
1247  /* kick reverse flag */
1248  /* handle RC6 flag to be backwards compatible: previous RC-6
1249  * config files did not set rc6_mask */
1250  rem = top_rem;
1251  while (rem != NULL) {
1252  if ((!is_raw(rem)) && rem->flags & REVERSE) {
1253  struct ir_ncode* codes;
1254 
1255  if (has_pre(rem))
1256  rem->pre_data = reverse(rem->pre_data, rem->pre_data_bits);
1257  if (has_post(rem))
1258  rem->post_data = reverse(rem->post_data, rem->post_data_bits);
1259  codes = rem->codes;
1260  while (codes->name != NULL) {
1261  codes->code = reverse(codes->code, rem->bits);
1262  codes++;
1263  }
1264  rem->flags = rem->flags & (~REVERSE);
1265  rem->flags = rem->flags | COMPAT_REVERSE;
1266  /* don't delete the flag because we still need
1267  * it to remain compatible with older versions
1268  */
1269  }
1270  if (rem->flags & RC6 && rem->rc6_mask == 0 && rem->toggle_bit > 0) {
1271  int all_bits = bit_count(rem);
1272 
1273  rem->rc6_mask = ((ir_code)1) << (all_bits - rem->toggle_bit);
1274  }
1275  if (rem->toggle_bit > 0) {
1276  int all_bits = bit_count(rem);
1277 
1278  if (has_toggle_bit_mask(rem))
1279  logprintf(LIRC_WARNING, "%s uses both toggle_bit and toggle_bit_mask", rem->name);
1280  else
1281  rem->toggle_bit_mask = ((ir_code)1) << (all_bits - rem->toggle_bit);
1282  rem->toggle_bit = 0;
1283  }
1284  if (has_toggle_bit_mask(rem)) {
1285  if (!is_raw(rem) && rem->codes) {
1286  rem->toggle_bit_mask_state = (rem->codes->code & rem->toggle_bit_mask);
1287  if (rem->toggle_bit_mask_state)
1288  /* start with state set to 0 for backwards compatibility */
1289  rem->toggle_bit_mask_state ^= rem->toggle_bit_mask;
1290  }
1291  }
1292  if (is_serial(rem)) {
1293  lirc_t base;
1294 
1295  if (rem->baud > 0) {
1296  base = 1000000 / rem->baud;
1297  if (rem->pzero == 0 && rem->szero == 0)
1298  rem->pzero = base;
1299  if (rem->pone == 0 && rem->sone == 0)
1300  rem->sone = base;
1301  }
1302  if (rem->bits_in_byte == 0)
1303  rem->bits_in_byte = 8;
1304  }
1305  if (rem->min_code_repeat > 0) {
1306  if (!has_repeat(rem) || rem->min_code_repeat > rem->min_repeat) {
1307  logprintf(LIRC_WARNING, "invalid min_code_repeat value");
1308  rem->min_code_repeat = 0;
1309  }
1310  }
1311  calculate_signal_lengths(rem);
1312  rem = rem->next;
1313  }
1314 
1315  return top_rem;
1316 }
1317 
1318 void calculate_signal_lengths(struct ir_remote* remote)
1319 {
1320  if (is_const(remote)) {
1321  remote->min_total_signal_length = min_gap(remote);
1322  remote->max_total_signal_length = max_gap(remote);
1323  } else {
1324  remote->min_gap_length = min_gap(remote);
1325  remote->max_gap_length = max_gap(remote);
1326  }
1327 
1328  lirc_t min_signal_length = 0, max_signal_length = 0;
1329  lirc_t max_pulse = 0, max_space = 0;
1330  int first_sum = 1;
1331  struct ir_ncode* c = remote->codes;
1332  int i;
1333 
1334  while (c->name) {
1335  struct ir_ncode code = *c;
1336  struct ir_code_node* next = code.next;
1337  int first = 1;
1338  int repeat = 0;
1339 
1340  do {
1341  if (first) {
1342  first = 0;
1343  } else {
1344  code.code = next->code;
1345  next = next->next;
1346  }
1347  for (repeat = 0; repeat < 2; repeat++) {
1348  if (init_sim(remote, &code, repeat)) {
1349  lirc_t sum = send_buffer_sum();
1350 
1351  if (sum) {
1352  if (first_sum || sum < min_signal_length)
1353  min_signal_length = sum;
1354  if (first_sum || sum > max_signal_length)
1355  max_signal_length = sum;
1356  first_sum = 0;
1357  }
1358  for (i = 0; i < send_buffer_length(); i++) {
1359  if (i & 1) { /* space */
1360  if (send_buffer_data()[i] > max_space)
1361  max_space = send_buffer_data()[i];
1362  } else { /* pulse */
1363  if (send_buffer_data()[i] > max_pulse)
1364  max_pulse = send_buffer_data()[i];
1365  }
1366  }
1367  }
1368  }
1369  } while (next);
1370  c++;
1371  }
1372  if (first_sum) {
1373  /* no timing data, so assume gap is the actual total
1374  * length */
1375  remote->min_total_signal_length = min_gap(remote);
1376  remote->max_total_signal_length = max_gap(remote);
1377  remote->min_gap_length = min_gap(remote);
1378  remote->max_gap_length = max_gap(remote);
1379  } else if (is_const(remote)) {
1380  if (remote->min_total_signal_length > max_signal_length) {
1381  remote->min_gap_length = remote->min_total_signal_length - max_signal_length;
1382  } else {
1383  logprintf(LIRC_WARNING,
1384  "min_gap_length is 0 for '%s' remote",
1385  remote->name);
1386  remote->min_gap_length = 0;
1387  }
1388  if (remote->max_total_signal_length > min_signal_length) {
1389  remote->max_gap_length = remote->max_total_signal_length - min_signal_length;
1390  } else {
1391  logprintf(LIRC_WARNING, "max_gap_length is 0 for '%s' remote", remote->name);
1392  remote->max_gap_length = 0;
1393  }
1394  } else {
1395  remote->min_total_signal_length = min_signal_length + remote->min_gap_length;
1396  remote->max_total_signal_length = max_signal_length + remote->max_gap_length;
1397  }
1398  LOGPRINTF(1, "lengths: %lu %lu %lu %lu", remote->min_total_signal_length, remote->max_total_signal_length,
1399  remote->min_gap_length, remote->max_gap_length);
1400 }
1401 
1402 void free_config(struct ir_remote* remotes)
1403 {
1404  struct ir_remote* next;
1405  struct ir_ncode* codes;
1406 
1407  while (remotes != NULL) {
1408  next = remotes->next;
1409 
1410  if (remotes->dyncodes_name != NULL)
1411  free(remotes->dyncodes_name);
1412  if (remotes->name != NULL)
1413  free((void*)(remotes->name));
1414  if (remotes->codes != NULL) {
1415  codes = remotes->codes;
1416  while (codes->name != NULL) {
1417  struct ir_code_node* node;
1418  struct ir_code_node* next_node;
1419 
1420  free(codes->name);
1421  if (codes->signals != NULL)
1422  free(codes->signals);
1423  node = codes->next;
1424  while (node) {
1425  next_node = node->next;
1426  free(node);
1427  node = next_node;
1428  }
1429  codes++;
1430  }
1431  free(remotes->codes);
1432  }
1433  free(remotes);
1434  remotes = next;
1435  }
1436 }
const lirc_t * send_buffer_data(void)
Definition: transmit.c:372
lirc_t min_total_signal_length
#define NO_FOOT_REP
#define RC6
unsigned int freq
lirc_t max_gap_length
#define GOLDSTAR
lirc_t max_total_signal_length
ir_code post_data
ir_code repeat_mask
struct ir_code_node * next
unsigned int baud
const char * name
#define SPACE_ENC
void free_config(struct ir_remote *remotes)
Definition: config_file.c:1402
lirc_t * signals
#define COMPAT_REVERSE
struct ir_ncode * last_code
unsigned int parity
__u64 ir_code
lirc_t min_gap_length
char * name
struct ir_code_node * current
unsigned int duty_cycle
#define RCMM
ir_code toggle_mask
ir_code pre_data
lirc_t send_buffer_sum(void)
Definition: transmit.c:377
#define RC5
char * dyncodes_name
#define REPEAT_HEADER
#define SPACE_FIRST
__u32 repeat_gap
#define CONST_LENGTH
#define NO_HEAD_REP
unsigned int stop_bits
#define GRUNDIG
void * get_void_array(struct void_array *ar)
Definition: config_file.c:141
#define LOGPRINTF(level, fmt, args...)
Definition: lirc_log.h:75
void *(* array_guest_func)(void *item, void *arg)
Definition: config_file.c:63
unsigned int aeps
lirc_t srepeat
#define SERIAL
#define SHIFT_ENC
#define BO
ir_code code
const char * driver
unsigned int min_code_repeat
const struct flaglist all_flags[]
Definition: config_file.c:91
struct ir_ncode dyncodes[2]
char * name
Definition: config_flags.h:14
ir_code rc6_mask
int send_buffer_length(void)
Definition: transmit.c:366
ir_code toggle_bit_mask
#define RAW_CODES
struct ir_remote * read_config(FILE *f, const char *name)
Definition: config_file.c:828
ir_code ignore_mask
#define XMP
unsigned int bits_in_byte
int add_void_array(struct void_array *ar, void *dataptr)
Definition: config_file.c:116