EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Keyword.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file Keyword.cxx
1 /* -------------------------------------------------------------------------- */
2 /* Keyword.cc */
3 /* */
4 /* A simple command line parser. */
5 /* */
6 /* A.Kisselev, PNPI, St.Petersburg, Russia. */
7 /* e-mail: kisselev@hermes.desy.de */
8 /* -------------------------------------------------------------------------- */
9 
10 #include <cstdio>
11 #include <cstring>
12 #include <cstdlib>
13 #include <cassert>
14 
15 #include <Keyword.h>
16 
18  // Key offset in argv[] array;
19  int start;
20 
21  // Actual number of arguments for this keyword;
22  int arg_num;
23 
24  // Pointer to the keyword frame (if exists);
26 } ;
27 
28 /* ========================================================================== */
29 
30 Keyword::Keyword(char *_name, int _arg_num_min, int _arg_num_max, keywordfun _fun,
31  MultipleInvocationMode _invocation_mode)
32 {
33  memset(this, 0x00, sizeof(Keyword));
34 
35  // Allocate keyword name and parameters;
36  name = strdup(_name);
37  //if (!name) return NULL;
38  assert(name);
39 
40  arg_num_min = _arg_num_min;
41  arg_num_max = _arg_num_max;
42  fun = _fun;
43 
44  __multiple_invocation_mode = _invocation_mode;
45 } /* Keyword::Keyword */
46 
47 /* ========================================================================== */
48 
49 static int isKeyword(char *argument)
50 {
51  int len = strlen(_KEYWORD_PREFIX_);
52 
53  if (strlen(argument) < len) return 0;
54  if (memcmp(argument, _KEYWORD_PREFIX_, len)) return 0;
55 
56  // Success (this argument is a keyword);
57  return 1;
58 } /* isKeyword */
59 
60 /* -------------------------------------------------------------------------- */
61 /* After a number of cross-checks append this command line keyword to the */
62 /* existing list; */
63 
64 Keyword *declare_keyword(Keyword **root, char *_name, int _arg_num_min, int _arg_num_max,
65  keywordfun _fun, MultipleInvocationMode _invocation_mode)
66 {
67  // Sanity check;
68  if (!isKeyword(_name))
69  {
70  printf("'%s' does not look like a keyword!\n", _name);
71  return NULL;
72  } /*if*/
73 
74  // Loop through the existing keywords and check for double counting;
75  while (*root)
76  {
77  if (!strcmp(_name, (*root)->name))
78  {
79  printf("Keyword '%s' encountered twice\n", _name);
80  return NULL;
81  } /*if*/
82 
83  root = &(*root)->next;
84  } /*while*/
85 
86  Keyword *key = *root = new Keyword(_name, _arg_num_min, _arg_num_max, _fun,
87  _invocation_mode);
88 
89  return key;
90 } /* declare_keyword */
91 
92 /* ========================================================================== */
93 
94 #define FALLOUT(key, why, ret) \
95  {printf("\n [PARSER]: '%s' --> %s!\n\n", (key), (why)); return (ret); }
96 
97 /* -------------------------------------------------------------------------- */
98 /* Well, do not care too much about performance optimization (parsing is */
99 /* fast and done only once); */
100 
101 int Keyword::parseCommandLine(int argc, char **argv)
102 {
103  int key_num = 0;
104  // 'argc': certainly not more;
105  t_cmd_line_key keys[argc];
106 
107  // No arguments --> Ok;
108  if (argc == 1) return 0;
109 
110  // The very first command lie parameter must be a keyword;
111  if (!isKeyword(argv[1])) FALLOUT(argv[1], "first argument is not a keyword", -1);
112 
113  // Loop through all the command line arguments and find keywords;
114  for(int ik=1; ik<argc; ik++)
115  if (isKeyword(argv[ik]))
116  keys[key_num++].start = ik;
117 
118  // Prefer to check everything first and start execution in
119  // separate loop only after making sure that everything is Ok;
120  for(int ik=0; ik<key_num; ik++)
121  {
122  t_cmd_line_key *key = keys + ik;
123 
124  // Calculate number of arguments for this keyword;
125  key->arg_num = (ik == key_num - 1) ? argc - key->start - 1 :
126  (key+1)->start - key->start - 1;
127 
128  // Now loop through all known keywords and find a match;
129  for(Keyword *pattern=this; pattern; pattern=pattern->next)
130  if (!strcmp(argv[key->start], pattern->name))
131  {
132  // Means this key was already found in the command line;
133  if (pattern->activated &&
134  pattern->__multiple_invocation_mode == _MULTIPLE_INVOCATION_DISABLED_)
135  FALLOUT(pattern->name, "key used more than once", -2);
136 
137  if (pattern->arg_num_min != -1 && key->arg_num < pattern->arg_num_min)
138  FALLOUT(pattern->name, "wrong number of arguments", -3);
139  if (pattern->arg_num_max != -1 && key->arg_num > pattern->arg_num_max)
140  FALLOUT(pattern->name, "wrong number of arguments", -3);
141 
142  pattern->activated = 1;
143 
144  key->keyword = pattern;
145 
146  goto _next_key;
147  } /*for..if*/
148 
149  // No match;
150  FALLOUT(argv[key->start], "unknown key", -4);
151 
152 _next_key:;
153  } /*for*/
154 
155  // Ok, now may actually call parser functions;
156  for(int ik=0; ik<key_num; ik++)
157  {
158  t_cmd_line_key *key = keys + ik;
159 
160  int ret = key->keyword->fun(key->arg_num, argv + key->start + 1);
161 
162  if (ret) FALLOUT(key->keyword->name, "syntax error", ret);
163  } /*for*/
164 
165  return 0;
166 } /* Keyword::parseCommandLine */
167 
168 /* ========================================================================== */