1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #ifndef MI_CHAR_TYPE
26 # define MI_CHAR_TYPE 1
27 #endif
28
29 #include <common.h>
30 #include <gen/gen.h>
31 #include <base/paths.h>
32 #include <base/io.h>
33 #include <base/env.h>
34 #include <base/conf.h>
35 #include <base/getopt.h>
36
37 static const char HELP[] = "\
38 Usage: %s [OPTIONS] PATH CLASSNAME[=ALIAS] ...\n\
39 \n\
40 OVERVIEW:\n\
41 This program generates provider source code from MOF class definitions.\n\
42 PATH is a file that contains the MOF definitions (or includes them).\n\
43 mike 1.1 It must include any dependent MOF defintions as well (such as the CIM\n\
44 schema). The PATH is followed by a list of CLASSNAME arguments, which are\n\
45 the names of the MOF classes to be generated. Each CLASSNAME argument may\n\
46 be followed by an optional ALIAS argument (separated by an equal sign).\n\
47 The ALIAS provides an alternative name for the class to be used within\n\
48 the C source code. For example, 'CIM_ComputerSystem=CompSys' says to\n\
49 use 'CompSys' in C sources instead of 'CIM_ComputerSystem'.\n\
50 \n\
51 OPTIONS:\n\
52 -I PATH Search this directory for included MOF files.\n\
53 -D Generate 'Description' qualifiers.\n\
54 -V Generate 'Values' and 'ValueMap' qualifiers.\n\
55 -M Generate 'MappingStrings' qualifiers.\n\
56 -S Generate standard CIM qualifier declarations.\n\
57 -B Generate boolean qualifiers.\n\
58 -Q Suppress qualifier declarations generation.\n\
59 -q Quiet mode - do not print anything on stdout.\n\
60 -h, --help Print this help message.\n\
61 -v, --version Print the program version.\n\
62 -s SCHEMA Specify C name of the schema [schemaDecl].\n\
63 -n Suppress provider generation (only schema.c).\n\
64 mike 1.1 --cpp Generate cpp skeleton for the provider.\n\
65 -d PATH Place output files in this directory.\n\
66 -l Generate strings.rc file.\n\
67 -f Set filter support flag into MI_Main().\n\
68 -A Generate single association function.\n\
69 -e CLASS Generate extra class with this name.\n\
70 -y NAME Use NAME as entry point (default MI_Main).\n\
71 -W Print MOF warnings (suppressed by default).\n\
72 -C, --schemafile PATH Alternative path of main CIM schema file.\n\
73 -m PROVIDERNAME Generate provider makefile.\n\
74 --nogi CLASSNAME Set MI_ProviderFT.GetInstance to NULL for\n\
75 the given class. This forces the provider\n\
76 manager to use the EnumerateInstances method\n\
77 to satisfy all GetInstance requests on this\n\
78 class.\n\
79 \n\
80 EXAMPLES:\n\
81 The following example generates a 'MSFT_ComputerSystem' class, which is\n\
82 defined in schema.mof.\n\
83 \n\
84 $ omigen schema.mof MSFT_ComputerSystem=CompSys\n\
85 mike 1.1 Created CompSys.h\n\
86 Created CompSys.c\n\
87 Created schema.c\n\
88 Created module.c\n\
89 \n\
90 CompSys.h defines the 'CompSys' structure. schema.c defines run-time type\n\
91 information for the CompSys structure. CompSys.c contains the provider\n\
92 stubs and module.c contains the MI_Main() provider entry point.\n\
93 \n\
94 FILES:\n\
95 .omigenrc\n\
96 This file contains an option per line as it might appear on the \n\
97 command line (-OPTION [ARGUMENT]). These options are appended to the\n\
98 command line options, which take precedence. The program first\n\
99 attempts to open this file in the current directory followed by\n\
100 the home directory (given by the 'HOME' environment variable).\n\
101 The following is an example of the contents of this file.\n\
102 \n\
103 -I /opt/microsoft/sca/mof/cim222\n\
104 -I /opt/microsoft/sca/mof/extras\n\
105 \n\
106 mike 1.1 ";
107
108 using namespace std;
109
110 static const char* arg0;
111
112 //==============================================================================
113 //
114 // err()
115 //
116 // Writes a formatted error message to standard error (preceded by argv[0])
117 // and then exists.
118 //
119 //==============================================================================
120
121 PRINTF_FORMAT(1, 2)
122 static void FUNCTION_NEVER_RETURNS err(const char* fmt, ...)
123 {
124 fprintf(stderr, "%s: ", arg0);
125
126 va_list ap;
127 mike 1.1 va_start(ap, fmt);
128 vfprintf(stderr, fmt, ap);
129 va_end(ap);
130
131 fputc('\n', stderr);
132 exit(1);
133 }
134
135 static void _GetCommandLineDestDirOption(
136 int* argc_,
137 const char* argv[])
138 {
139 int argc = *argc_;
140 int i;
141 const char* destdir = NULL;
142
143 for (i = 1; i < argc; )
144 {
145 if (strcmp(argv[i], "--destdir") == 0)
146 {
147 if (i + 1 == argc)
148 mike 1.1 err("missing argument for --destdir option");
149
150 destdir = argv[i+1];
151 memmove((char*)&argv[i], (char*)&argv[i+2],
152 sizeof(char*) * (argc-i-1));
153 argc -= 2;
154 }
155 else if (strncmp(argv[i], "--destdir=", 10) == 0)
156 {
157 destdir = argv[i] + 10;
158 memmove((char*)&argv[i], (char*)&argv[i+1],
159 sizeof(char*) * (argc-i));
160
161 argc -= 1;
162 }
163 else
164 i++;
165 }
166
167 if (destdir)
168 {
169 mike 1.1 if (SetPath(ID_DESTDIR, destdir) != 0)
170 err("failed to set destdir");
171 }
172
173 *argc_ = argc;
174 }
175
176 //==============================================================================
177 //
178 // _GetCommandLineOptions()
179 //
180 // This function processes command line options. Each option begins with
181 // the '-' character followed by a single alphabetic character. An option
182 // may be followed by an optional argument. GeneratorOptions and their
183 // optional arguments are removed from the argc-argv array upon return.
184 // Extracted options are stored in the options parameter (see the
185 // GeneratorOptions structure defined above).
186 //
187 //==============================================================================
188
189 static string schemafile;
190 mike 1.1
191 static void _GetCommandLineOptions(
192 int& argc,
193 const char**& argv,
194 GeneratorOptions& options)
195 {
196 GetOptState state = GETOPTSTATE_INITIALIZER;
197
198 const char* opts[] =
199 {
200 "-I:",
201 "-h",
202 "--help",
203 "-v",
204 "--version",
205 "-D",
206 "-V",
207 "-M",
208 "-S",
209 "-B",
210 "-Q",
211 mike 1.1 "-f",
212 "-q",
213 "-W",
214 "-a",
215 "-n",
216 "--cpp",
217 "-s:",
218 "-d:",
219 "-e:",
220 "-y:",
221 "-l",
222 "-reg:",
223 "-A",
224 "-C:",
225 "--schemafile:",
226 "-m:",
227 "--nogi:",
228 NULL,
229 };
230
231 /* For each argument */
232 mike 1.1 for (;;)
233 {
234 int r = GetOpt(&argc, (const char**)argv, opts, &state);
235
236 if (r == 1)
237 break;
238
239 if (r == -1)
240 err("%s", state.err);
241
242 /* Check for -I option */
243 if (strcmp(state.opt, "-I") == 0)
244 {
245 options.paths.push_back(state.arg);
246 }
247 else if (strcmp(state.opt, "-h") == 0 ||
248 strcmp(state.opt, "--help") == 0)
249 {
250 printf(HELP, arg0);
251 exit(1);
252 }
253 mike 1.1 else if (strcmp(state.opt, "-v") == 0 ||
254 strcmp(state.opt, "--version") == 0)
255 {
256 printf("%s: %s\n", arg0,
257 CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE);
258 exit(0);
259 }
260 else if (strcmp(state.opt, "-D") == 0)
261 {
262 options.descriptions = true;
263 }
264 else if (strcmp(state.opt, "-V") == 0)
265 {
266 options.values = true;
267 }
268 else if (strcmp(state.opt, "-M") == 0)
269 {
270 options.mappingStrings = true;
271 }
272 else if (strcmp(state.opt, "-S") == 0)
273 {
274 mike 1.1 options.standardQualifiers = true;
275 }
276 else if (strcmp(state.opt, "-B") == 0)
277 {
278 options.booleanQualifiers = true;
279 }
280 else if (strcmp(state.opt, "-Q") == 0)
281 {
282 options.ignoreAllQualifiers = true;
283 }
284 else if (strcmp(state.opt, "-f") == 0)
285 {
286 options.filterSupport = true;
287 }
288 else if (strcmp(state.opt, "-q") == 0)
289 {
290 options.quiet = true;
291 }
292 else if (strcmp(state.opt, "-W") == 0)
293 {
294 options.warnings = true;
295 mike 1.1 }
296 else if (strcmp(state.opt, "-a") == 0)
297 {
298 options.all = true;
299 }
300 else if (strcmp(state.opt, "-n") == 0)
301 {
302 options.noProviders = true;
303 }
304 else if (strcmp(state.opt, "--cpp") == 0)
305 {
306 options.cpp = true;
307 }
308 else if (strcmp(state.opt, "-s") == 0)
309 {
310 options.schema = state.arg;
311 }
312 else if (strcmp(state.opt, "-d") == 0)
313 {
314 options.dir = state.arg;
315 }
316 mike 1.1 else if (strcmp(state.opt, "-e") == 0)
317 {
318 options.extraClasses.push_back(state.arg);
319 }
320 else if (strcmp(state.opt, "-y") == 0)
321 {
322 options.entryPoint = state.arg;
323 }
324 else if (strcmp(state.opt, "-l") == 0)
325 {
326 options.localize = true;
327 }
328 else if (strcmp(state.opt, "-reg") == 0)
329 {
330 options.providerRegistryPath = state.arg;
331 }
332 else if (strcmp(state.opt, "-A") == 0)
333 {
334 options.association = true;
335 }
336 else if (strcmp(state.opt, "-C") == 0 ||
337 mike 1.1 strcmp(state.opt, "--schemafile") == 0)
338 {
339 schemafile = state.arg;
340
341 if (schemafile.size() && access(schemafile.c_str(), R_OK) != 0)
342 {
343 err("file given by %s option does not exist: %s",
344 state.opt, schemafile.c_str());
345 }
346 }
347 else if (strcmp(state.opt, "-m") == 0)
348 {
349 options.providerName = state.arg;
350 }
351 else if (strcmp(state.opt, "--nogi") == 0)
352 {
353 options.noGetInstance.push_back(state.arg);
354 }
355 }
356 }
357
358 mike 1.1 //==============================================================================
359 //
360 // FindConfigFile()
361 //
362 // Find the configuration file by checking in following order:
363 //
364 // ./.omigenrc
365 // home/.omigenrc
366 // sysconfdir/.omigenrc
367 //
368 //==============================================================================
369
370 static int FindConfigFile(char path[MAX_PATH_SIZE])
371 {
372 /* Look in current directory */
373 {
374 Strlcpy(path, "./.omigenrc", MAX_PATH_SIZE);
375
376 if (access(path, R_OK) == 0)
377 return 0;
378 }
379 mike 1.1
380 /* Look in HOME directory */
381 char* home = Dupenv("HOME");
382 if (home)
383 {
384 Strlcpy(path, home, MAX_PATH_SIZE);
385 Strlcat(path, "/.omigenrc", MAX_PATH_SIZE);
386
387 if (access(path, R_OK) == 0)
388 {
389 free(home);
390 return 0;
391 }
392 free(home);
393 }
394
395 /* Look in system config directory */
396 {
397 Strlcpy(path, GetPath(ID_DESTDIR), MAX_PATH_SIZE);
|
399 mike 1.1 Strlcat(path, GetPath(ID_SYSCONFDIR), MAX_PATH_SIZE);
400 Strlcat(path, "/omigen.conf", MAX_PATH_SIZE);
401
402 if (access(path, R_OK) == 0)
403 return 0;
404 }
405
406 /* Not found */
407 return -1;
408 }
409
410 //==============================================================================
411 //
412 // _GetConfigFileOptions()
413 //
414 // Read options from the omigen configuration file.
415 //
416 //==============================================================================
417
418 static void _GetConfigFileOptions(GeneratorOptions& opts)
419 {
420 mike 1.1 char path[MAX_PATH_SIZE];
421 Conf* conf;
422
423 MI_UNUSED(opts);
424
425 /* Form the configuration file path */
426 if (FindConfigFile(path) != 0)
427 err("failed to find configuration file");
428
429 /* Open the configuration file */
430 conf = Conf_Open(path);
431 if (!conf)
432 err("failed to open configuration file: %s", path);
433
434 /* For each key=value pair in configuration file */
435 for (;;)
436 {
437 const char* key;
438 const char* value;
439 int r = Conf_Read(conf, &key, &value);
440
441 mike 1.1 if (r == -1)
442 err("%s: %s\n", path, Conf_Error(conf));
443
444 if (r == 1)
445 break;
446
447 if (strcmp(key, "schemafile") == 0)
448 {
449 schemafile = value;
450
451 if (schemafile.size() && access(schemafile.c_str(), R_OK) != 0)
452 {
453 err("%s(%u): file given by '%s' key does not exist: %s",
454 path, Conf_Line(conf), key, schemafile.c_str());
455 }
456 }
457 else
458 err("%s(%u): unknown key: %s", path, Conf_Line(conf), key);
459 }
460
461 /* Close configuration file */
462 mike 1.1 Conf_Close(conf);
463 }
464
465 //==============================================================================
466 //
467 // _EncodeStr()
468 //
469 // Encodes special characters in a string; replaces all 'lookfor wtih replacewith
470 //
471 //==============================================================================
472
473 static void _EncodeStr(
474 std::string& str,
475 const std::string lookfor,
476 const std::string& replacewith)
477 {
478 std::string::size_type start = 0;
479 std::string::size_type pos;
480
481 for(;;)
482 {
483 mike 1.1 pos = str.find(lookfor, start);
484
485 if (pos == std::string::npos)
486 break;
487
488 str.replace(pos, lookfor.size(), replacewith);
489 start = pos + replacewith.size();
490 }
491 }
492
493 int main(int argc, const char** argv)
494 {
495 arg0 = argv[0];
496 GeneratorOptions options;
497
498
499 // command line
500 {
501 for (int i = 1; i < argc; i++)
502 {
503 std::string arg = argv[i];
504 mike 1.1
505 // escape special characters
506 _EncodeStr(arg, "\\", "\\\\");
507 _EncodeStr(arg, "\"", "\\\"");
508 _EncodeStr(arg, " ", "\\ ");
509
510 if (!options.cmdLine.empty())
511 options.cmdLine += " ";
512
513 options.cmdLine += arg;
514 }
515 }
516
517 // Get --destdir command-line option.
518 _GetCommandLineDestDirOption(&argc, argv);
519
520 // Set path of default CIM schema file.
521 schemafile = GetPath(ID_SCHEMAFILE);
522
523 // Get configuraiton file options.
524 _GetConfigFileOptions(options);
525 mike 1.1
526 // Get command-line options.
527 _GetCommandLineOptions(argc, argv, options);
528
529 // Check arguments. There must one or mores class name arguments unless
530 // the -a options was given.
531 if (argc < 2 || (!options.all && argc < 3))
532 {
533 fprintf(stderr, "Usage: %s PATH CLASSNAME[=ALIAS] ...\n", arg0);
534 fprintf(stderr, "Try '%s -h' for help\n\n", arg0);
535 exit(1);
536 }
537
538 // ProgramName argument:
539 string programName = argv[0];
540
541 // MofFiles argument (only one file):
542 vector<string> mofFiles;
543 {
544 if (schemafile.size())
545 mofFiles.push_back(schemafile);
546 mike 1.1
547 mofFiles.push_back(argv[1]);
548 }
549
550 // ClassNames argument:
551 vector<string> classNames;
552 {
553 for (int i = 2; i < argc; i++)
554 classNames.push_back(argv[i]);
555 }
556
557 // Invoke generator:
558 return GeneratorMain(programName, mofFiles, classNames, options);
559 }
|