(file) Return to main.cpp CVS log (file) (dir) Up to [OMI] / omi / gen

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

ViewCVS 0.9.2