(file) Return to gen.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           #include "Parser.h"
  26           #include <cstdio>
  27           #include <cstdio>
  28           #include <cstdlib>
  29           #include <cstdarg>
  30           #include <cassert>
  31           #include <cctype>
  32           #include <string>
  33           #include <vector>
  34           #include <set>
  35           #include <map>
  36           
  37           #include <common.h>
  38           #include <strids.h>
  39           
  40           #include "QualifierDecls.h"
  41           
  42 krisbash 1.5 #include <pal/strings.h>
  43 mike     1.1 #include <base/types.h>
  44 krisbash 1.5 #include <pal/format.h>
  45              #include <pal/file.h>
  46              #include <pal/dir.h>
  47 mike     1.1 #include <base/env.h>
  48              #include <base/paths.h>
  49              
  50 krisbash 1.5 #if defined(_MSC_VER)
  51 mike     1.1 # include <time.h>
  52              #else
  53              # include <unistd.h>
  54              # include <sys/time.h>
  55              # include <sys/types.h>
  56              #endif
  57              
  58              #include "gen.h"
  59              
  60              // C Provider Templates:
  61              #include "cprototypes_t.h"
  62              #include "cprovider_t.h"
  63              #include "cmodule_t.h"
  64              #include "cmakefile_t.h"
  65              
  66              // C++ Provider Templates:
  67              #include "cxxmodule_t.h"
  68              #include "cxxprovider_t.h"
  69              #include "cxxstubs_t.h"
  70              #include "cxxmakefile_t.h"
  71              
  72 mike     1.1 using namespace std;
  73              
  74              /* xlc doesn't want to use static inline funciotns inside temaplate functions */
  75              int _Scasecmp(const MI_Char* s1, const MI_Char* s2)
  76              {
  77 krisbash 1.5     return Strcasecmp(s1, s2);
  78 mike     1.1 }
  79              
  80              //==============================================================================
  81              //
  82              // GeneratorOptions
  83              //
  84              //==============================================================================
  85              
  86              GeneratorOptions::GeneratorOptions()
  87              {
  88                  paths.clear();
  89                  descriptions = false;
  90                  values = false;
  91                  mappingStrings = false;
  92                  standardQualifiers = false;
  93                  booleanQualifiers = false;
  94                  ignoreAllQualifiers = false;
  95                  filterSupport = false;
  96                  quiet = false;
  97                  noProviders = false;
  98                  all = false;
  99 mike     1.1     cpp = false;
 100                  schema.clear();
 101                  dir.clear();
 102                  localize = false;
 103                  providerRegistryPath.clear();
 104                  association = false;
 105                  extraClasses.clear();
 106                  entryPoint.clear();
 107 krisbash 1.5     no_warnings = false;
 108                  modelCorrespondence = false;
 109 mike     1.1 }
 110              
 111              //==============================================================================
 112              //
 113              // WARNING
 114              //
 115              //     Message included in all generated files that are not intended to be
 116              //     modified by the developer.
 117              //
 118              //==============================================================================
 119              
 120              #define WARNING \
 121                  "WARNING: THIS FILE WAS AUTOMATICALLY GENERATED. PLEASE DO NOT EDIT."
 122              
 123              //==============================================================================
 124              //
 125              // arg0
 126              //
 127              //     A global pointer to argv[0] that is set immediately by main().
 128              //
 129              //==============================================================================
 130 mike     1.1 
 131              static const char* arg0;
 132              static FILE* s_stdout;
 133              
 134              //==============================================================================
 135              //
 136              // providerClasses
 137              //
 138              //     The set of class names for which there are providers (used by generator
 139              //     to include or exclude various elements).
 140              //
 141              //==============================================================================
 142              
 143              typedef set<string> ProviderClassSet;
 144              static ProviderClassSet providerClasses;
 145              
 146              //==============================================================================
 147              //
 148              // generated
 149              //
 150              //     Allows keep tracking of generated classes in 'generateHeader' function
 151 mike     1.1 //
 152              //==============================================================================
 153              
 154              static set<string> generated_headers;
 155              static set<string> generated_classes;
 156              
 157              //==============================================================================
 158              //
 159 krisbash 1.5 // Fprintf()
 160 mike     1.1 //
 161 krisbash 1.5 //     Formats and writes a message to FILE.
 162 mike     1.1 //
 163              //==============================================================================
 164              
 165              PRINTF_FORMAT(3, 4)
 166              static void Fprintf(FILE* os, int id, const MI_Char* format, ...)
 167              {
 168                  va_list ap;
 169                  va_start(ap, format);
 170              
 171              #if defined(_MSC_VER)
 172                  wchar_t* wformat = LookupString(id);
 173              
 174                  if (wformat)
 175                  {
 176                      vfwprintf(os, wformat, ap);
 177 krisbash 1.5         PAL_Free(wformat);
 178 mike     1.1     }
 179                  else
 180              #endif
 181                  {
 182                      vfprintf(os, format, ap);
 183                  }
 184              
 185                  va_end(ap);
 186              }
 187              
 188              //==============================================================================
 189              //
 190              // err()
 191              //
 192              //     Writes a formatted error message to standard error (preceded by argv[0])
 193 krisbash 1.5 //     and then exits.
 194 mike     1.1 //
 195              //==============================================================================
 196              
 197              PRINTF_FORMAT(2, 3)
 198              void FUNCTION_NEVER_RETURNS err(int id, const char* format, ...)
 199              {
 200                  fprintf(stderr, "%s: ", arg0);
 201              
 202                  va_list ap;
 203                  va_start(ap, format);
 204              
 205              #if defined(_MSC_VER)
 206                  wchar_t* wformat = LookupString(id);
 207              
 208                  if (wformat)
 209                  {
 210                      vfwprintf(stderr, wformat, ap);
 211 krisbash 1.5         PAL_Free(wformat);
 212 mike     1.1     }
 213                  else
 214              #endif
 215                  {
 216                      vfprintf(stderr, format, ap);
 217                  }
 218              
 219                  va_end(ap);
 220              
 221                  fputc('\n', stderr);
 222              
 223                  exit(1);
 224              }
 225              
 226              //==============================================================================
 227              //
 228 krisbash 1.5 // errRefPropCount()
 229              //
 230              //     For assocation class, it must have 2 reference properties count.
 231              //     Otherwise, call this function to write error message and exits.
 232              //
 233              //==============================================================================
 234              void errRefPropCount(const MI_Char* classname)
 235              {
 236                  err(ID_INSUFFICIENT_REFERENCES, "incorrect references properties count: "
 237                      "assocation class %s shall have two references properties", classname);
 238              }
 239              
 240              //==============================================================================
 241              //
 242 mike     1.1 // put()
 243              //
 244              //     Write formatted output to the given stream (similar to fprintf).
 245              //
 246              //==============================================================================
 247              
 248              PRINTF_FORMAT(2, 3)
 249              static void put(FILE* os, const char* fmt, ...)
 250              {
 251                  va_list ap;
 252                  va_start(ap, fmt);
 253                  vfprintf(os, fmt, ap);
 254                  va_end(ap);
 255              }
 256              
 257              //==============================================================================
 258              //
 259              // putl()
 260              //
 261              //     Similar to put() but adds a newline at the end.
 262              //
 263 mike     1.1 //==============================================================================
 264              
 265              PRINTF_FORMAT(2, 3)
 266              static void putl(FILE* os, const char* fmt, ...)
 267              {
 268                  va_list ap;
 269                  va_start(ap, fmt);
 270                  vfprintf(os, fmt, ap);
 271                  va_end(ap);
 272                  fputc('\n', os);
 273              }
 274              
 275              //==============================================================================
 276              //
 277              // Exists()
 278              //
 279              //     Return true if the given file exists.
 280              //
 281              //==============================================================================
 282              
 283              static bool Exists(const char* path)
 284 mike     1.1 {
 285                  return access(path, F_OK) == 0;
 286              }
 287              
 288              //==============================================================================
 289              //
 290              // ValidIdent()
 291              //
 292              //     Check whether the given string is a valid C identifier.
 293              //
 294              //==============================================================================
 295              
 296              static bool ValidIdent(const string& s)
 297              {
 298                  const char* p = s.c_str();
 299              
 300                  if (!isalpha((unsigned char)(*p)) && *p != '_')
 301                      return false;
 302              
 303                  p++;
 304              
 305 mike     1.1     for (; *p; p++)
 306                  {
 307                      if (!isalnum((unsigned char)(*p)) && *p != '_')
 308                          return false;
 309                  }
 310              
 311                  return true;
 312              }
 313              
 314              //==============================================================================
 315              //
 316              // Inhale()
 317              //
 318              //     Read the contents of the given file into memory.
 319              //
 320              //==============================================================================
 321              
 322              static bool Inhale(const char* path, vector<char>& data)
 323              {
 324 krisbash 1.5     FILE* is = File_Open(path, "r");
 325 mike     1.1 
 326                  if (!is)
 327                      return false;
 328              
 329                  size_t n;
 330                  char buf[4096];
 331              
 332                  while ((n = fread(buf, 1, sizeof(buf), is)) != 0)
 333                  {
 334                      data.insert(data.end(), buf, buf + n);
 335                  }
 336              
 337                  data.push_back('\0');
 338              
 339                  fclose(is);
 340              
 341                  return true;
 342              }
 343              
 344              //==============================================================================
 345              //
 346 mike     1.1 // puts()
 347              //
 348              //     Put a string onto the output stream.
 349              //
 350              //==============================================================================
 351              
 352              static void puts(FILE* os, const string& s)
 353              {
 354                  fprintf(os, "%s", s.c_str());
 355              }
 356              
 357              //==============================================================================
 358              //
 359              // eqi()
 360              //
 361              //     Return true if the two strings are identical except for case.
 362              //
 363              //==============================================================================
 364              
 365              static bool eqi(const char* s1, const char* s2)
 366              {
 367 mike     1.1     return Strcasecmp(s1, s2) == 0;
 368              }
 369              
 370              //==============================================================================
 371              //
 372              // nl()
 373              //
 374              //     Print a newline to the given stream.
 375              //
 376              //==============================================================================
 377              
 378              inline void nl(FILE* os)
 379              {
 380                  fputc('\n', os);
 381              }
 382              
 383              //==============================================================================
 384              //
 385              // Generate a random key
 386              //
 387              //==============================================================================
 388 mike     1.1 
 389              #if 0
 390              
 391              static MI_Uint64 _GetCurrentTime()
 392              {
 393              #if defined(CONFIG_OS_WINDOWS)
 394                  FILETIME ft;
 395                  ULARGE_INTEGER tmp;
 396              
 397                  GetSystemTimeAsFileTime(&ft);
 398                  tmp.u.LowPart = ft.dwLowDateTime;
 399                  tmp.u.HighPart = ft.dwHighDateTime;
 400                  tmp.QuadPart -= 0X19DB1DED53E8000;
 401                  return tmp.QuadPart / (UINT64)10;
 402              #else
 403                  struct timeval tv;
 404                  struct timezone tz;
 405                  memset(&tv, 0, sizeof(tv));
 406                  memset(&tz, 0, sizeof(tz));
 407              
 408                  if (gettimeofday(&tv, &tz) != 0)
 409 mike     1.1         return MI_RESULT_FAILED;
 410              
 411                  return (MI_Uint64)tv.tv_sec * (MI_Uint64)1000000 + (MI_Uint64)tv.tv_usec;
 412              #endif
 413              }
 414              
 415              static void _SleepMsec(MI_Uint64 msec)
 416              {
 417              #if defined(CONFIG_OS_WINDOWS)
 418                  Sleep((DWORD)msec);
 419              #else
 420                  struct timespec rqtp;
 421              
 422                  rqtp.tv_sec = static_cast<long>(msec/1000);
 423                  rqtp.tv_nsec = static_cast<long>((msec%1000)*1000*1000);
 424              
 425                  nanosleep(&rqtp, NULL);
 426              #endif
 427              }
 428              
 429              static void _MakeID(char id[33])
 430 mike     1.1 {
 431                  MI_Uint64 s1 = _GetCurrentTime();
 432                  _SleepMsec(10);
 433                  MI_Uint64 s2 = _GetCurrentTime();
 434              
 435                  srand((unsigned int)(((s1 >> 32) ^ s1 ^ (s2 >> 32)) | s2));
 436              
 437                  static const char XDIGITS[] =
 438                  {
 439                      '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',
 440                  };
 441              
 442                  for (size_t i = 0; i < 32; i++)
 443                  {
 444                      int x = rand() % 16;
 445                      id[i] = XDIGITS[x];
 446                  }
 447              
 448                  id[32] = '\0';
 449              }
 450              
 451 mike     1.1 #endif
 452              
 453              //==============================================================================
 454              //
 455              // GeneratorOptions
 456              //
 457              //     This structure defines program options. These include:
 458              //
 459              //==============================================================================
 460              
 461              static GeneratorOptions s_options;
 462              
 463              static set<string> s_generated;
 464              
 465              //==============================================================================
 466              //
 467              // GenStatikGenLine()
 468              //
 469              //==============================================================================
 470              
 471              static void GenStatikGenLine(FILE* os)
 472 mike     1.1 {
 473                  // Files generated by Statik may be located by searching for files which
 474                  // contain the following string. The ampersands are separted into a format
 475                  // argument to prevent this file (generator.cpp) from containg that string.
 476                  fprintf(os, "/* %cmigen%c */\n", '@', '@');
 477              }
 478              
 479              //==============================================================================
 480              //
 481              // aliases
 482              //
 483              //     Maps MOF classnames to aliases. This map is built in main before 
 484              //     classes are generated. The generator consults this table to determine 
 485              //     the real name of the C structure (the alias) which may be different 
 486              //     than the name of the MOF class.
 487              //
 488              //==============================================================================
 489              
 490              typedef map<string, string> Aliases;
 491              static Aliases aliases;
 492              
 493 mike     1.1 //==============================================================================
 494              //
 495              // Quote()
 496              //
 497              //     This function puts quotation marks around a string.
 498              //
 499              //==============================================================================
 500              
 501              static string Quote(const string& str)
 502              {
 503                  return "MI_T(\"" + str + "\")";
 504              }
 505              
 506              //==============================================================================
 507              //
 508              // ExpandPath()
 509              //
 510              //     Obtain the full path (including directory given by optional -d option).
 511              //
 512              //==============================================================================
 513              
 514 mike     1.1 static string ExpandPath(const string& str)
 515              {
 516                  if (s_options.dir.size())
 517                  {
 518                      string r = s_options.dir + "/" + str;
 519                      return s_options.dir + "/" + str;
 520                  }
 521                  else
 522                      return str;
 523              }
 524              
 525              //==============================================================================
 526              //
 527              // Contains()
 528              //
 529              //     Return true if this vector contains the given string.
 530              //
 531              //==============================================================================
 532              
 533              static bool Contains(const vector<string>& v, const string& s)
 534              {
 535 mike     1.1     for (size_t i = 0; i < v.size(); i++)
 536                  {
 537                      if (s == v[i])
 538                          return true;
 539                  }
 540              
 541                  return false;
 542              }
 543              
 544              //==============================================================================
 545              //
 546              // MakeFlags()
 547              //
 548              //     This function builds a flags expression from a bit mask. For example,
 549              //     for a key property, the flag expression might look like this:
 550              //
 551              //         MI_FLAG_PROPERTY | MI_FLAG_KEY
 552              //
 553              //     Many structures have a flags field whose bits indicate the type of the
 554              //     object (e.g., MI_FLAG_CLASS, MI_FLAG_METHOD, MI_FLAG_PROPERTY) as well 
 555              //     as any boolean qualifiers whose values are true (e.g., MI_FLAG_KEY, 
 556 mike     1.1 //     MI_FLAG_IN, MI_FLAG_OUT).
 557              //
 558              //==============================================================================
 559              
 560              static string MakeFlags(MI_Uint32 flags)
 561              {
 562                  struct
 563                  {
 564                      const char* name;
 565                      MI_Uint32 flag;
 566                  }
 567                  _flags[] =
 568                  {
 569                      { "CLASS", MI_FLAG_CLASS },
 570                      { "METHOD", MI_FLAG_METHOD },
 571                      { "PROPERTY", MI_FLAG_PROPERTY },
 572                      { "PARAMETER", MI_FLAG_PARAMETER },
 573                      { "ASSOCIATION", MI_FLAG_ASSOCIATION },
 574                      { "INDICATION", MI_FLAG_INDICATION },
 575                      { "REFERENCE", MI_FLAG_REFERENCE },
 576                      { "KEY", MI_FLAG_KEY },
 577 mike     1.1         { "IN", MI_FLAG_IN },
 578                      { "OUT", MI_FLAG_OUT },
 579                      { "REQUIRED", MI_FLAG_REQUIRED },
 580                      { "STATIC", MI_FLAG_STATIC },
 581                      { "ABSTRACT", MI_FLAG_ABSTRACT },
 582                      { "TERMINAL", MI_FLAG_TERMINAL },
 583                      { "EXPENSIVE", MI_FLAG_EXPENSIVE },
 584                      { "STREAM", MI_FLAG_STREAM },
 585                      { "ENABLEOVERRIDE", MI_FLAG_ENABLEOVERRIDE },
 586                      { "DISABLEOVERRIDE", MI_FLAG_DISABLEOVERRIDE },
 587                      { "RESTRICTED", MI_FLAG_RESTRICTED},
 588                      { "TOSUBCLASS", MI_FLAG_TOSUBCLASS},
 589                      { "TRANSLATABLE", MI_FLAG_TRANSLATABLE},
 590                  };
 591              
 592                  string result;
 593                  size_t count = 0;
 594              
 595                  for (size_t i = 0; i < MI_COUNT(_flags); i++)
 596                  {
 597                      if (_flags[i].flag & flags)
 598 mike     1.1         {
 599                          if (count)
 600                              result += "|";
 601                          result += string("MI_FLAG_") + _flags[i].name;
 602                          count++;
 603                      }
 604                  }
 605              
 606                  if (result.size())
 607                      return result;
 608              
 609                  return "0";
 610              }
 611              
 612              //==============================================================================
 613              //
 614              // MakeFlavor()
 615              //
 616              //     This function builds a flavor string from the given flavor mask. For
 617              //     example:
 618              //
 619 mike     1.1 //         MI_FLAG_TOSUBCLASS | MI_FLAG_DISABLEOVERRIDE
 620              //
 621              //==============================================================================
 622              
 623              static string MakeFlavor(MI_Uint32 flavor)
 624              {
 625                  struct
 626                  {
 627                      MI_Uint32 mask;
 628                      const char* name;
 629                  }
 630                  _flavors[] =
 631                  {
 632                      { MI_FLAG_ENABLEOVERRIDE, "MI_FLAG_ENABLEOVERRIDE" },
 633                      { MI_FLAG_DISABLEOVERRIDE, "MI_FLAG_DISABLEOVERRIDE" },
 634                      { MI_FLAG_TOSUBCLASS, "MI_FLAG_TOSUBCLASS" },
 635                      { MI_FLAG_TRANSLATABLE, "MI_FLAG_TRANSLATABLE" },
 636                      { MI_FLAG_RESTRICTED, "MI_FLAG_RESTRICTED" },
 637                  };
 638              
 639                  string result;
 640 mike     1.1     size_t count = 0;
 641              
 642                  for (size_t i = 0; i < MI_COUNT(_flavors); i++)
 643                  {
 644                      if (_flavors[i].mask & flavor)
 645                      {
 646                          if (count)
 647                              result += "|";
 648                          result += _flavors[i].name;
 649                          count++;
 650                      }
 651                  }
 652              
 653                  if (result.size())
 654                      return result;
 655              
 656                  return "0";
 657              }
 658              
 659              //==============================================================================
 660              //
 661 mike     1.1 // MakeScope()
 662              //
 663              //     This function builds a scope string from the given scope mask. For
 664              //     example:
 665              //
 666              //         MI_FLAG_TOSUBCLASS | MI_FLAG_DISABLEOVERRIDE
 667              //
 668              //==============================================================================
 669              
 670              static string MakeScope(MI_Uint32 scope)
 671              {
 672                  struct
 673                  {
 674                      MI_Uint32 mask;
 675                      const char* name;
 676                  }
 677                  _scopes[] =
 678                  {
 679                      { MI_FLAG_ASSOCIATION, "MI_FLAG_ASSOCIATION" },
 680                      { MI_FLAG_CLASS, "MI_FLAG_CLASS" },
 681                      { MI_FLAG_INDICATION, "MI_FLAG_INDICATION" },
 682 mike     1.1         { MI_FLAG_METHOD, "MI_FLAG_METHOD" },
 683                      { MI_FLAG_PARAMETER, "MI_FLAG_PARAMETER" },
 684                      { MI_FLAG_PROPERTY, "MI_FLAG_PROPERTY" },
 685                      { MI_FLAG_REFERENCE, "MI_FLAG_REFERENCE" },
 686                  };
 687              
 688                  if ((scope & MI_FLAG_ANY) == MI_FLAG_ANY)
 689                      return "MI_FLAG_ANY";
 690              
 691                  string result;
 692                  size_t count = 0;
 693              
 694                  for (size_t i = 0; i < MI_COUNT(_scopes); i++)
 695                  {
 696                      if (_scopes[i].mask & scope)
 697                      {
 698                          if (count)
 699                              result += "|";
 700                          result += _scopes[i].name;
 701                          count++;
 702                      }
 703 mike     1.1     }
 704              
 705                  if (result.size())
 706                      return result;
 707              
 708                  return "0";
 709              }
 710              
 711              //==============================================================================
 712              //
 713              // MakeType()
 714              //
 715              //     This function returns the type tag string for the given Statik type
 716              //     (given by the MI_Type structure). 
 717              //
 718              //==============================================================================
 719              
 720              static string MakeType(MI_Uint32 type)
 721              {
 722                  switch (type)
 723                  {
 724 mike     1.1         case MI_BOOLEAN: return "MI_BOOLEAN";
 725                      case MI_UINT8: return "MI_UINT8";
 726                      case MI_SINT8: return "MI_SINT8";
 727                      case MI_UINT16: return "MI_UINT16";
 728                      case MI_SINT16: return "MI_SINT16";
 729                      case MI_UINT32: return "MI_UINT32";
 730                      case MI_SINT32: return "MI_SINT32";
 731                      case MI_UINT64: return "MI_UINT64";
 732                      case MI_SINT64: return "MI_SINT64";
 733                      case MI_REAL32: return "MI_REAL32";
 734                      case MI_REAL64: return "MI_REAL64";
 735                      case MI_CHAR16: return "MI_CHAR16";
 736                      case MI_DATETIME: return "MI_DATETIME";
 737                      case MI_STRING: return "MI_STRING";
 738                      case MI_REFERENCE: return "MI_REFERENCE";
 739                      case MI_INSTANCE: return "MI_INSTANCE";
 740                      case MI_BOOLEANA: return "MI_BOOLEANA";
 741                      case MI_UINT8A: return "MI_UINT8A";
 742                      case MI_SINT8A: return "MI_SINT8A";
 743                      case MI_UINT16A: return "MI_UINT16A";
 744                      case MI_SINT16A: return "MI_SINT16A";
 745 mike     1.1         case MI_UINT32A: return "MI_UINT32A";
 746                      case MI_SINT32A: return "MI_SINT32A";
 747                      case MI_UINT64A: return "MI_UINT64A";
 748                      case MI_SINT64A: return "MI_SINT64A";
 749                      case MI_REAL32A: return "MI_REAL32A";
 750                      case MI_REAL64A: return "MI_REAL64A";
 751                      case MI_CHAR16A: return "MI_CHAR16A";
 752                      case MI_DATETIMEA: return "MI_DATETIMEA";
 753                      case MI_STRINGA: return "MI_STRINGA";
 754                      case MI_REFERENCEA: return "MI_REFERENCEA";
 755                      case MI_INSTANCEA: return "MI_INSTANCEA";
 756                      default: return "UNKNOWN_TYPE";
 757                  };
 758              }
 759              
 760              //==============================================================================
 761              //
 762              // AliasOf()
 763              //
 764              //     The the given class name is in the alias map, return the alias. 
 765              //     Otherwise, just return the class name.
 766 mike     1.1 //
 767              //==============================================================================
 768              
 769              string AliasOf(const string& className)
 770              {
 771                  Aliases::const_iterator pos = aliases.find(className);
 772              
 773                  if (pos != aliases.end())
 774                      return (*pos).second;
 775              
 776                  return className;
 777              }
 778              
 779              //==============================================================================
 780              //
 781              // PutRule()
 782              //
 783              //     Put a rule line (2 '*' characters followed by 78 '=' characters).
 784              //
 785              //==============================================================================
 786              
 787 mike     1.1 static void PutRule(FILE* os)
 788              {
 789                  put(os, "**");
 790              
 791                  for (size_t i = 0; i < 78; i++)
 792                      put(os, "=");
 793              
 794                  nl(os);
 795              }
 796              
 797              //==============================================================================
 798              //
 799              // PutCommentBox()
 800              //
 801              //     Put a C comment box with a message in it.
 802              //
 803              //==============================================================================
 804              
 805              static void PutCommentBox(FILE* os, const string& msg)
 806              {
 807                  putl(os, "/*");
 808 mike     1.1     PutRule(os);
 809                  putl(os, "**");
 810                  putl(os, "** %s", msg.c_str());
 811                  putl(os, "**");
 812                  PutRule(os);
 813                  putl(os, "*/");
 814              }
 815              
 816              //==============================================================================
 817              //
 818              // TypeNameOf()
 819              //
 820              //     Return the C type name for the given Statik type tag. For arrays type
 821              //     tags, return the C type name of the element type. For example:
 822              //
 823              //         TypeNameOf(MI_UINT8) => "Uint8"
 824              //         TypeNameOf(MI_UINT8A) => "Uint8"
 825              // 
 826              //==============================================================================
 827              
 828              static const char* TypeNameOf(MI_Uint32 type)
 829 mike     1.1 {
 830                  switch (type)
 831                  {
 832                      case MI_BOOLEAN:
 833                          return "Boolean";
 834                      case MI_SINT8:
 835                          return "Sint8";
 836                      case MI_UINT8:
 837                          return "Uint8";
 838                      case MI_SINT16:
 839                          return "Sint16";
 840                      case MI_UINT16:
 841                          return "Uint16";
 842                      case MI_SINT32:
 843                          return "Sint32";
 844                      case MI_UINT32:
 845                          return "Uint32";
 846                      case MI_SINT64:
 847                          return "Sint64";
 848                      case MI_UINT64:
 849                          return "Uint64";
 850 mike     1.1         case MI_REAL32:
 851                          return "Real32";
 852                      case MI_REAL64:
 853                          return "Real64";
 854                      case MI_CHAR16:
 855                          return "Char16";
 856                      case MI_DATETIME:
 857                          return "Datetime";
 858                      case MI_STRING:
 859                          return "String";
 860                      case MI_REFERENCE:
 861                          return "Reference";
 862                      case MI_INSTANCE:
 863                          return "Instance";
 864                      case MI_BOOLEANA:
 865                          return "Boolean";
 866                      case MI_SINT8A:
 867                          return "Sint8";
 868                      case MI_UINT8A:
 869                          return "Uint8";
 870                      case MI_SINT16A:
 871 mike     1.1             return "Sint16";
 872                      case MI_UINT16A:
 873                          return "Uint16";
 874                      case MI_SINT32A:
 875                          return "Sint32";
 876                      case MI_UINT32A:
 877                          return "Uint32";
 878                      case MI_SINT64A:
 879                          return "Sint64";
 880                      case MI_UINT64A:
 881                          return "Uint64";
 882                      case MI_REAL32A:
 883                          return "Real32";
 884                      case MI_REAL64A:
 885                          return "Real64";
 886                      case MI_CHAR16A:
 887                          return "Char16";
 888                      case MI_DATETIMEA:
 889                          return "Datetime";
 890                      case MI_STRINGA:
 891                          return "String";
 892 mike     1.1         case MI_REFERENCEA:
 893                          return "Reference";
 894                      case MI_INSTANCEA:
 895                          return "Instance";
 896                      default:
 897                          return "UNKNOWN";
 898                  }
 899              }
 900              
 901              //==============================================================================
 902              //
 903              // CountRefs()
 904              //
 905              //     Count how many roles (references) the given class has.
 906              //
 907              //==============================================================================
 908              
 909              static size_t CountRefs(const MI_ClassDecl* cd)
 910              {
 911                  size_t r = 0;
 912              
 913 mike     1.1     for (size_t i = 0; i < cd->numProperties; i++)
 914                  {
 915                      const MI_PropertyDecl* pd = cd->properties[i];
 916              
 917                      if (pd->type == MI_REFERENCE)
 918                          r++;
 919                  }
 920              
 921                  return r;
 922              }
 923              
 924              //==============================================================================
 925              //
 926              // CanGenerateAssocRoles()
 927              //
 928              //     returns true if:
 929              //  - association class has two references
 930              //  - ref classes are not inherited from each other
 931              //
 932              //==============================================================================
 933              
 934 mike     1.1 static bool CanGenerateAssocRoles(const MI_ClassDecl* cd)
 935              {
 936                  if (2 != CountRefs(cd))
 937                      return false;
 938              
 939                  int index1 = -1, index2 = -1;
 940              
 941                  for (int i = 0; i < (int)cd->numProperties; i++)
 942                  {
 943                      const MI_PropertyDecl* pd = cd->properties[i];
 944              
 945                      if (pd->type == MI_REFERENCE)
 946                      {
 947                          if (-1 == index1)
 948                              index1 = i;
 949                          else 
 950                              index2 = i;
 951                      }
 952                  }
 953              
 954                  if (-1 == index2 ||
 955 mike     1.1         !cd->properties[index1]->className ||
 956                      !cd->properties[index2]->className)
 957                      return false;
 958              
 959 mike     1.3     return true;
 960 mike     1.1 }
 961              
 962              //==============================================================================
 963              //
 964              // FullTypeNameOf()
 965              //
 966              //     Same as TypeNameOf() except that it gives the full typedef name.
 967              //
 968              //         TypeNameOf(MI_UINT8) => "MI_Uint8"
 969              // 
 970              //==============================================================================
 971              
 972              static string FullTypeNameOf(MI_Uint32 type)
 973              {
 974                  return string("MI_") + TypeNameOf(type);
 975              }
 976              
 977              //==============================================================================
 978              //
 979              // CppTypeNameOf()
 980              //
 981 mike     1.1 //     Return the Cpp type name for the given Statik type tag. For arrays type
 982              //     tags, return the Cpp type name of the element type. For example:
 983              //
 984              //         CppTypeNameOf(MI_UINT8) => "Uint8"
 985              //         CppTypeNameOf(MI_UINT8A) => "Uint8"
 986              // 
 987              //==============================================================================
 988              
 989              const char* CppTypeNameOf(MI_Uint32 type)
 990              {
 991                  const char* res = TypeNameOf(type);
 992              
 993                  return res;
 994              }
 995              
 996              //==============================================================================
 997              //
 998              // ScalarSizeOf()
 999              //
1000              //     Return the size of the given type; for arrays return the element size.
1001              // 
1002 mike     1.1 //==============================================================================
1003              
1004              INLINE MI_Uint32 ScalarSizeOf(MI_Uint32 type)
1005              {
1006                  return (MI_Uint32)Type_SizeOf(Type_ScalarOf(MI_Type(type)));
1007              }
1008              
1009              //==============================================================================
1010              //
1011              // sub()
1012              //
1013              //     Substitute all occurences of 'pattern' with 'replacement' within the
1014              //     'str' parameter. Return the result.
1015              // 
1016              //==============================================================================
1017              
1018              string sub(
1019                  const string& str,
1020                  const string& pattern,
1021                  const string& replacement)
1022              {
1023 mike     1.1     size_t pos = 0;
1024                  string r = str;
1025              
1026                  while ((pos = r.find(pattern, pos)) != string::npos)
1027                  {
1028                      r = r.substr(0, pos) + replacement + r.substr(pos + pattern.size());
1029                      pos += replacement.size();
1030                  }
1031              
1032                  return r;
1033              }
1034              
1035              //==============================================================================
1036              //
1037              // subu()
1038              //
1039              //     Similiar to sub() but substitutes an unsigned integer.
1040              // 
1041              //==============================================================================
1042              
1043              static string subu(
1044 mike     1.1     const string& str,
1045                  const string& pattern,
1046                  MI_Uint32 replacement)
1047              {
1048                  char buf[32];
1049                  Snprintf(buf, sizeof(buf), "%u", replacement);
1050                  return sub(str, pattern, buf);
1051              }
1052              
1053              //==============================================================================
1054              //
1055              // subx()
1056              //
1057              //     Similiar to sub() but substitutes an unsigned integer (as hex string).
1058              // 
1059              //==============================================================================
1060              
1061              static string subx(
1062                  const string& str,
1063                  const string& pattern,
1064                  MI_Uint32 replacement)
1065 mike     1.1 {
1066                  char buf[32];
1067                  Snprintf(buf, sizeof(buf), "0x%08X", replacement);
1068                  return sub(str, pattern, buf);
1069              }
1070              
1071              //==============================================================================
1072              //
1073              // subd()
1074              //
1075              //     Substitute all occurences of 'pattern' with the string form of 
1076              //     'replacement' within the 'str' parameter.
1077              // 
1078              //==============================================================================
1079              
1080              #if 0
1081              static string subd(
1082                  const string& str,
1083                  const string& pattern,
1084                  MI_Sint32 replacement)
1085              {
1086 mike     1.1     char buf[32];
1087                  Snprintf(buf, sizeof(buf), "%d", replacement);
1088                  return sub(str, pattern, buf);
1089              }
1090              #endif
1091              
1092              //==============================================================================
1093              //
1094              // FindStandardQualifierDecl()
1095              //
1096              //     Find the standard qualifier declaration with the given name.
1097              // 
1098              //==============================================================================
1099              
1100              static const MI_QualifierDecl* FindStandardQualifierDecl(const char* name)
1101              {
1102                  for (size_t i = 0; i < g_numQualifierDecls; i++)
1103                  {
1104                      MI_QualifierDecl* qd = g_qualifierDecls[i];
1105              
1106                      if (Strcasecmp(qd->name, name) == 0)
1107 mike     1.1             return qd;
1108                  }
1109                  /* Not found! */
1110                  return NULL;
1111              }
1112              
1113              //==============================================================================
1114              //
1115              // FindPropertyDecl()
1116              //
1117              //     Find the named property in the given class declarartion. Return a 
1118              //     pointer if found, else return NULL.
1119              // 
1120              //==============================================================================
1121              
1122              static const MI_PropertyDecl* FindPropertyDecl(
1123                  const MI_ClassDecl* cd, 
1124                  const char* name)
1125              {
1126                  for (size_t i = 0; i < cd->numProperties; i++)
1127                  {
1128 mike     1.1         if (Strcasecmp(cd->properties[i]->name, name) == 0)
1129                          return cd->properties[i];
1130                  }
1131              
1132                  /* Not found */
1133                  return NULL;
1134              }
1135              
1136              //==============================================================================
1137              //
1138              // ExistInstanceQualifier
1139              //
1140              //     returns 'true' if EmbeddedInstance/Object qualifier is set 
1141              //
1142              //==============================================================================
1143              template< typename PropertyDeclType>
1144              bool ExistInstanceQualifier(
1145                  const PropertyDeclType* pd)
1146              {
1147                  for ( MI_Uint32 i = 0; i < pd->numQualifiers; i++ )
1148                  {
1149 mike     1.1         if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedInstance")) == 0)
1150                          return true;
1151                      if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedObject")) == 0)
1152                          return true;
1153                  }
1154                  return false;
1155              }
1156              
1157              //==============================================================================
1158              //
1159              // IsPropertyRefOrInstance
1160              //
1161              //     returns 'true' if property (or parameter) is 
1162              //      REFERENCE, REFERENCEA, EmbeddedInstance [arry], EmbeddedObject [array]
1163              //
1164              //==============================================================================
1165              template< typename PropertyDeclType>
1166              bool IsPropertyRefOrInstance(
1167                  const PropertyDeclType* pd)
1168              {
1169              
1170 mike     1.1     if ((pd->type == MI_REFERENCE) || (pd->type == MI_REFERENCEA))
1171                      return true;
1172              
1173                  if ((pd->type == MI_INSTANCE) || (pd->type == MI_INSTANCEA))
1174                      return true;
1175              
1176                  if ((pd->type == MI_STRING) || (pd->type == MI_STRINGA))
1177                      return ExistInstanceQualifier<PropertyDeclType>(pd);
1178              
1179                  return false;
1180              }
1181              
1182              //==============================================================================
1183              //
1184              // GetPropertyClassname
1185              //
1186              //     returns 'class-name' of the property; only makes sense for 
1187              //     REFERENCE, REFERENCEA, EmbeddedInstance [arry], EmbeddedObject [array]
1188              //     for EmbeddedObject returns empty string
1189              //
1190              //==============================================================================
1191 mike     1.1 template< typename PropertyDeclType>
1192              string GetPropertyClassname(
1193                  const PropertyDeclType* pd)
1194              {
1195              
1196                  if ((pd->type == MI_REFERENCE) || (pd->type == MI_REFERENCEA))
1197                      return pd->className;
1198              
1199                  if ((pd->type == MI_INSTANCE) || (pd->type == MI_INSTANCEA))
1200                      return pd->className ? pd->className : "";
1201              
1202                  if ((pd->type == MI_STRING) || (pd->type == MI_STRINGA))
1203                  {
1204                      for ( MI_Uint32 i = 0; i < pd->numQualifiers; i++ )
1205                      {
1206                          if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedInstance"))==0)
1207                          {
1208                              if (pd->qualifiers[i]->type != MI_STRING)
1209                              {
1210                                  err(ID_EMBEDDEDINSTANCE_ON_NON_STRING,
1211                                      "EmbeddedInstance qualifier on non-string type: %s",
1212 mike     1.1                         pd->name);
1213                              }
1214              
1215                              return (const MI_Char*)pd->qualifiers[i]->value;
1216                          }
1217                          if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedObject")) == 0)
1218                              return string();
1219                      }
1220                      return string();
1221                  }
1222              
1223                  return string();
1224              }
1225              
1226              //==============================================================================
1227              //
1228              // GenProperties()
1229              //
1230              //     This function writes properties for the MOF class currently being
1231              //     generated (i.e., it generates fields for the corresponing C structure).
1232              //     Properties are written in the order they are encountered when 
1233 mike     1.1 //     traversing from the root of the inheritance chain to the current class.
1234              //     A property may be defined more than once in the inheritance chain due
1235              //     to overriding. In that case, overrides by descendent classes have no
1236              //     bearing on the order.
1237              //
1238              //==============================================================================
1239              
1240              // Keeps track of property-name/class-name pairs.
1241              typedef map<string,string> NameClassMap;
1242              typedef pair<string,string> NameClassPair;
1243              
1244              static void GenProperties(
1245                  FILE* os,
1246                  Parser& parser,
1247                  const MI_ClassDecl* lcd, /* the leaf class in the recursion */
1248                  const MI_ClassDecl* cd,
1249                  NameClassMap& map)
1250              {
1251                  // Inject the property-name and class-name for all reference properties
1252                  // first. During recursion we want to use the class-name of the most
1253                  // derived reference declaration.
1254 mike     1.1 
1255                  for (size_t i = 0; i < cd->numProperties; i++)
1256                  {
1257                      const MI_PropertyDecl* pd = cd->properties[i];
1258              
1259                      if (pd->type == MI_REFERENCE)
1260                      {
1261                          if (map.find(pd->name) == map.end())
1262                              map.insert(NameClassPair(pd->name, pd->className));
1263                      }
1264                  }
1265              
1266                  // Recurse on superclass (if any) and print its properties first.
1267                  if (cd->superClass)
1268                  {
1269                      const MI_ClassDecl* scd = parser.findClassDecl(cd->superClass);
1270              
1271                      if (!scd)
1272                          err(ID_UNKNOWN_SUPERCLASS_FOR, "unknown superclass for %s: %s", 
1273                              cd->name, cd->superClass);
1274              
1275 mike     1.1         GenProperties(os, parser, lcd, scd, map);
1276                  }
1277              
1278                  // Print the local properties of this class.
1279                  putl(os, "    /* %s properties */", AliasOf(cd->name).c_str());
1280              
1281                  for (size_t i = 0; i < cd->numProperties; i++)
1282                  {
1283                      const MI_PropertyDecl* pd = cd->properties[i];
1284              
1285                      // Skip non-local properties:
1286                      if (Strcasecmp(cd->name, pd->origin) != 0)
1287                          continue;
1288              
1289                      // Indent this property.
1290                      put(os, "    ");
1291              
1292                      // Put the key attribute if the property in the leaf class has
1293                      // the Key qualifier.
1294                      {
1295                          const MI_PropertyDecl* lpd = FindPropertyDecl(lcd, pd->name);
1296 mike     1.1 
1297                          if (lpd && (lpd->flags & MI_FLAG_KEY))
1298                              put(os, "/*KEY*/ ");
1299                      }
1300              
1301                      if (pd->type == MI_REFERENCE)
1302                      {
1303                          // If a derived class defines this property, use the classname
1304                          // that it uses for the property.
1305              
1306                          NameClassMap::iterator p = map.find(pd->name);
1307                          string al;
1308              
1309                          if (p == map.end())
1310                          {
1311                              al = AliasOf(pd->className);
1312                          }
1313                          else
1314                          {
1315                              al = AliasOf((*p).second);
1316                          }
1317 mike     1.1 
1318                          putl(os, "%s_ConstRef %s;", al.c_str(), pd->name);
1319                      }
1320                      else if (pd->type == MI_REFERENCEA)
1321                      {
1322                          err(ID_REFERENCE_ARRAY_AS_PROPERTY,
1323                              "reference arrays are not allowed as properties");
1324                      }
1325                      else if (IsPropertyRefOrInstance(pd) && 
1326                          !GetPropertyClassname(pd).empty())
1327                      {   // embedded instance
1328                          const string al = AliasOf(GetPropertyClassname(pd));
1329              
1330                          if (pd->type & MI_ARRAY_BIT)
1331                          {
1332                              putl(os, "%s_ConstArrayRef %s;", al.c_str(), pd->name);
1333                          }
1334                          else
1335                          {
1336                              putl(os, "%s_ConstRef %s;", al.c_str(), pd->name);
1337                          }
1338 mike     1.1         }
1339                      else if (IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty())
1340                      {   // embedded object
1341                          if (pd->type & MI_ARRAY_BIT)
1342                          {
1343                              putl(os, "MI_ConstReferenceAField %s;", pd->name);
1344                          }
1345                          else
1346                          {
1347                              putl(os, "MI_ConstReferenceField %s;", pd->name);
1348                          }
1349                      }
1350                      else if (pd->type & MI_ARRAY_BIT)
1351                      {
1352                          putl(os, "MI_Const%sAField %s;", TypeNameOf(pd->type), 
1353                              pd->name);
1354                      }
1355                      else
1356                      {
1357                          putl(os, "MI_Const%sField %s;", TypeNameOf(pd->type), 
1358                              pd->name);
1359 mike     1.1         }
1360                  }
1361              }
1362              
1363              //==============================================================================
1364              //
1365              // GenSingleParameter()
1366              //
1367              //     This function generates the parameter structure, which holds the 
1368              //     extrinsic method parameters that are passed to an extrinsic method 
1369              //     provider stub. The return value is also defined in the structure whose
1370              //     field name is "MIReturn".
1371              //
1372              //==============================================================================
1373              static void GenSingleParameter(
1374                  FILE* os,
1375                  const MI_ParameterDecl* pd)
1376              {
1377                  if (pd->flags & MI_FLAG_IN && pd->flags & MI_FLAG_OUT)
1378                      put(os, "    /*IN-OUT*/ ");
1379                  else if (pd->flags & MI_FLAG_IN)
1380 mike     1.1         put(os, "    /*IN*/ ");
1381                  else if (pd->flags & MI_FLAG_OUT)
1382                      put(os, "    /*OUT*/ ");
1383              
1384                  if (IsPropertyRefOrInstance(pd) && !GetPropertyClassname(pd).empty())
1385                  {
1386                      const string al = AliasOf(GetPropertyClassname(pd));
1387              
1388                      if (pd->type & MI_ARRAY_BIT)
1389                      {
1390                          putl(os, "%s_ConstArrayRef %s;", al.c_str(), pd->name);
1391                      }
1392                      else
1393                      {
1394                          putl(os, "%s_ConstRef %s;", al.c_str(), pd->name);
1395                      }
1396                  }
1397                  else if (IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty())
1398                  {   // embedded object
1399                      if (pd->type & MI_ARRAY_BIT)
1400                      {
1401 mike     1.1             putl(os, "MI_ConstReferenceAField %s;", pd->name);
1402                      }
1403                      else
1404                      {
1405                          putl(os, "MI_ConstReferenceField %s;", pd->name);
1406                      }
1407                  }
1408                  else if (pd->type & MI_ARRAY_BIT)
1409                  {
1410                      putl(os, "MI_Const%sAField %s;", TypeNameOf(pd->type), 
1411                          pd->name);
1412                  }
1413                  else
1414                  {
1415                      putl(os, "MI_Const%sField %s;", TypeNameOf(pd->type), 
1416                          pd->name);
1417                  }
1418              }
1419              //==============================================================================
1420              //
1421              // GenParameters()
1422 mike     1.1 //
1423              //     This function generates MOF method parameters (i.e., C fields for the
1424              //     parameters structure).
1425              //
1426              //==============================================================================
1427              
1428              static void GenParameters(
1429                  FILE* os,
1430                  const MI_ClassDecl* cd,
1431                  const MI_MethodDecl* md)
1432              {
1433                  for (size_t i = 0; i < md->numParameters; i++)
1434                  {
1435                      const MI_ParameterDecl* pd = md->parameters[i];
1436              
1437                      // Skip stream parameters:
1438                      if (pd->flags & MI_FLAG_STREAM)
1439                      {
1440                          if (!(pd->type & MI_ARRAY_BIT))
1441                          {
1442                              err(ID_STREAM_QUALIFIER_ON_NON_ARRAY, 
1443 mike     1.1                     "'Stream' qualifiers may only appear on array parameters: "
1444                                  "%s.%s(): %s",
1445                                  cd->name, md->name, pd->name);
1446                          }
1447              
1448                          if (!(pd->flags & MI_FLAG_OUT))
1449                          {
1450                              err(ID_STREAM_QUALIFIER_ON_NON_OUTPUT, 
1451                                  "'Stream' qualifiers may only appear on output parameters: "
1452                                  "%s.%s(): %s",
1453                                  cd->name, md->name, pd->name);
1454                          }
1455                          continue;
1456                      }
1457              
1458                      // Reject properties named "MIReturn".
1459                      if (Strcasecmp(pd->name, "MIReturn") == 0)
1460                      {
1461                          err(ID_RESERVED_PARAMETER_NAME, 
1462                              "reserved parameter name: %s.%s(): %s", cd->name, md->name, 
1463                              pd->name);
1464 mike     1.1         }
1465              
1466                      GenSingleParameter(os,pd);
1467                  }
1468              }
1469              
1470              
1471              //==============================================================================
1472              //
1473              // GenParametersStruct()
1474              //
1475              //     This function generates the parameters structure, which holds the 
1476              //     extrinsic method parameters that are passed to an extrinsic method 
1477              //     provider stub. The return value is also defined in the structure whose
1478              //     field name is "MIReturn".
1479              //
1480              //==============================================================================
1481              
1482              static void GenParametersStruct(
1483                  FILE* os,
1484                  const MI_ClassDecl* cd, 
1485 mike     1.1     const MI_MethodDecl* md)
1486              {
1487                  const string alias = AliasOf(cd->name);
1488              
1489                  // Put comment box for the parameter structure name.
1490                  const string str = alias + "." + md->name +  "()";
1491                  PutCommentBox(os, str);
1492                  nl(os);
1493              
1494                  // Put method structure definition.
1495                  putl(os, "typedef struct _%s_%s", alias.c_str(), md->name);
1496                  putl(os, "{");
1497                  putl(os, "    MI_Instance __instance;");
1498              
1499                  {
1500                      MI_ParameterDecl pd;
1501                      memset(&pd, 0, sizeof(pd));
1502                      pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT;
1503                      pd.name = (char*)"MIReturn";
1504                      pd.type = md->returnType;
1505                      pd.offset = sizeof(MI_Instance);
1506 mike     1.1         pd.numQualifiers = md->numQualifiers;
1507                      pd.qualifiers = md->qualifiers;
1508                      GenSingleParameter(os,&pd);
1509                  }
1510                  GenParameters(os, cd, md);
1511                  putl(os, "}");
1512                  putl(os, "%s_%s;", alias.c_str(), md->name);
1513                  nl(os);
1514              }
1515              
1516              //==============================================================================
1517              //
1518              // GenSetter()
1519              //
1520              //     This function generates the 'setter' convenience functions for the 
1521              //     given class property or method parameter.
1522              //
1523              //==============================================================================
1524              
1525              static void GenSetter(
1526                  FILE* os, 
1527 mike     1.1     const MI_ClassDecl* cd,
1528                  const MI_MethodDecl* md,
1529                  const MI_ParameterDecl* pd)
1530              {
1531                  const string alias = AliasOf(cd->name);
1532                  string r,r_ptr;
1533                  MI_Uint32 index = (MI_Uint32)-1;
1534              
1535                  // Form the structure prefix (<ALIAS> for classes, <ALIAS><METH> for
1536                  // methods.
1537                  string prefix = alias;
1538              
1539                  if (md)
1540                  {
1541                      prefix += "_";
1542                      prefix += md->name;
1543                  }
1544              
1545                  // Find index of this property.
1546                  if (md)
1547                  {
1548 mike     1.1         if (strcmp(pd->name, "MIReturn") == 0)
1549                      {
1550                          index = 0;
1551                      }
1552                      else
1553                      {
1554                          for (MI_Uint32 i = 0; i < md->numParameters; i++)
1555                          {
1556                              if (md->parameters[i] == pd)
1557                              {
1558                                  index = i;
1559                                  break;
1560                              }
1561                          }
1562              
1563                          // Increment parameter index to make room for insertion of
1564                          // the "MIReturn" pseudo-parameter.
1565                          index++;
1566                      }
1567                  }
1568                  else
1569 mike     1.1     {
1570                      for (MI_Uint32 i = 0; i < cd->numProperties; i++)
1571                      {
1572                          if (cd->properties[i] == (MI_PropertyDecl*)pd)
1573                          {
1574                              index = i;
1575                              break;
1576                          }
1577                      }
1578                  }
1579              
1580                  if (index == (MI_Uint32)-1)
1581                      err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__);
1582              
1583                  // Generate *_Set_* and *_SetPtr_* functions.
1584              
1585                  if (pd->type & MI_ARRAY_BIT)
1586                  {
1587                      const char T[] =
1588                          "MI_INLINE MI_Result MI_CALL <PREFIX><SET><PROP>(\n"
1589                          "    <PREFIX>* self,\n"
1590 mike     1.1             "    const <TYPEEXPR>* data,\n"
1591                          "    MI_Uint32 size)\n"
1592                          "{\n"
1593                          "    MI_Array arr;\n"
1594                          "    arr.data = (void*)data;\n"
1595                          "    arr.size = size;\n"
1596                          "    return self->__instance.ft->SetElementAt(\n"
1597                          "        (MI_Instance*)&self->__instance,\n"
1598                          "        <INDEX>,\n"
1599                          "        (MI_Value*)&arr,\n"
1600                          "        <TYPE>,\n"
1601                          "        <COPY_FLAG>);\n"
1602                          "}\n"
1603                          "\n";
1604              
1605                      r = T;
1606              
1607                      r = sub(r, "<PREFIX>", prefix);
1608                      r = sub(r, "<PROP>", pd->name);
1609                      r = subu(r, "<INDEX>", index);
1610              
1611 mike     1.1         if (pd->type == MI_REFERENCEA)
1612                          r = sub(r, "<TYPEEXPR>", AliasOf(pd->className) + "* const");
1613                      else if (pd->type == MI_STRINGA && IsPropertyRefOrInstance(pd) && !GetPropertyClassname(pd).empty())
1614                      {
1615                          r = sub(r, "<TYPEEXPR>", AliasOf(GetPropertyClassname(pd)) + string(" * const "));
1616                          r = sub(r, "<TYPE>", "MI_INSTANCEA");
1617                      }
1618                      else if (pd->type == MI_STRINGA && IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty())
1619                      {
1620                          r = sub(r, "<TYPEEXPR>", "MI_Instance * const ");
1621                          r = sub(r, "<TYPE>", "MI_INSTANCEA");
1622                      }
1623                      else if (pd->type == MI_STRINGA)
1624                          r = sub(r, "<TYPEEXPR>", "MI_Char*");
1625                      else
1626                          r = sub(r, "<TYPEEXPR>", FullTypeNameOf(pd->type));
1627              
1628                      r = sub(r, "<TYPE>", MakeType(pd->type));
1629              
1630                      r_ptr = r;
1631                      // non-copying version has to be created from initial template
1632 mike     1.1         // otherwise name conflict is possible if function name is 'Set'
1633                      r = sub(r, "<SET>", "_Set_");
1634                      r = sub(r, "<COPY_FLAG>", "0");
1635                      r_ptr = sub(r_ptr, "<SET>", "_SetPtr_");
1636                      r_ptr = sub(r_ptr, "<COPY_FLAG>", "MI_FLAG_BORROW");
1637                      puts(os, r);
1638                      puts(os, r_ptr);
1639                  }
1640                  else if (IsPropertyRefOrInstance(pd))
1641                  {
1642                      const char T[] =
1643                          "MI_INLINE MI_Result MI_CALL <PREFIX><SET><PROP>(\n"
1644                          "    <PREFIX>* self,\n"
1645                          "    const <REFCLASSNAME>* x)\n"
1646                          "{\n"
1647                          "    return self->__instance.ft->SetElementAt(\n"
1648                          "        (MI_Instance*)&self->__instance,\n"
1649                          "        <INDEX>,\n"
1650                          "        (MI_Value*)&x,\n"
1651                          "        <TYPE>,\n"
1652                          "        <COPY_FLAG>);\n"
1653 mike     1.1             "}\n"
1654                          "\n";
1655              
1656                      r = T;
1657                      r = sub(r, "<PREFIX>", prefix);
1658                      r = sub(r, "<PROP>", pd->name);
1659                      r = subu(r, "<INDEX>", index);
1660                      r = sub(r, "<TYPE>", pd->type == MI_REFERENCE ? "MI_REFERENCE" : "MI_INSTANCE");
1661              
1662                      if (!GetPropertyClassname(pd).empty())
1663                          r = sub(r, "<REFCLASSNAME>", AliasOf(GetPropertyClassname(pd)));
1664                      else
1665                          r = sub(r, "<REFCLASSNAME>", "MI_Instance");
1666              
1667                      r_ptr = r;
1668                      // non-copying version has to be created from initial template
1669                      // otherwise name conflict is possible if function name is 'Set'
1670                      r = sub(r, "<SET>", "_Set_");
1671                      r = sub(r, "<COPY_FLAG>", "0");
1672                      r_ptr = sub(r_ptr, "<SET>", "_SetPtr_");
1673                      r_ptr = sub(r_ptr, "<COPY_FLAG>", "MI_FLAG_BORROW");
1674 mike     1.1         puts(os, r);
1675                      puts(os, r_ptr);
1676                  }
1677                  else if (pd->type == MI_STRING)
1678                  {
1679                      const char T[] =
1680                          "MI_INLINE MI_Result MI_CALL <PREFIX><SET><PROP>(\n"
1681                          "    <PREFIX>* self,\n"
1682                          "    const MI_Char* str)\n"
1683                          "{\n"
1684                          "    return self->__instance.ft->SetElementAt(\n"
1685                          "        (MI_Instance*)&self->__instance,\n"
1686                          "        <INDEX>,\n"
1687                          "        (MI_Value*)&str,\n"
1688                          "        MI_STRING,\n"
1689                          "        <COPY_FLAG>);\n"
1690                          "}\n"
1691                          "\n";
1692              
1693                      r = T;
1694                      r = sub(r, "<PREFIX>", prefix);
1695 mike     1.1         r = sub(r, "<PROP>", pd->name);
1696                      r = subu(r, "<INDEX>", index);
1697              
1698                      r_ptr = r;
1699                      // non-copying version has to be created from initial template
1700                      // otherwise name conflict is possible if function name is 'Set'
1701                      r = sub(r, "<SET>", "_Set_");
1702                      r = sub(r, "<COPY_FLAG>", "0");
1703                      r_ptr = sub(r_ptr, "<SET>", "_SetPtr_");
1704                      r_ptr = sub(r_ptr, "<COPY_FLAG>", "MI_FLAG_BORROW");
1705                      puts(os, r);
1706                      puts(os, r_ptr);
1707                  }
1708                  else
1709                  {
1710                      const char T[] =
1711                          "MI_INLINE MI_Result MI_CALL <PREFIX>_Set_<PROP>(\n"
1712                          "    <PREFIX>* self,\n"
1713                          "    MI_<TYPENAME> x)\n"
1714                          "{\n"
1715                          "    ((MI_<TYPENAME>Field*)&self-><PROP>)->value = x;\n"
1716 mike     1.1             "    ((MI_<TYPENAME>Field*)&self-><PROP>)->exists = 1;\n"
1717                          "    return MI_RESULT_OK;\n"
1718                          "}\n"
1719                          "\n";
1720              
1721                      r = T;
1722                      r = sub(r, "<PREFIX>", prefix);
1723                      r = sub(r, "<PROP>", pd->name);
1724                      r = sub(r, "<TYPENAME>", TypeNameOf(pd->type));
1725                      puts(os, r);
1726                  }
1727              
1728                  // Generate *_Clear_* function.
1729              
1730                  if ((pd->type & MI_ARRAY_BIT) != 0 || 
1731                      pd->type == MI_STRING || 
1732                      pd->type == MI_REFERENCE ||
1733                      pd->type == MI_INSTANCE)
1734                  {
1735                      const char T[] =
1736                          "MI_INLINE MI_Result MI_CALL <PREFIX>_Clear_<PROP>(\n"
1737 mike     1.1             "    <PREFIX>* self)\n"
1738                          "{\n"
1739                          "    return self->__instance.ft->ClearElementAt(\n"
1740                          "        (MI_Instance*)&self->__instance,\n"
1741                          "        <INDEX>);\n"
1742                          "}\n"
1743                          "\n";
1744              
1745                      r = T;
1746                      r = sub(r, "<PREFIX>", prefix);
1747                      r = sub(r, "<PROP>", pd->name);
1748                      r = subu(r, "<INDEX>", index);
1749                      puts(os, r);
1750                  }
1751                  else
1752                  {
1753                      const char T[] =
1754                          "MI_INLINE MI_Result MI_CALL <PREFIX>_Clear_<PROP>(\n"
1755                          "    <PREFIX>* self)\n"
1756                          "{\n"
1757                          "    memset((void*)&self-><PROP>, 0, sizeof(self-><PROP>));\n"
1758 mike     1.1             "    return MI_RESULT_OK;\n"
1759                          "}\n"
1760                          "\n";
1761              
1762                      r = T;
1763                      r = sub(r, "<PREFIX>", prefix);
1764                      r = sub(r, "<PROP>", pd->name);
1765                      puts(os, r);
1766                  }
1767              
1768              #if 0
1769                  // Generate function to obtain the flags for this property:
1770                  {
1771                      const char T[] =
1772                          "MI_INLINE MI_Result MI_CALL <PREFIX>_GetFlags_<PROP>(\n"
1773                          "    const <PREFIX>* self,\n"
1774                          "    MI_Uint32* flags)\n"
1775                          "{\n"
1776                          "    return self->__instance.ft->GetElementAt(&self->__instance,\n"
1777                          "        <INDEX>, NULL, NULL, NULL, flags);\n"
1778                          "}\n"
1779 mike     1.1             "\n";
1780              
1781                      r = T;
1782                      r = sub(r, "<PREFIX>", prefix);
1783                      r = sub(r, "<PROP>", pd->name);
1784                      r = subu(r, "<INDEX>", index);
1785                      puts(os, r);
1786                  }
1787              #endif
1788              }
1789              
1790              //==============================================================================
1791              //
1792              // GenInstanceFunctions()
1793              //
1794              //     This function generates the 'initInstance' convenience function for the 
1795              //     given class. 
1796              //
1797              //==============================================================================
1798              
1799              static void GenInstanceFunctions(
1800 mike     1.1     FILE* os, 
1801                  const MI_ClassDecl* cd)
1802              {
1803                  const string alias = AliasOf(cd->name);
1804              
1805                  const char T[] =
1806                      "MI_INLINE MI_Result MI_CALL <ALIAS>_Construct(\n"
1807                      "    <ALIAS>* self,\n"
1808                      "    MI_Context* context)\n"
1809                      "{\n"
1810                      "    return MI_ConstructInstance(context, &<ALIAS>_rtti,\n"
1811                      "        (MI_Instance*)&self->__instance);\n"
1812                      "}\n"
1813                      "\n"
1814                      "MI_INLINE MI_Result MI_CALL <ALIAS>_Clone(\n"
1815                      "    const <ALIAS>* self,\n"
1816                      "    <ALIAS>** newInstance)\n"
1817                      "{\n"
1818                      "    return MI_Instance_Clone(\n"
1819                      "        &self->__instance, (MI_Instance**)newInstance);\n"
1820                      "}\n"
1821 mike     1.1         "\n"
1822                      "MI_INLINE MI_Boolean MI_CALL <ALIAS>_IsA(\n"
1823                      "    const MI_Instance* self)\n"
1824                      "{\n"
1825                      "    MI_Boolean res = MI_FALSE;\n"
1826                      "    return MI_Instance_IsA(self, &<ALIAS>_rtti, &res) == MI_RESULT_OK && res;\n"
1827                      "}\n"
1828                      "\n"
1829                      "MI_INLINE MI_Result MI_CALL <ALIAS>_Destruct(<ALIAS>* self)\n"
1830                      "{\n"
1831                      "    return MI_Instance_Destruct(&self->__instance);\n"
1832                      "}\n"
1833                      "\n"
1834                      "MI_INLINE MI_Result MI_CALL <ALIAS>_Delete(<ALIAS>* self)\n"
1835                      "{\n"
1836                      "    return MI_Instance_Delete(&self->__instance);\n"
1837                      "}\n"
1838 krisbash 1.5         "\n";
1839              
1840                  string r = T;
1841                  if (cd->flags & MI_FLAG_INDICATION)
1842                  {
1843                      r += "MI_INLINE MI_Result MI_CALL <ALIAS>_Post(\n"
1844                      "    const <ALIAS>* self,\n"
1845                      "    MI_Context* context,\n"
1846                      "    MI_Uint32 subscriptionIDCount,\n"
1847                      "    const MI_Char* bookmark)\n"
1848                      "{\n"
1849                      "    return MI_Context_PostIndication(context, &self->__instance, subscriptionIDCount, bookmark);\n"
1850                      "}\n"
1851                      "\n";
1852                  }
1853                  else
1854                  {
1855                      r += "MI_INLINE MI_Result MI_CALL <ALIAS>_Post(\n"
1856 mike     1.1         "    const <ALIAS>* self,\n"
1857                      "    MI_Context* context)\n"
1858                      "{\n"
1859                      "    return MI_PostInstance(context, &self->__instance);\n"
1860                      "}\n"
1861                      "\n";
1862 krisbash 1.5     }
1863 mike     1.1     r = sub(r, "<ALIAS>", alias);
1864                  puts(os, r);
1865              }
1866              
1867              //==============================================================================
1868              //
1869              // GenMethodFunctions()
1870              //
1871              //     This function generates convenience functions for the given method.
1872              //
1873              //==============================================================================
1874              
1875              static void GenMethodFunctions(
1876                  FILE* os, 
1877                  const MI_ClassDecl* cd,
1878                  const MI_MethodDecl* md)
1879              {
1880                  const string alias = AliasOf(cd->name);
1881              
1882                  const char T[] =
1883                  "MI_EXTERN_C MI_CONST MI_MethodDecl <ALIAS>_<METH>_rtti;\n"
1884 mike     1.1     "\n"
1885                  "MI_INLINE MI_Result MI_CALL <ALIAS>_<METH>_Construct(\n"
1886                  "    <ALIAS>_<METH>* self,\n"
1887                  "    MI_Context* context)\n"
1888                  "{\n"
1889                  "    return MI_ConstructParameters(context, &<ALIAS>_<METH>_rtti,\n"
1890                  "        (MI_Instance*)&self->__instance);\n"
1891                  "}\n"
1892                  "\n"
1893                  "MI_INLINE MI_Result MI_CALL <ALIAS>_<METH>_Clone(\n"
1894                  "    const <ALIAS>_<METH>* self,\n"
1895                  "    <ALIAS>_<METH>** newInstance)\n"
1896                  "{\n"
1897                  "    return MI_Instance_Clone(\n"
1898                  "        &self->__instance, (MI_Instance**)newInstance);\n"
1899                  "}\n"
1900                  "\n"
1901                  "MI_INLINE MI_Result MI_CALL <ALIAS>_<METH>_Destruct(\n"
1902                  "    <ALIAS>_<METH>* self)\n"
1903                  "{\n"
1904                  "    return MI_Instance_Destruct(&self->__instance);\n"
1905 mike     1.1     "}\n"
1906                  "\n"
1907                  "MI_INLINE MI_Result MI_CALL <ALIAS>_<METH>_Delete(\n"
1908                  "    <ALIAS>_<METH>* self)\n"
1909                  "{\n"
1910                  "    return MI_Instance_Delete(&self->__instance);\n"
1911                  "}\n"
1912                  "\n"
1913                  "MI_INLINE MI_Result MI_CALL <ALIAS>_<METH>_Post(\n"
1914                  "    const <ALIAS>_<METH>* self,\n"
1915                  "    MI_Context* context)\n"
1916                  "{\n"
1917                  "    return MI_PostInstance(context, &self->__instance);\n"
1918                  "}\n"
1919                  "\n";
1920              
1921                  string r = T;
1922                  r = sub(r, "<ALIAS>", alias);
1923                  r = sub(r, "<METH>", md->name);
1924                  puts(os, r);
1925              }
1926 mike     1.1 
1927              //==============================================================================
1928              //
1929              // FindDirectDependencies
1930              //
1931              //     Find classes that this class depends (via superclasses and references).
1932              //
1933              //==============================================================================
1934              
1935              static void FindDirectDependencies(
1936                  const MI_ClassDecl* cd, 
1937                  vector<string>& deps)
1938              {
1939                  // Find super classes.
1940                  if (cd->superClass)
1941                      deps.push_back(cd->superClass);
1942              
1943                  // Find property reference dependencies.
1944                  for (MI_Uint32 i = 0; i < cd->numProperties; i++)
1945                  {
1946                      MI_PropertyDecl* pd = cd->properties[i];
1947 mike     1.1 
1948                      if (IsPropertyRefOrInstance(pd))
1949                      {
1950                          string cn = GetPropertyClassname(pd);
1951              
1952                          if (!cn.empty() && !Contains(deps, cn))
1953                              deps.push_back(cn);
1954                      }
1955                  }
1956              
1957                  // Find parameter reference dependencies.
1958                  for (MI_Uint32 i = 0; i < cd->numMethods; i++)
1959                  {
1960                      MI_MethodDecl* md = cd->methods[i];
1961              
1962                      // check return type
1963                      {
1964                          MI_ParameterDecl pd;
1965                          memset(&pd, 0, sizeof(pd));
1966                          pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT;
1967                          pd.name = (char*)"MIReturn";
1968 mike     1.1             pd.type = md->returnType;
1969                          pd.offset = sizeof(MI_Instance);
1970                          pd.numQualifiers = md->numQualifiers;
1971                          pd.qualifiers = md->qualifiers;
1972                          
1973                          if (IsPropertyRefOrInstance(&pd))
1974                          {
1975                              string cn = GetPropertyClassname(&pd);
1976              
1977                              if (!cn.empty() && !Contains(deps, cn))
1978                                  deps.push_back(cn);
1979                          }
1980                      }
1981              
1982                      for (MI_Uint32 j = 0; j < md->numParameters; j++)
1983                      {
1984                          MI_ParameterDecl* pd = md->parameters[j];
1985              
1986                          if (IsPropertyRefOrInstance(pd))
1987                          {
1988                              string cn = GetPropertyClassname(pd);
1989 mike     1.1 
1990                              if (!cn.empty() && !Contains(deps, cn))
1991                                  deps.push_back(cn);
1992                          }
1993                      }
1994                  }
1995              }
1996              
1997              //==============================================================================
1998              //
1999              // PutCppPropertyAccessor
2000              //
2001              //     Generate inline functions to access a single property
2002              //
2003              //==============================================================================
2004              template< typename PropertyDeclType>
2005              void PutCppPropertyAccessor(
2006                  FILE* os,
2007                  const PropertyDeclType* pd,
2008                  const string& alias)
2009              {
2010 mike     1.1     const char T[] =
2011                      "    //\n"
2012                      "    // =ALIAS=_Class.=NAME=\n"
2013                      "    //\n"
2014                      "    \n"
2015                      "    const Field<=TYPE=>& =NAME=() const\n"
2016                      "    {\n"
2017                      "        const size_t n = offsetof(Self, =NAME=);\n"
2018                      "        return GetField<=TYPE=>(n);\n"
2019                      "    }\n"
2020                      "    \n"
2021                      "    void =NAME=(const Field<=TYPE=>& x)\n"
2022                      "    {\n"
2023                      "        const size_t n = offsetof(Self, =NAME=);\n"
2024                      "        GetField<=TYPE=>(n) = x;\n"
2025                      "    }\n"
2026                      "    \n"
2027                      "    const =TYPE=& =NAME=_value() const\n"
2028                      "    {\n"
2029                      "        const size_t n = offsetof(Self, =NAME=);\n"
2030                      "        return GetField<=TYPE=>(n).value;\n"
2031 mike     1.1         "    }\n"
2032                      "    \n"
2033                      "    void =NAME=_value(const =TYPE=& x)\n"
2034                      "    {\n"
2035                      "        const size_t n = offsetof(Self, =NAME=);\n"
2036                      "        GetField<=TYPE=>(n).Set(x);\n"
2037                      "    }\n"
2038                      "    \n"
2039                      "    bool =NAME=_exists() const\n"
2040                      "    {\n"
2041                      "        const size_t n = offsetof(Self, =NAME=);\n"
2042                      "        return GetField<=TYPE=>(n).exists ? true : false;\n"
2043                      "    }\n"
2044                      "    \n"
2045                      "    void =NAME=_clear()\n"
2046                      "    {\n"
2047                      "        const size_t n = offsetof(Self, =NAME=);\n"
2048                      "        GetField<=TYPE=>(n).Clear();\n"
2049                      "    }\n";
2050              
2051                  string r = sub(T, "=ALIAS=", alias);
2052 mike     1.1 
2053                  if (IsPropertyRefOrInstance<PropertyDeclType>(pd) && 
2054                      !GetPropertyClassname<PropertyDeclType>(pd).empty())
2055                  {
2056                      const string al = AliasOf(GetPropertyClassname<PropertyDeclType>(pd));
2057              
2058                      if (pd->type & MI_ARRAY_BIT)
2059                      {
2060                          r = sub(r, "=TYPE=", al + "_ClassA");
2061                      }
2062                      else
2063                      {
2064                          r = sub(r, "=TYPE=", al + "_Class");
2065                      }
2066                  }
2067                  else if (IsPropertyRefOrInstance<PropertyDeclType>(pd) && 
2068                      GetPropertyClassname<PropertyDeclType>(pd).empty())
2069                  {   // embedded object
2070                      const string al = AliasOf(GetPropertyClassname<PropertyDeclType>(pd));
2071              
2072                      if (pd->type & MI_ARRAY_BIT)
2073 mike     1.1             r = sub(r, "=TYPE=", "InstanceA");
2074                      else
2075                          r = sub(r, "=TYPE=", "Instance");
2076                  }
2077                  else if (pd->type & MI_ARRAY_BIT)
2078                  {
2079                      r = sub(r, "=TYPE=", string(CppTypeNameOf(pd->type)) + "A");
2080                  }
2081                  else
2082                  {
2083                      r = sub(r, "=TYPE=", CppTypeNameOf(pd->type));
2084                  }
2085              
2086                  r = sub(r, "=NAME=", pd->name);
2087              
2088                  puts(os, r);
2089              }
2090              
2091              //==============================================================================
2092              //
2093              // getReturnType
2094 mike     1.1 //
2095              //     returns 'return-type' for funciton declaration; for instances return false
2096              //
2097              //==============================================================================
2098              template< typename ClassDeclType, typename PropertyDeclType>
2099              bool getReturnType(const ClassDeclType* cd, MI_Uint32& type);
2100              
2101              template<>
2102              bool getReturnType<MI_ClassDecl,_MI_PropertyDecl>(
2103                  const MI_ClassDecl* , 
2104                  MI_Uint32& )
2105              {
2106                  return false;
2107              }
2108              
2109              template<>
2110              bool getReturnType<MI_MethodDecl,_MI_ParameterDecl>(
2111                  const MI_MethodDecl* cd, 
2112                  MI_Uint32& type)
2113              {
2114                  type = cd->returnType;
2115 mike     1.1     return true;
2116              }
2117              
2118              //==============================================================================
2119              //
2120              // isPropertyLocal
2121              //
2122              //     checks if rpoerty is local
2123              //
2124              //==============================================================================
2125              template< typename ClassDeclType, typename PropertyDeclType>
2126              bool isPropertyLocal(const ClassDeclType* , const PropertyDeclType* );
2127              
2128              template<>
2129              bool isPropertyLocal<MI_ClassDecl,_MI_PropertyDecl>(
2130                  const MI_ClassDecl* cd, 
2131                  const _MI_PropertyDecl* pd)
2132              {
2133                  return Strcasecmp(cd->name, pd->origin) == 0;
2134              }
2135              
2136 mike     1.1 template<>
2137              bool isPropertyLocal<MI_MethodDecl,_MI_ParameterDecl>(
2138                  const MI_MethodDecl*, 
2139                  const _MI_ParameterDecl*)
2140              {
2141                  return true;
2142              }
2143              
2144              //==============================================================================
2145              //
2146              // HashKeys()
2147              //
2148              //     Return true if the given class declaration has any key properties.
2149              //
2150              //==============================================================================
2151              
2152              static bool HasKeys(const MI_ClassDecl* cd)
2153              {
2154                  for (MI_Uint32 i = 0; i < cd->numProperties; i++)
2155                  {
2156                      if (cd->properties[i]->flags & MI_FLAG_KEY)
2157 mike     1.1             return true;
2158                  }
2159              
2160                  // No keys found!
2161                  return false;
2162              }
2163              
2164              //==============================================================================
2165              //
2166              // GenCppPropertiesAccessors
2167              //
2168              //     Generate C++ class property accessors funciotns
2169              //
2170              //==============================================================================
2171              template< typename ClassDeclType, typename PropertyDeclType>
2172              void GenCppPropertiesAccessors(
2173                  FILE* os,
2174                  const ClassDeclType* cd,
2175                  const string& alias,
2176                  size_t numProperties,
2177                  PropertyDeclType** const properties )
2178 mike     1.1 {
2179                  // Print the local properties of this class.
2180                  {
2181                      // put MIReturn if it's a method
2182                      MI_Uint32 type = 0;
2183                      if (getReturnType<ClassDeclType, PropertyDeclType>(cd,type))
2184                      {
2185                          MI_ParameterDecl pd;
2186                          memset(&pd, 0, sizeof(pd));
2187                          pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT;
2188                          pd.name = (char*)"MIReturn";
2189                          pd.type = type;
2190                          pd.offset = sizeof(MI_Instance);
2191                          pd.numQualifiers = cd->numQualifiers;
2192                          pd.qualifiers = cd->qualifiers;
2193              
2194                          PutCppPropertyAccessor<MI_ParameterDecl>(os,&pd,alias);
2195              
2196                          if (numProperties)
2197                              nl(os);
2198                      }
2199 mike     1.1     }
2200              
2201                  for (size_t i = 0; i < numProperties; i++)
2202                  {
2203                      const PropertyDeclType* pd = properties[i];
2204              
2205                      // Skip non-local properties:
2206                      if (!isPropertyLocal(cd,pd))
2207                          continue;
2208              
2209                      // Skip stream parameters:
2210                      if (pd->flags & MI_FLAG_STREAM)
2211                          continue;
2212              
2213                      // generate skeleton
2214                      PutCppPropertyAccessor<PropertyDeclType>(os,pd,alias);
2215              
2216                      if (i +1 != numProperties)
2217                          nl(os);
2218                  }
2219              }
2220 mike     1.1 
2221              //==============================================================================
2222              //
2223              // GenCppClassDeclaration
2224              //
2225              //     Generate C++ class
2226              //
2227              //==============================================================================
2228              template< typename ClassDeclType, typename PropertyDeclType>
2229              void GenCppClassDeclaration(
2230                  FILE* os,
2231                  const ClassDeclType* cd,
2232                  const string& alias,
2233                  const char* superClass,
2234                  size_t numProperties,
2235                  PropertyDeclType** const properties )
2236              {
2237                  ////////////////////////////////////////
2238                  // class definition
2239                  {
2240                      const char T[] =
2241 mike     1.1         "class <ALIAS>_Class : public <BASE>\n"
2242                      "{\n"
2243                      "public:\n"
2244                      "    \n"
2245                      "    typedef <ALIAS> Self;\n"
2246                      "    \n"
2247                      "    <ALIAS>_Class() :\n"
2248                      "        <BASE>(&<ALIAS>_rtti)\n"
2249                      "    {\n"
2250                      "    }\n"
2251                      "    \n"
2252                      "    <ALIAS>_Class(\n"
2253                      "        const <ALIAS>* instanceName,\n"
2254                      "        bool keysOnly) :\n"
2255                      "        <BASE>(\n"
2256                      "            &<ALIAS>_rtti,\n"
2257                      "            &instanceName->__instance,\n"
2258                      "            keysOnly)\n"
2259                      "    {\n"
2260                      "    }\n"
2261                      "    \n"
2262 mike     1.1         "    <ALIAS>_Class(\n"
2263                      "        const MI_ClassDecl* clDecl,\n"
2264                      "        const MI_Instance* instance,\n"
2265                      "        bool keysOnly) :\n"
2266                      "        <BASE>(clDecl, instance, keysOnly)\n"
2267                      "    {\n"
2268                      "    }\n"
2269                      "    \n"
2270                      "    <ALIAS>_Class(\n"
2271                      "        const MI_ClassDecl* clDecl) :\n"
2272                      "        <BASE>(clDecl)\n"
2273                      "    {\n"
2274                      "    }\n"
2275                      "    \n"
2276                      "    <ALIAS>_Class& operator=(\n"
2277                      "        const <ALIAS>_Class& x)\n"
2278                      "    {\n"
2279                      "        CopyRef(x);\n"
2280                      "        return *this;\n"
2281                      "    }\n"
2282                      "    \n"
2283 mike     1.1         "    <ALIAS>_Class(\n"
2284                      "        const <ALIAS>_Class& x) :\n"
2285                      "        <BASE>(x)\n"
2286                      "    {\n"
2287                      "    }\n"
2288                      "\n";
2289                      const char S[] =
2290                      "    static const MI_ClassDecl* GetClassDecl()\n"
2291                      "    {\n"
2292                      "        return &<ALIAS>_rtti;\n"
2293                      "    }\n"
2294                      "\n";
2295              
2296                      string r = sub(T, "<ALIAS>", alias);
2297              
2298                      if (superClass)
2299                      {
2300                          string tmp = AliasOf(superClass) + "_Class";
2301                          r = sub(r, "<BASE>", tmp);
2302                      }
2303                      else
2304 mike     1.1         {
2305                          r = sub(r, "<BASE>", "Instance");
2306                      }
2307                      puts(os, r);
2308              
2309                      if (cd->flags & MI_FLAG_CLASS)
2310                      {
2311                          r = sub(S, "<ALIAS>", alias);
2312                          puts(os, r);
2313                      }
2314              
2315                  }
2316              
2317                  /// inline funciotns for property access
2318                  GenCppPropertiesAccessors<ClassDeclType,PropertyDeclType>(
2319                      os,cd,alias,numProperties,properties);
2320              
2321                  /// end class
2322                  {
2323                      const char T[] =
2324                          "};\n"
2325 mike     1.1             "\n"
2326                          "typedef Array<<ALIAS>_Class> <ALIAS>_ClassA;\n"
2327                          "\n"
2328                          ;
2329              
2330                      string r = sub(T, "<ALIAS>", alias);
2331                      puts(os, r);
2332                  }
2333              }
2334              
2335              //==============================================================================
2336              //
2337              // SubRoles()
2338              //
2339              //     Substitute <ROLE1>, <ROLE2>, <ALIAS1>, and <ALIAS2> with
2340              //     property names and classnames for the first and second references 
2341              //     (roles) in this class.
2342              //
2343              //==============================================================================
2344              
2345              static void SubRoles(const MI_ClassDecl* cd, string& r)
2346 mike     1.1 {
2347                  size_t role = 1;
2348              
2349                  for (size_t i = 0; i < cd->numProperties; i++)
2350                  {
2351                      const MI_PropertyDecl* pd = cd->properties[i];
2352              
2353                      if (pd->type == MI_REFERENCE)
2354                      {
2355                          if (role == 1)
2356                          {
2357                              r = sub(r, "<ROLE1>", pd->name);
2358                              r = sub(r, "<ALIAS1>", AliasOf(pd->className).c_str());
2359                              role++;
2360                          }
2361                          else if (role == 2)
2362                          {
2363                              r = sub(r, "<ROLE2>", pd->name);
2364                              r = sub(r, "<ALIAS2>", AliasOf(pd->className).c_str());
2365                              role++;
2366                          }
2367 mike     1.1             else if (role == 3)
2368                          {
2369                              err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, 
2370                                  __LINE__);
2371                          }
2372                      }
2373                  }
2374              }
2375              
2376              //==============================================================================
2377              //
2378              // GenCppClassProviderHeaderNewFile
2379              //
2380              //     Generate class provider declaration 
2381              //     used only to create a new file
2382              //
2383              //==============================================================================
2384              static void GenCppClassProviderHeaderNewFile(
2385                  FILE* os,
2386                  const MI_ClassDecl* cd)
2387              {
2388 mike     1.1     string alias = AliasOf(cd->name);
2389                  GenStatikGenLine(os);
2390              
2391                  // Prevent multiple inclusion.
2392                  putl(os, "#ifndef _%s_Class_Provider_h", alias.c_str());
2393                  putl(os, "#define _%s_Class_Provider_h", alias.c_str());
2394                  nl(os);
2395              
2396                  // Include instance class
2397                  putl(os, "#include \"%s.h\"", alias.c_str());
2398              
2399              
2400                  // standard starting part
2401                  putl(os, "#ifdef __cplusplus");
2402                  putl(os, "# include <micxx/micxx.h>");
2403                  putl(os, "# include \"module.h\"");
2404                  nl(os);
2405                  putl(os, "MI_BEGIN_NAMESPACE");
2406                  nl(os);
2407              
2408              
2409 mike     1.1     // Write the intrinsic provider function prototypes.
2410                  {
2411                      PutCommentBox(os, alias + " provider class declaration");
2412                      nl(os);
2413              
2414                      // Generate forward typedef for Self structure.
2415                      string extraDataMemebers;
2416                      
2417                      if (cd->flags & MI_FLAG_ASSOCIATION)
2418                      {
2419                          string r;
2420              
2421 krisbash 1.5             if (CanGenerateAssocRoles(cd))
2422 mike     1.1             {
2423 krisbash 1.5                 if (!s_options.association)
2424                              {
2425                                  r = ASSOCIATION_PROVIDER_CLASS_DECLARATION_ROLES;
2426                                  SubRoles(cd, r);
2427                              }
2428                              else
2429                                  r = ASSOCIATION_PROVIDER_CLASS_DECLARATION;
2430 mike     1.1             }
2431                          else
2432 krisbash 1.5                 errRefPropCount(cd->name);
2433 mike     1.1 
2434                          r = sub(r, "<ALIAS>", alias);
2435                          r = sub(r, "<DATA_MEMBERS>", extraDataMemebers);
2436                          puts(os, r);
2437                      }
2438                      else if (cd->flags & MI_FLAG_INDICATION)
2439                      {
2440                          string r = INDICATION_PROVIDER_CLASS_DECLARATION;
2441                          extraDataMemebers = "    MI_Context* m_IndicationsContext;\n";
2442                          r = sub(r, "<ALIAS>", alias);
2443                          r = sub(r, "<DATA_MEMBERS>", extraDataMemebers);
2444                          puts(os, r);
2445                      }
2446                      else
2447                      {
2448                          string r = INSTANCE_PROVIDER_CLASS_DECLARATION;
2449                          r = sub(r, "<ALIAS>", alias);
2450                          r = sub(r, "<DATA_MEMBERS>", extraDataMemebers);
2451                          puts(os, r);
2452                      }
2453                  }
2454 mike     1.1 
2455                  // Write the extrinsic provider function prototypes.
2456                  {
2457                      for (size_t i = 0; i < cd->numMethods; i++)
2458                      {
2459                          const MI_MethodDecl* md = cd->methods[i];
2460                          string r = sub(EXTRINSIC_METHOD_PROVIDER_CLASS_DECLARATION, 
2461                              "<ALIAS>", alias);
2462                          r = sub(r, "<METHOD>", md->name);
2463                          puts(os, r);
2464                      }
2465                  }
2466              
2467                  // close class declaration
2468                  putl(os, COMMON_PROVIDER_CLASS_DECLARATION_END);
2469                  putl(os,"};");
2470                  nl(os);
2471              
2472              
2473                  // end c++ specific part
2474                  putl(os, "MI_END_NAMESPACE");
2475 mike     1.1     nl(os);
2476                  putl(os, "#endif /* __cplusplus */");
2477                  nl(os);
2478                  putl(os, "#endif /* _%s_Class_Provider_h */", alias.c_str());
2479                  nl(os);
2480              }
2481              
2482              //==============================================================================
2483              //
2484              // GenCppClassProviderHeader
2485              //
2486              //     Generate class provider declaration 
2487              //     Support patching of methods
2488              //
2489              //==============================================================================
2490              static void GenCppClassProviderHeader(
2491                  const MI_ClassDecl* cd)
2492              {
2493                  string alias = AliasOf(cd->name);
2494              
2495                  // create/patch provider class declaration file.
2496 mike     1.1     const string path = ExpandPath(alias + "_Class_Provider.h");
2497                  bool append;
2498                  vector<char> data;
2499                  {
2500                      append = Exists(path.c_str());
2501              
2502                      if (append)
2503                      {
2504                          if (!Inhale(path.c_str(), data))
2505                          {
2506                              err(ID_FAILED_TO_READ_FILE, "failed to read file: %s", 
2507                                  path.c_str());
2508                          }
2509                      }
2510                      else
2511                      {
2512 krisbash 1.5             FILE* os = File_Open(path.c_str(), "w");
2513 mike     1.1 
2514                          if (!os)
2515                          {
2516                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
2517                                  path.c_str());
2518                          }
2519              
2520                          Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
2521                          GenCppClassProviderHeaderNewFile(os,cd);
2522                          fclose(os);
2523                          return;
2524                      }
2525                  }
2526              
2527              
2528                  // patch existing file
2529                  data.push_back(0);
2530                  string str_data = &data[0];
2531              
2532                  /* remove \r*/
2533                  str_data = sub(str_data, "\r", "");
2534 mike     1.1 
2535                  if (str_data.find(COMMON_PROVIDER_CLASS_DECLARATION_END) == string::npos)
2536                  {
2537                      err(ID_FAILED_TO_FIND_PATCH_MARKER,
2538                          "failed to find patch marker (%s) in file %s",
2539                          COMMON_PROVIDER_CLASS_DECLARATION_END,
2540                          path.c_str());
2541                  }
2542              
2543                  bool patched = false;
2544              
2545                  // Add Load/Unload functions if missing
2546                  if (str_data.find("void Unload(") == string::npos)
2547                  {
2548                      if (!patched)
2549                      {
2550                          Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str());
2551                          patched = true;
2552                      }
2553              
2554                      str_data = sub(str_data, COMMON_PROVIDER_CLASS_DECLARATION_END, 
2555 mike     1.1             COMMON_PROVIDER_LOAD_UNLOAD_DECLARATION  COMMON_PROVIDER_CLASS_DECLARATION_END);
2556                  }
2557              
2558                  // Generate extrinsic method declarations (only new one).
2559                  for (size_t i = 0; i < cd->numMethods; i++)
2560                  {
2561                      const MI_MethodDecl* md = cd->methods[i];
2562                      string r = sub(EXTRINSIC_METHOD_PROVIDER_CLASS_DECLARATION, "<ALIAS>", 
2563                          alias);
2564                      r = sub(r, "<METHOD>", md->name);
2565              
2566                      string name = string("Invoke_") + md->name;
2567              
2568                      // Skip methods already found in file.
2569                      if (str_data.find(name) != string::npos)
2570                          continue;
2571              
2572                      if (!patched)
2573                      {
2574                          Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str());
2575                          patched = true;
2576 mike     1.1         }
2577              
2578                      str_data = sub(str_data, COMMON_PROVIDER_CLASS_DECLARATION_END, 
2579                          r + COMMON_PROVIDER_CLASS_DECLARATION_END);
2580                  }
2581              
2582                  if (!patched)
2583                  {
2584                      Fprintf(s_stdout, ID_CHECKING, "Checking %s\n", path.c_str());
2585                  }
2586                  else
2587                  {
2588                      // Rewrite the file.
2589 krisbash 1.5         FILE* os = File_Open(path.c_str(), "w");
2590 mike     1.1 
2591                      if (!os)
2592                          err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s",path.c_str());
2593              
2594                      put(os, "%s", &str_data[0]);
2595              
2596                      fclose(os);
2597                  }
2598              }
2599              
2600              
2601              //==============================================================================
2602              //
2603              // GenCppClassHeader
2604              //
2605              //     Generate C++ part of the header file for the given MOF class. This part 
2606              //     contains the c++ wrapper class and provider class definition.
2607              //
2608              //==============================================================================
2609              static void GenCppClassHeader(
2610                  Parser& /*parser*/, 
2611 mike     1.1     const MI_ClassDecl* cd,
2612                  FILE* os
2613                  )
2614              {
2615                  string alias = AliasOf(cd->name);
2616              
2617                  // Comment box introducing C++ class definiti9on
2618                  {
2619                      string tmp = alias + "_Class";
2620                      PutCommentBox(os, tmp);
2621                      nl(os);
2622                  }
2623              
2624                  // standard starting part
2625                  putl(os, "#ifdef __cplusplus");
2626                  putl(os, "# include <micxx/micxx.h>");
2627                  nl(os);
2628                  putl(os, "MI_BEGIN_NAMESPACE");
2629                  nl(os);
2630              
2631              
2632 mike     1.1     // instance itself
2633                  GenCppClassDeclaration<MI_ClassDecl,_MI_PropertyDecl>(os, cd, alias, 
2634                      cd->superClass, cd->numProperties, cd->properties);
2635              
2636                  // gen parameters classes
2637                  // Put method definitions and setters for each method parameter.
2638                  for (size_t i = 0; !s_options.noProviders && i < cd->numMethods; i++)
2639                  {
2640                      const MI_MethodDecl* md = cd->methods[i];
2641              
2642                      string param_alias = alias + "_" + md->name;
2643              
2644                      if (Strcasecmp(cd->name, md->propagator) == 0 ||
2645                          providerClasses.find(cd->name) != providerClasses.end())
2646                      {
2647                          GenCppClassDeclaration(os, md, param_alias, 0, md->numParameters, 
2648                              md->parameters);
2649                      }
2650                  }
2651              
2652                  // provider class definition - if required
2653 mike     1.1     if (providerClasses.find(cd->name) != providerClasses.end() &&
2654                      !s_options.noProviders)
2655                  {
2656              
2657                      GenCppClassProviderHeader(cd);
2658                  }
2659              
2660                  // end c++ specific part
2661                  putl(os, "MI_END_NAMESPACE");
2662                  nl(os);
2663                  putl(os, "#endif /* __cplusplus */");
2664                  nl(os);
2665              }
2666              
2667              
2668              static void _PatchLoadSignature(
2669                  const string& alias, 
2670                  const string& path, 
2671                  vector<char>& data)
2672              {
2673                  /* special case: patch Load funciton signature */
2674 mike     1.1     string old_load = sub(OLD_PROVIDER_LOAD_PROTOTYPES, "<ALIAS>", alias);
2675              
2676                  data.push_back(0);
2677                  string str_data = &data[0];
2678              
2679                  /* remove \r*/
2680                  str_data = sub(str_data, "\r", "");
2681              
2682                  if (str_data.find(old_load) != string::npos)
2683                  {
2684                      string new_load = sub(NEW_PROVIDER_LOAD_PROTOTYPES, "<ALIAS>", alias);
2685              
2686                      str_data = sub(str_data, old_load, new_load);
2687              
2688                      // Rewrite the file.
2689                      {
2690 krisbash 1.5             FILE* os = File_Open(path.c_str(), "w");
2691 mike     1.1 
2692                          if (!os)
2693                          {
2694                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s",
2695                                  path.c_str());
2696                          }
2697              
2698                          Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str());
2699                          put(os, "%s", &str_data[0]);
2700              
2701                          fclose(os);
2702                      }
2703                  }
2704              }
2705              
2706              /* Patches old cpp skeletons with load/unload funcitons */
2707              static void _PatchLoadUnloadCPP(
2708                  const string& alias, 
2709                  const string& path, 
2710                  vector<char>& data)
2711              {
2712 mike     1.1     /* special case: check if Load/Unload are declared */
2713                  string old_load = sub("<ALIAS>_Class_Provider::Load(", "<ALIAS>", alias);
2714              
2715                  data.push_back(0);
2716                  string str_data = &data[0];
2717              
2718                  /* remove \r*/
2719                  str_data = sub(str_data, "\r", "");
2720              
2721                  if (str_data.find(old_load) == string::npos)
2722                  {
2723                      string new_load = sub(COMMON_PROVIDER_CLASS_LOAD_UNLOAD_CPP, "<ALIAS>", alias);
2724              
2725                      str_data += "MI_BEGIN_NAMESPACE\n";
2726                      str_data += new_load;
2727                      str_data += "MI_END_NAMESPACE\n";
2728              
2729                      // Rewrite the file.
2730                      {
2731 krisbash 1.5             FILE* os = File_Open(path.c_str(), "w");
2732 mike     1.1 
2733                          if (!os)
2734                          {
2735                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s",
2736                                  path.c_str());
2737                          }
2738              
2739                          Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str());
2740                          put(os, "%s", &str_data[0]);
2741              
2742                          fclose(os);
2743                      }
2744                  }
2745              }
2746              
2747              //==============================================================================
2748              //
2749              // GenCppClassSource
2750              //
2751              //     Generate the cpp source file for the given MOF class. This file contains the
2752              //     the provider function stubs.
2753 mike     1.1 //
2754              //==============================================================================
2755              
2756              static void GenCppClassSource(const MI_ClassDecl* cd)
2757              {
2758                  const string alias = AliasOf(cd->name);
2759              
2760                  // Open source file (refuse if it already exists).
2761                  bool append;
2762                  vector<char> data;
2763                  const string path = ExpandPath(alias + "_Class_Provider.cpp");
2764                  FILE* os = 0;
2765                  {
2766                      append = Exists(path.c_str());
2767              
2768                      if (append)
2769                      {
2770                          if (!Inhale(path.c_str(), data))
2771                          {
2772                              err(ID_FAILED_TO_READ_FILE, "failed to read file: %s", 
2773                                  path.c_str());
2774 mike     1.1             }
2775              
2776                          _PatchLoadUnloadCPP(alias, path, data);
2777              
2778 krisbash 1.5             os = File_Open(path.c_str(), "a");
2779 mike     1.1 
2780                          if (!os)
2781                          {
2782                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
2783                                  path.c_str());
2784                          }
2785                      }
2786                      else
2787                      {
2788 krisbash 1.5             os = File_Open(path.c_str(), "w");
2789 mike     1.1 
2790                          if (!os)
2791                          {
2792                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
2793                                  path.c_str());
2794                          }
2795              
2796                          GenStatikGenLine(os);
2797                          Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
2798                      }
2799                  }
2800              
2801                  // Include required headers.
2802                  if (!append)
2803                  {
2804                      putl(os, "#include <MI.h>");
2805                      putl(os, "#include \"%s_Class_Provider.h\"", alias.c_str());
2806                      nl(os);
2807                      putl(os, "MI_BEGIN_NAMESPACE");
2808                      nl(os);
2809                  }
2810 mike     1.1 
2811                  // spil out provider class implementation (stubs)
2812                  if (!append)
2813                  {
2814                      string r;
2815                      
2816                      if (cd->flags & MI_FLAG_ASSOCIATION)
2817                      {
2818 krisbash 1.5             if (CanGenerateAssocRoles(cd))
2819 mike     1.1             {
2820 krisbash 1.5                 if (!s_options.association)
2821                              {
2822                                  r = ASSOCIATION_PROVIDER_CLASS_STUBS_CPP_ROLES;
2823                                  SubRoles(cd, r);
2824                              }
2825                              else
2826                                  r = ASSOCIATION_PROVIDER_CLASS_STUBS_CPP;
2827 mike     1.1             }
2828                          else
2829 krisbash 1.5                 errRefPropCount(cd->name);
2830 mike     1.1         }
2831                      else if (cd->flags & MI_FLAG_INDICATION)
2832                          r = INDICATION_PROVIDER_CLASS_STUBS_CPP;
2833                      else
2834                          r = INSTANCE_PROVIDER_CLASS_STUBS_CPP;
2835              
2836                      r = sub(r, "<ALIAS>", alias);
2837                      puts(os, r);
2838                  }
2839              
2840                  // spil out provider extrinsic method stubs 
2841                  if (!append)
2842                  {
2843                      for (size_t i = 0; i < cd->numMethods; i++)
2844                      {
2845                          const MI_MethodDecl* md = cd->methods[i];
2846                          string r = sub(EXTRINSIC_METHOD_CLASS_STUB_CPP, "<ALIAS>", alias);
2847                          r = sub(r, "<METHOD>", md->name);
2848                          puts(os, r);
2849                      }
2850                  }
2851 mike     1.1 
2852                  // close namespace
2853                  if (!append)
2854                  {
2855                      nl(os);
2856                      putl(os, "MI_END_NAMESPACE");
2857                  }
2858              
2859              
2860                  // only if we are updating exisitng one
2861                  if (append)
2862                  {
2863                      bool patched = false;
2864              
2865                      // Generate extrinsic method stubs (not already found in file).
2866                      for (size_t i = 0; i < cd->numMethods; i++)
2867                      {
2868                          const MI_MethodDecl* md = cd->methods[i];
2869                          string r = sub(
2870                              "MI_BEGIN_NAMESPACE\n\n" EXTRINSIC_METHOD_CLASS_STUB_CPP "\nMI_END_NAMESPACE\n", "<ALIAS>", alias);
2871                          r = sub(r, "<METHOD>", md->name);
2872 mike     1.1 
2873                          string name = string("::Invoke_") + md->name;
2874              
2875                          // Skip methods already found in file.
2876              
2877                          if (strstr(&data[0], name.c_str()))
2878                              continue;
2879                          else
2880                          {
2881                              if (!patched)
2882                              {
2883                                  Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", 
2884                                      path.c_str());
2885                                  patched = true;
2886                              }
2887                              puts(os, r);
2888                          }
2889                      }
2890              
2891                      if (!patched)
2892                      {
2893 mike     1.1             Fprintf(s_stdout, ID_CHECKING, "Checking %s\n", path.c_str());
2894                      }
2895                  }
2896              
2897                  // Close file.
2898                  fclose(os);
2899              }
2900              
2901              //==============================================================================
2902              //
2903              // GenerateClassStub
2904              //
2905              //     Generate wrapper for provider class
2906              //
2907              //==============================================================================
2908              
2909              static void GenerateClassStub(FILE* os, const MI_ClassDecl* cd)
2910              {
2911                  const string alias = AliasOf(cd->name);
2912              
2913                  // Generate extrinsic method stubs.
2914 mike     1.1     {
2915                      if (cd->flags & MI_FLAG_ASSOCIATION)
2916                      {
2917                          string r;
2918              
2919 krisbash 1.5             if (CanGenerateAssocRoles(cd))
2920 mike     1.1             {
2921 krisbash 1.5                 if (!s_options.association)
2922                              {
2923                                  r = ASSOCIATION_PROVIDER_STUBS_CPP_ROLES;
2924                                  SubRoles(cd, r);
2925                              }
2926                              else
2927                                  r = ASSOCIATION_PROVIDER_STUBS_CPP;
2928 mike     1.1             }
2929                          else
2930 krisbash 1.5                 errRefPropCount(cd->name);
2931 mike     1.1 
2932                          r = sub(r, "<ALIAS>", alias);
2933                          puts(os, r);
2934                      }
2935                      else if (cd->flags & MI_FLAG_INDICATION)
2936                      {
2937                          string r = INDICATION_PROVIDER_STUBS_CPP;
2938                          r = sub(r, "<ALIAS>", alias);
2939                          puts(os, r);
2940                      }
2941                      else
2942                      {
2943                          if (HasKeys(cd))
2944                          {
2945                              string r = INSTANCE_PROVIDER_STUBS_CPP;
2946                              r = sub(r, "<ALIAS>", alias);
2947                              puts(os, r);
2948                          }
2949                          else 
2950                          {
2951                              string r = COMMON_PROVIDER_STUBS_CPP;
2952 mike     1.1                 r = sub(r, "<ALIAS>", alias);
2953                              puts(os, r);
2954                          }
2955                      }
2956                  }
2957              
2958                  // generate all extrinsic method stubs (if new one)
2959                  {
2960                      for (size_t i = 0; i < cd->numMethods; i++)
2961                      {
2962                          const MI_MethodDecl* md = cd->methods[i];
2963                          string r = sub(EXTRINSIC_METHOD_STUB_CPP, "<ALIAS>", alias);
2964                          r = sub(r, "<METHOD>", md->name);
2965                          puts(os, r);
2966                      }
2967              
2968                  }
2969              }
2970              
2971              //==============================================================================
2972              //
2973 mike     1.1 // GenClassHeader
2974              //
2975              //     Generate the header file for the given MOF class. This file contains the
2976              //     C structure definition, setter functions, parameter structures, and
2977              //     provider function prototypes.
2978              //
2979              //==============================================================================
2980              
2981              static void GenClassHeader(
2982                  Parser& parser, 
2983                  const MI_ClassDecl* cd,
2984                  set<string>& classIdentifiers)
2985              {
2986                  const string alias = AliasOf(cd->name);
2987              
2988                  // Refuse to generate same class more than once.
2989              
2990                  if (generated_headers.find(cd->name) != generated_headers.end())
2991                      return;
2992              
2993                  generated_headers.insert(cd->name);
2994 mike     1.1 
2995                  // Find direct dependencies of this class.
2996                  vector<string> deps;
2997                  FindDirectDependencies(cd, deps);
2998              
2999                  // Recurse on dependencies.
3000                  for (size_t i = 0; i < deps.size(); i++)
3001                  {
3002                      const MI_ClassDecl* tcd = parser.findClassDecl(deps[i].c_str());
3003              
3004                      if (!tcd)
3005                          err(ID_UNKNOWN_CLASS, "unknown class: %s", deps[i].c_str());
3006              
3007                      GenClassHeader(parser, tcd, classIdentifiers);
3008                  }
3009              
3010                  // Open class header file.
3011                  string path = ExpandPath(alias + ".h");
3012                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
3013              
3014 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
3015 mike     1.1     
3016                  if (!os)
3017                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
3018              
3019                  GenStatikGenLine(os);
3020              
3021                  // Put comment header.
3022                  PutCommentBox(os, WARNING);
3023              
3024                  // Prevent multiple inclusion.
3025                  putl(os, "#ifndef _%s_h", alias.c_str());
3026                  putl(os, "#define _%s_h", alias.c_str());
3027                  nl(os);
3028              
3029                  // Include <MI.h>
3030                  putl(os, "#include <MI.h>");
3031              
3032                  // Generate includes for direct dependencies.
3033                  for (size_t i = 0; i < deps.size(); i++)
3034                  {
3035                      string al = AliasOf(deps[i]);
3036 mike     1.1         putl(os, "#include \"%s.h\"", al.c_str());
3037                  }
3038              
3039                  nl(os);
3040              
3041                  // Put comment box for the class structure. List the key names for this
3042                  // class.
3043                  {
3044                      putl(os, "/*");
3045                      PutRule(os);
3046                      putl(os, "**");
3047                      putl(os, "** %s [%s]", alias.c_str(), cd->name);
3048                      putl(os, "**");
3049                      putl(os, "** Keys:");
3050              
3051                      for (size_t i = 0; i < cd->numProperties; i++)
3052                      {
3053                          const MI_PropertyDecl* pd = cd->properties[i];
3054              
3055                          if (pd->flags & MI_FLAG_KEY)
3056                              putl(os, "**    %s", pd->name);
3057 mike     1.1         }
3058              
3059                      putl(os, "**");
3060                      PutRule(os);
3061                      putl(os, "*/");
3062                      nl(os);
3063                  }
3064              
3065                  // Put class structure definition with all its properties.
3066                  if (cd->superClass)
3067                  {
3068                      putl(os, "typedef struct _%s /* extends %s */", 
3069                          alias.c_str(), cd->superClass);
3070                  }
3071                  else
3072                  {
3073                      putl(os, "typedef struct _%s", alias.c_str());
3074                  }
3075              
3076                  putl(os, "{");
3077                  putl(os, "    MI_Instance __instance;");
3078 mike     1.1     NameClassMap map;
3079                  GenProperties(os, parser, cd, cd, map);
3080                  putl(os, "}");
3081                  putl(os, "%s;", alias.c_str());
3082                  nl(os);
3083              
3084                  // Generate a reference of this type (if not an association or indication).
3085              #if 0
3086                  if (!(cd->flags & MI_FLAG_ASSOCIATION || cd->flags & MI_FLAG_INDICATION))
3087              #endif
3088                  // Associations can be used as endpoints in other associations.
3089                  {
3090                      {
3091                          const char T[] =
3092                              "typedef struct _<ALIAS>_Ref\n"
3093                              "{\n"
3094                              "    <ALIAS>* value;\n"
3095                              "    MI_Boolean exists;\n"
3096                              "    MI_Uint8 flags;\n"
3097                              "}\n"
3098                              "<ALIAS>_Ref;\n"
3099 mike     1.1                 "\n"
3100                              "typedef struct _<ALIAS>_ConstRef\n"
3101                              "{\n"
3102                              "    MI_CONST <ALIAS>* value;\n"
3103                              "    MI_Boolean exists;\n"
3104                              "    MI_Uint8 flags;\n"
3105                              "}\n"
3106                              "<ALIAS>_ConstRef;\n"
3107                              "\n";
3108              
3109                          string r = sub(T, "<ALIAS>", alias);
3110                          puts(os, r);
3111                      }
3112                      {
3113                          const char T[] =
3114                              "typedef struct _<ALIAS>_Array\n"
3115                              "{\n"
3116                              "    struct _<ALIAS>** data;\n"
3117                              "    MI_Uint32 size;\n"
3118                              "}\n"
3119                              "<ALIAS>_Array;\n"
3120 mike     1.1                 "\n"
3121                              "typedef struct _<ALIAS>_ConstArray\n"
3122                              "{\n"
3123                              "    struct _<ALIAS> MI_CONST* MI_CONST* data;\n"
3124                              "    MI_Uint32 size;\n"
3125                              "}\n"
3126                              "<ALIAS>_ConstArray;\n"
3127                              "\n"
3128                              "typedef struct _<ALIAS>_ArrayRef\n"
3129                              "{\n"
3130                              "    <ALIAS>_Array value;\n"
3131                              "    MI_Boolean exists;\n"
3132                              "    MI_Uint8 flags;\n"
3133                              "}\n"
3134                              "<ALIAS>_ArrayRef;\n"
3135                              "\n"
3136                              "typedef struct _<ALIAS>_ConstArrayRef\n"
3137                              "{\n"
3138                              "    <ALIAS>_ConstArray value;\n"
3139                              "    MI_Boolean exists;\n"
3140                              "    MI_Uint8 flags;\n"
3141 mike     1.1                 "}\n"
3142                              "<ALIAS>_ConstArrayRef;\n"
3143                              "\n";
3144              
3145                          string r = sub(T, "<ALIAS>", alias);
3146                          puts(os, r);
3147                      }
3148                  }
3149              
3150                  // Generate an external reference to the class RTTI instance.
3151                  if (s_options.cpp || !s_options.noProviders)
3152                  {
3153                      putl(os, "MI_EXTERN_C MI_CONST MI_ClassDecl %s_rtti;", alias.c_str());
3154                      nl(os);
3155                  }
3156              
3157                  // Generate Instance function
3158                  if (!s_options.noProviders)
3159                      GenInstanceFunctions(os,cd);
3160              
3161                  // Gen setters.
3162 mike     1.1     {
3163                      for (size_t i = 0; i < cd->numProperties; i++)
3164                          GenSetter(os, cd, NULL, (MI_ParameterDecl*)cd->properties[i]);
3165                  }
3166              
3167                  // Put method definitions and setters for each method parameter.
3168                  for (size_t i = 0; i < cd->numMethods; i++)
3169                  {
3170                      const MI_MethodDecl* md = cd->methods[i];
3171                      GenParametersStruct(os, cd, md);
3172              
3173                      // Generate convenience functions.
3174                      if (!s_options.noProviders)
3175                      {
3176                          if (Strcasecmp(cd->name, md->propagator) == 0 ||
3177                              providerClasses.find(cd->name) != providerClasses.end())
3178                          {
3179                              GenMethodFunctions(os, cd, md);
3180                          }
3181                      }
3182              
3183 mike     1.1         // Generate parameter setter for "MIReturn".
3184                      if (!s_options.noProviders)
3185                      {
3186                          MI_ParameterDecl pd;
3187                          memset(&pd, 0, sizeof(pd));
3188                          pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT;
3189                          pd.name = (char*)"MIReturn";
3190                          pd.type = md->returnType;
3191                          pd.offset = sizeof(MI_Instance);
3192                          pd.numQualifiers = md->numQualifiers;
3193                          pd.qualifiers = md->qualifiers;
3194                          GenSetter(os, cd, md, &pd);
3195                      }
3196              
3197                      if (!s_options.noProviders)
3198                      {
3199                          for (size_t j = 0; j < md->numParameters; j++)
3200                          {
3201                              const MI_ParameterDecl* pd = md->parameters[j];
3202              
3203                              // Skip stream parameters:
3204 mike     1.1                 if (pd->flags & MI_FLAG_STREAM)
3205                                  continue;
3206              
3207                              GenSetter(os, cd, md, pd);
3208                          }
3209                      }
3210                  }
3211              
3212                  if (providerClasses.find(cd->name) != providerClasses.end())
3213                  {
3214              
3215                      // Write the intrinsic provider function prototypes.
3216              
3217                      if (!s_options.noProviders)
3218                      {
3219                          PutCommentBox(os, alias + " provider function prototypes");
3220                          nl(os);
3221              
3222                          // Generate forward typedef for Self structure.
3223                          putl(os,"/* The developer may optionally define this structure */");
3224                          putl(os, "typedef struct _%s_Self %s_Self;\n", 
3225 mike     1.1                 alias.c_str(), alias.c_str());
3226              
3227                          if (cd->flags & MI_FLAG_ASSOCIATION)
3228                          {
3229                              string r;
3230              
3231 krisbash 1.5                 if (CanGenerateAssocRoles(cd))
3232 mike     1.1                 {
3233 krisbash 1.5                     if (s_options.association)
3234                                      r = ASSOCIATION_PROVIDER_PROTOTYPES;
3235                                  else
3236                                  {
3237                                      r = ROLE_PROVIDER_PROTOTYPES;
3238                                      SubRoles(cd, r);
3239                                  }
3240 mike     1.1                 }
3241 krisbash 1.5                 else
3242                                  errRefPropCount(cd->name);
3243 mike     1.1 
3244                              r = sub(r, "<ALIAS>", alias);
3245                              puts(os, r);
3246                          }
3247                          else if (cd->flags & MI_FLAG_INDICATION)
3248                          {
3249                              string r;
3250                              r = INDICATION_PROVIDER_PROTOTYPES;
3251                              r = sub(r, "<ALIAS>", alias);
3252                              puts(os, r);
3253                          }
3254                          else
3255                          {
3256                              if (HasKeys(cd))
3257                              {
3258                                  string r = INSTANCE_PROVIDER_PROTOTYPES;
3259                                  r = sub(r, "<ALIAS>", alias);
3260                                  puts(os, r);
3261                              }
3262                              else
3263                              {
3264 mike     1.1                     string r = COMMON_PROVIDER_PROTOTYPES;
3265                                  r = sub(r, "<ALIAS>", alias);
3266                                  puts(os, r);
3267                              }
3268                          }
3269                      }
3270              
3271                      // Write the extrinsic provider function prototypes.
3272                      if (!s_options.noProviders)
3273                      {
3274                          for (size_t i = 0; i < cd->numMethods; i++)
3275                          {
3276                              const MI_MethodDecl* md = cd->methods[i];
3277                              string r = sub(EXTRINSIC_METHOD_PROTOTYPE, "<ALIAS>", alias);
3278                              r = sub(r, "<METHOD>", md->name);
3279                              puts(os, r);
3280                          }
3281                      }
3282                  }
3283              
3284                  // Generate the class identifier:
3285 mike     1.1 #if 0
3286                  {
3287                      char id[33];
3288                      _MakeID(id);
3289                      string classIdentifier = alias + "_" + id;
3290                      classIdentifiers.insert(classIdentifier);
3291                      putl(os, "#define %s\n", classIdentifier.c_str());
3292                  }
3293              #endif
3294              
3295                  nl(os);
3296              
3297                  // c++ part
3298                  if (s_options.cpp)
3299                      GenCppClassHeader(parser, cd, os);
3300              
3301                  // End ifdef that Prevents multiple inclusion.
3302                  putl(os, "#endif /* _%s_h */", alias.c_str());
3303              
3304                  // Close file.
3305                  fclose(os);
3306 mike     1.1 }
3307              
3308              //==============================================================================
3309              //
3310              // GenClassSource
3311              //
3312              //     Generate the source file for the given MOF class. This file contains the
3313              //     the provider function stubs.
3314              //
3315              //==============================================================================
3316              
3317              static void GenClassSource(const MI_ClassDecl* cd)
3318              {
3319                  const string alias = AliasOf(cd->name);
3320              
3321                  // Open source file (refuse if it already exists).
3322                  bool append;
3323                  vector<char> data;
3324                  const string path = ExpandPath(alias + ".c");
3325                  FILE* os = 0;
3326                  {
3327 mike     1.1         append = Exists(path.c_str());
3328              
3329                      if (append)
3330                      {
3331                          if (!Inhale(path.c_str(), data))
3332                          {
3333                              err(ID_FAILED_TO_READ_FILE, "failed to read file: %s", 
3334                                  path.c_str());
3335                          }
3336              
3337                          _PatchLoadSignature(alias, path, data);
3338              
3339 krisbash 1.5             os = File_Open(path.c_str(), "a");
3340 mike     1.1 
3341                          if (!os)
3342                          {
3343                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
3344                                  path.c_str());
3345                          }
3346                      }
3347                      else
3348                      {
3349 krisbash 1.5             os = File_Open(path.c_str(), "w");
3350 mike     1.1 
3351                          if (!os)
3352                          {
3353                              err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
3354                                  path.c_str());
3355                          }
3356              
3357                          GenStatikGenLine(os);
3358                          Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
3359                      }
3360                  }
3361              
3362                  // Include required headers.
3363                  if (!append)
3364                  {
3365                      putl(os, "#include <MI.h>");
3366                      putl(os, "#include \"%s.h\"", alias.c_str());
3367                      nl(os);
3368                  }
3369              
3370                  // Generate extrinsic method stubs.
3371 mike     1.1     if (!append)
3372                  {
3373                      if (cd->flags & MI_FLAG_ASSOCIATION)
3374                      {
3375                          string r;
3376 krisbash 1.5             if (CanGenerateAssocRoles(cd))
3377 mike     1.1             {
3378 krisbash 1.5                 if (s_options.association)
3379                                  r = ASSOCIATION_PROVIDER_STUBS;
3380                              else
3381                              {
3382                                  r = ROLE_PROVIDER_STUBS;
3383                                  SubRoles(cd, r);
3384                              }
3385 mike     1.1             }
3386 krisbash 1.5             else
3387                              errRefPropCount(cd->name);
3388 mike     1.1 
3389                          r = sub(r, "<ALIAS>", alias);
3390                          puts(os, r);
3391                      }
3392                      else if (cd->flags & MI_FLAG_INDICATION)
3393                      {
3394                          string r = INDICATION_PROVIDER_STUBS;
3395                          r = sub(r, "<ALIAS>", alias);
3396                          puts(os, r);
3397                      }
3398                      else
3399                      {
3400                          if (HasKeys(cd))
3401                          {
3402                              string r = INSTANCE_PROVIDER_STUBS;
3403                              r = sub(r, "<ALIAS>", alias);
3404                              puts(os, r);
3405                          }
3406                          else
3407                          {
3408                              string r = COMMON_PROVIDER_STUBS;
3409 mike     1.1                 r = sub(r, "<ALIAS>", alias);
3410                              puts(os, r);
3411                          }
3412                      }
3413              
3414                  } 
3415              
3416                  bool patched = false;
3417              
3418                  // Generate extrinsic method stubs (not already found in file).
3419                  for (size_t i = 0; i < cd->numMethods; i++)
3420                  {
3421                      const MI_MethodDecl* md = cd->methods[i];
3422                      string r = sub(EXTRINSIC_METHOD_STUB, "<ALIAS>", alias);
3423                      r = sub(r, "<METHOD>", md->name);
3424              
3425                      string name = alias + "_Invoke_" + md->name;
3426              
3427                      // Skip methods already found in file.
3428              
3429                      if (append && strstr(&data[0], name.c_str()))
3430 mike     1.1             continue;
3431                      else
3432                      {
3433                          if (!patched)
3434                          {
3435                              Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str());
3436                              patched = true;
3437                          }
3438                          puts(os, r);
3439                      }
3440                  }
3441              
3442                  if (!patched)
3443                  {
3444                      Fprintf(s_stdout, ID_CHECKING, "Checking %s\n", path.c_str());
3445                  }
3446              
3447                  // Close file.
3448                  fclose(os);
3449              }
3450              
3451 mike     1.1 //==============================================================================
3452              //
3453              // PutString()
3454              //
3455              //     Write a string literal.
3456              //
3457              //==============================================================================
3458              
3459              static void PutStringLiteral(FILE* os, const char* value)
3460              {
3461                  put(os, "MI_T(\"");
3462              
3463                  for (const char* p = value; *p; p++)
3464                  {
3465                      unsigned char c = (unsigned char)*p;
3466              
3467                      if (c >= 32 && c <= 127)
3468                          put(os, "%c", c);
3469                      else
3470                          put(os, "\\%04o", c);
3471                  }
3472 mike     1.1 
3473                  put(os, "\")");
3474              }
3475              
3476              //==============================================================================
3477              //
3478              // Localize()
3479              //
3480              //     Add the string to the localization table and return an integer 
3481              //     identifier for that string. The localization id is one greater
3482              //     than its index in the s_localizations.
3483              //
3484              //==============================================================================
3485              
3486              static vector<string> s_localizations;
3487              
3488              static MI_Uint32 Localize(const string& msg)
3489              {
3490                  for (size_t i = 0; i < s_localizations.size(); i++)
3491                  {
3492                      if (s_localizations[i] == msg)
3493 mike     1.1             return (MI_Uint32)(i + 1);
3494                  }
3495              
3496                  s_localizations.push_back(msg);
3497                  return (MI_Uint32)s_localizations.size();
3498              }
3499              
3500              //==============================================================================
3501              //
3502              // GenScalarValueInitializer
3503              //
3504              //     Put the value initializer for a property or qualifier value.
3505              //
3506              //==============================================================================
3507              
3508              static void GenScalarValueInitializer(
3509                  FILE* os, 
3510                  MI_Type type, 
3511                  const void* value,
3512                  bool localize)
3513              {
3514 mike     1.1     // Unsatisfiable condition.
3515                  assert(value != NULL);
3516              
3517                  switch (type)
3518                  {
3519                      case MI_BOOLEAN:
3520                      {
3521                          put(os, "%s", *((MI_Boolean*)value) ? "1" : "0");
3522                          break;
3523                      }
3524                      case MI_UINT8:
3525                      {
3526                          put(os, "%u", *((MI_Uint8*)value));
3527                          break;
3528                      }
3529                      case MI_SINT8:
3530                      {
3531                          put(os, "%d", *((MI_Sint8*)value));
3532                          break;
3533                      }
3534                      case MI_UINT16:
3535 mike     1.1         {
3536                          put(os, "%u", *((MI_Uint16*)value));
3537                          break;
3538                      }
3539                      case MI_SINT16:
3540                      {
3541                          put(os, "%d", *((MI_Sint16*)value));
3542                          break;
3543                      }
3544                      case MI_UINT32:
3545                      {
3546                          MI_Uint32 x = *((MI_Uint32*)value);
3547                          put(os, "%uU", x);
3548                          break;
3549                      }
3550                      case MI_SINT32:
3551                      {
3552                          MI_Sint32 x = *((MI_Sint32*)value);
3553              
3554                          if (x == -2147483647-1)
3555                              put(os, "-2147483647-1");
3556 mike     1.1             else
3557                              put(os, "%d", x);
3558                          break;
3559                      }
3560                      case MI_UINT64:
3561                      {
3562                          put(os, "MI_ULL(" UINT64_FMT ")", *((MI_Uint64*)value));
3563                          break;
3564                      }
3565                      case MI_SINT64:
3566                      {
3567                          MI_Sint64 x = *((MI_Sint64*)value);
3568                          if (x == -MI_LL(9223372036854775807)-MI_LL(1))
3569                              put(os, "-MI_LL(9223372036854775807)-MI_LL(1)");
3570                          else
3571 krisbash 1.5             {
3572                              if (x >= 0)
3573                                  put(os, "MI_LL(" SINT64_FMT ")", x);
3574                              else
3575                                  put(os, "-MI_LL(" SINT64_FMT ")", -x);
3576                          }
3577 mike     1.1             break;
3578                      }
3579                      case MI_REAL32:
3580                      {
3581                          put(os, "(float)%g", *((MI_Real32*)value));
3582                          break;
3583                      }
3584                      case MI_REAL64:
3585                      {
3586                          put(os, "(double)%g", *((MI_Real64*)value));
3587                          break;
3588                      }
3589                      case MI_CHAR16:
3590                      {
3591                          put(os, "%u", *((MI_Char16*)value));
3592                          break;
3593                      }
3594                      case MI_DATETIME:
3595                      {
3596                          const MI_Datetime& x = *((MI_Datetime*)value);
3597              
3598 mike     1.1             if (x.isTimestamp)
3599                          {
3600                              put(os,"{1,{{%u,%u,%u,%u,%u,%u,%u,%d}}}",
3601                                  x.u.timestamp.year, 
3602                                  x.u.timestamp.month, 
3603                                  x.u.timestamp.day, 
3604                                  x.u.timestamp.hour, 
3605                                  x.u.timestamp.minute, 
3606                                  x.u.timestamp.second, 
3607                                  x.u.timestamp.microseconds,
3608                                  x.u.timestamp.utc);
3609                          }
3610                          else
3611                          {
3612                              put(os,"{0,{{%u,%u,%u,%u,%u}}}",
3613                                  x.u.interval.days, 
3614                                  x.u.interval.hours, 
3615                                  x.u.interval.minutes,
3616                                  x.u.interval.seconds, 
3617                                  x.u.interval.microseconds);
3618                          }
3619 mike     1.1             break;
3620                      }
3621                      case MI_STRING:
3622                      {
3623                          if (localize && s_options.localize)
3624                          {
3625                              MI_Uint32 id = Localize((char*)value);
3626                              char buf[9];
3627                              Snprintf(buf, MI_COUNT(buf), "%u", id);
3628                              PutStringLiteral(os, buf);
3629                          }
3630                          else
3631                              PutStringLiteral(os, (char*)value);
3632                          break;
3633                      }
3634                      default:
3635                          // Unreachable!
3636                          assert(0);
3637                          break;
3638                  }
3639              }
3640 mike     1.1 
3641              //==============================================================================
3642              //
3643              // GenValue()
3644              //
3645              //     Generate the value for a property declaration.
3646              //
3647              //==============================================================================
3648              
3649              static void GenValue(
3650                  FILE* os, 
3651                  const string& stem,
3652                  MI_Uint32 type,
3653                  const void* value,
3654                  bool localize)
3655              {
3656                  MI_Type stype = (MI_Type)(type & ~MI_ARRAY_BIT);
3657                  string typenameof = sub( TypeNameOf(stype), "String", "Char*");
3658              
3659                  // If the value is null, just return.
3660                  if (!value)
3661 mike     1.1         return;
3662              
3663                  // Encode array or scalar.
3664                  if (type & MI_ARRAY_BIT)
3665                  {
3666                      // Write the array data elements.
3667              
3668                      putl(os, "static MI_CONST MI_%s %s_data_value[] =", 
3669                          typenameof.c_str(), stem.c_str());
3670                      putl(os, "{");
3671              
3672                      if (type == MI_STRINGA)
3673                      {
3674                          MI_StringA* arr = (MI_StringA*)value;
3675              
3676                          for (MI_Uint32 i = 0; i < arr->size; i++)
3677                          {
3678                              put(os, "    ");
3679                              GenScalarValueInitializer(os, stype, arr->data[i], localize);
3680                              putl(os, ",");
3681                          }
3682 mike     1.1         }
3683                      else
3684                      {
3685                          MI_Uint8A* arr = (MI_Uint8A*)value;
3686                          MI_Uint8* p = arr->data;
3687              
3688                          for (MI_Uint32 i = 0; i < arr->size; i++)
3689                          {
3690                              put(os, "    ");
3691                              GenScalarValueInitializer(os, stype, p, localize);
3692                              p += ScalarSizeOf(stype);
3693                              putl(os, ",");
3694                          }
3695                      }
3696              
3697                      putl(os, "};");
3698                      nl(os);
3699              
3700                      // Write the array itself.
3701              
3702                      putl(os, "static MI_CONST MI_Const%sA %s_value =", TypeNameOf(stype), stem.c_str());
3703 mike     1.1         putl(os, "{");
3704                      putl(os, "    %s_data_value,", stem.c_str());
3705                      putl(os, "    MI_COUNT(%s_data_value),", stem.c_str());
3706                      putl(os, "};");
3707                      nl(os);
3708                  }
3709                  else
3710                  {
3711                      put(os, "static MI_CONST MI_%s %s_value = ", typenameof.c_str(), stem.c_str());
3712                      GenScalarValueInitializer(os, (MI_Type)type, value, localize);
3713                      putl(os, ";");
3714                      nl(os);
3715                  }
3716              }
3717              
3718              //==============================================================================
3719              //
3720              // MI_Qualifier
3721              //
3722              //     This function generates a qualifier.
3723              //
3724 mike     1.1 //==============================================================================
3725              
3726              static void GenQualifier(
3727                  Parser& parser,
3728                  FILE* os,
3729                  const MI_Qualifier* q,
3730                  const string& stem_)
3731              {
3732                  string stem = stem_ + "_" + q->name + "_qual";
3733              
3734                  /* Find qualifier declaration */
3735                  const MI_QualifierDecl* qd = parser.findQualifierDecl(q->name);
3736              
3737                  if (!qd)
3738                      err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__);
3739              
3740                  /* Generate the value */
3741                  GenValue(os, stem, q->type, q->value, 
3742                      (q->flavor & MI_FLAG_TRANSLATABLE) ? true : false);
3743              
3744                  const char T[] =
3745 mike     1.1         "static MI_CONST MI_Qualifier <STEM> =\n"
3746                      "{\n"
3747                      "    MI_T(\"<NAME>\"),\n"
3748                      "    <TYPE>,\n"
3749                      "    <FLAVOR>,\n"
3750                      "    <VALUE>\n"
3751                      "};\n"
3752                      "\n";
3753              
3754                  string r = T;
3755                  r = sub(r, "<STEM>", stem);
3756                  r = sub(r, "<NAME>", q->name);
3757                  r = sub(r, "<TYPE>", MakeType(q->type));
3758                  r = sub(r, "<FLAVOR>", MakeFlavor(q->flavor));
3759              
3760                  if (q->value)
3761                      r = sub(r, "<VALUE>", "&" + stem + "_value");
3762                  else
3763                      r = sub(r, "<VALUE>", "NULL");
3764              
3765                  puts(os, r);
3766 mike     1.1 }
3767              
3768              //==============================================================================
3769              //
3770              // GenQualifiers()
3771              //
3772              //     Generate a list of qualifier definitions. Return the number of qualifiers
3773              //     generated (which may be less than numQualifiers due to excluded
3774              //     qualifiers, such as boolean).
3775              //
3776              //==============================================================================
3777              
3778              static size_t GenQualifiers(
3779                  Parser& parser,
3780                  FILE* os, 
3781                  MI_Qualifier** qualifiers,
3782                  MI_Uint32 numQualifiers,
3783                  const string& stem)
3784              {
3785                  size_t count = 0;
3786              
3787 mike     1.1     if (numQualifiers == 0)
3788                      return 0;
3789              
3790                  /* Check if qualifiers are ignored */
3791                  if (s_options.ignoreAllQualifiers)
3792                      return 0;
3793              
3794                  // Generate qualifiers.
3795              
3796                  for (MI_Uint32 i = 0; i < numQualifiers; i++)
3797                  {
3798                      const MI_Qualifier* q = qualifiers[i];
3799              
3800                      if (q->type == MI_BOOLEAN && !s_options.booleanQualifiers)
3801                          continue;
3802              
3803                      // Skip Description qualifier if -D option was given.
3804                      if (eqi(q->name, "Description") && !s_options.descriptions)
3805                          continue;
3806              
3807                      // Skip Values qualifier if -V option was given.
3808 mike     1.1         if (eqi(q->name, "Values") && !s_options.values)
3809                          continue;
3810              
3811                      // Skip ValueMap qualifier if -V option was given.
3812                      if (eqi(q->name, "ValueMap") && !s_options.values)
3813                          continue;
3814              
3815 krisbash 1.5         // Skip MappingStrings qualifier if -M option was given.
3816 mike     1.1         if (eqi(q->name, "MappingStrings") && !s_options.mappingStrings)
3817                          continue;
3818              
3819 krisbash 1.5         // Skip ModelCorrespondence qualifiers?
3820                      if (eqi(q->name, "ModelCorrespondence") && !s_options.modelCorrespondence)
3821                          continue;
3822              
3823 mike     1.1         GenQualifier(parser, os, q, stem);
3824                      count++;
3825                  }
3826              
3827                  // If no qualifiers were generated, return now to avoid creating an
3828                  // empty array of qualifiers.
3829                  if (count == 0)
3830                      return 0;
3831              
3832                  // Generate the array of qualifiers.
3833              
3834                  putl(os, "static MI_Qualifier MI_CONST* MI_CONST %s_quals[] =", stem.c_str());
3835                  putl(os, "{");
3836              
3837                  for (MI_Uint32 i = 0; i < numQualifiers; i++)
3838                  {
3839                      const MI_Qualifier* q = qualifiers[i];
3840              
3841                      if (q->type == MI_BOOLEAN && !s_options.booleanQualifiers)
3842                          continue;
3843              
3844 mike     1.1         // Skip Description qualifier if -D option was given.
3845                      if (eqi(q->name, "Description") && !s_options.descriptions)
3846                          continue;
3847              
3848                      // Skip Values qualifier if -v option was given.
3849                      if (eqi(q->name, "Values") && !s_options.values)
3850                          continue;
3851              
3852                      // Skip ValueMap qualifier if -v option was given.
3853                      if (eqi(q->name, "ValueMap") && !s_options.values)
3854                          continue;
3855              
3856                      // Skip Values qualifier if -M option was given.
3857                      if (eqi(q->name, "MappingStrings") && !s_options.mappingStrings)
3858                          continue;
3859              
3860 krisbash 1.5         // Skip ModelCorrespondence qualifiers?
3861                      if (eqi(q->name, "ModelCorrespondence") && !s_options.modelCorrespondence)
3862                          continue;
3863              
3864 mike     1.1         putl(os, "    &%s_%s_qual,", stem.c_str(), q->name);
3865                  }
3866              
3867                  putl(os, "};");
3868                  nl(os);
3869              
3870                  return count;
3871              }
3872              
3873              //==============================================================================
3874              //
3875              // HashCode()
3876              //
3877              //     Compute a hash code of the given CIM identifier as follows.
3878              //
3879              //         (name[0] << 16) | (name[len-1] << 8) | len
3880              //
3881              //==============================================================================
3882              
3883              static MI_Uint32 HashCode(const string& s)
3884              {
3885 mike     1.1     MI_Uint32 n = (MI_Uint32)s.size();
3886              
3887                  if (n == 0)
3888                      err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__);
3889              
3890                  return tolower((MI_Uint32)s[0])<<16 | tolower((MI_Uint32)s[n-1])<<8 | n;
3891              }
3892              
3893              //==============================================================================
3894              //
3895              // GenPropertyDecl()
3896              //
3897              //     This function generates a property declaration (i.e., a structure 
3898              //     initialization of the MI_PropertyDecl structure) for the given property.
3899              //
3900              //==============================================================================
3901              
3902              static void GenPropertyDecl(
3903                  Parser& parser,
3904                  FILE* os, 
3905                  const MI_ClassDecl* cd,
3906 mike     1.1     const MI_PropertyDecl* pd)
3907              {
3908                  const string alias = AliasOf(cd->name);
3909              
3910                  // Generate the qualifiers first.
3911                  size_t numQualifiers = GenQualifiers(
3912                      parser,
3913                      os, 
3914                      pd->qualifiers, 
3915                      pd->numQualifiers,
3916                      AliasOf(cd->name) + "_" + pd->name);
3917              
3918                  // Generate the value.
3919                  if (pd->value)
3920                      GenValue(os, alias + "_" + pd->name, pd->type, pd->value, false);
3921              
3922                  static const char T[] =
3923                      "/* property <CLASS>.<PROP> */\n"
3924                      "static MI_CONST MI_PropertyDecl <CLASS>_<PROP>_prop =\n"
3925                      "{\n"
3926                      "    <FLAGS>, /* flags */\n"
3927 mike     1.1         "    <CODE>, /* code */\n"
3928                      "    MI_T(\"<PROP>\"), /* name */\n"
3929                      "    <QUALS>, /* qualifiers */\n"
3930                      "    <NQUALS>, /* numQualifiers */\n"
3931                      "    <TYPE>, /* type */\n"
3932                      "    <CLASSNAME>, /* className */\n"
3933                      "    <SUBSCRIPT>, /* subscript */\n"
3934                      "    offsetof(<CLASS>, <PROP>), /* offset */\n"
3935                      "    <ORIGIN>, /* origin */\n"
3936                      "    <PROPAGATOR>, /* propagator */\n";
3937              
3938                  string r = T;
3939                  r = sub(r, "<CLASS>", alias);
3940                  r = subx(r, "<CODE>", HashCode(pd->name));
3941                  r = sub(r, "<PROP>", pd->name);
3942                  r = sub(r, "<FLAGS>", MakeFlags(pd->flags));
3943              
3944                  /* check for embedded instances */
3945                  if (MI_STRING == (pd->type & ~MI_ARRAY_BIT) 
3946                      && IsPropertyRefOrInstance(pd))
3947                  {
3948 mike     1.1         r = sub(r, "<TYPE>", ((pd->type & MI_ARRAY_BIT) != 0 ? "MI_INSTANCEA" : "MI_INSTANCE"));
3949                  }
3950                  else
3951                      r = sub(r, "<TYPE>", MakeType(pd->type));
3952              
3953                  if (numQualifiers)
3954                  {
3955                      string s = AliasOf(cd->name) + "_" + pd->name + "_quals";
3956                      r = sub(r, "<QUALS>", s);
3957                      r = sub(r, "<NQUALS>", "MI_COUNT(" + s + ")");
3958                  }
3959                  else
3960                  {
3961                      r = sub(r, "<QUALS>", "NULL");
3962                      r = sub(r, "<NQUALS>", "0");
3963                  }
3964              
3965                  if (!GetPropertyClassname(pd).empty())
3966                      r = sub(r, "<CLASSNAME>", Quote(GetPropertyClassname(pd)));
3967                  else
3968                      r = sub(r, "<CLASSNAME>", "NULL");
3969 mike     1.1 
3970                  r = subu(r, "<SUBSCRIPT>", pd->subscript);
3971                  r = sub(r, "<ORIGIN>", Quote(pd->origin));
3972                  r = sub(r, "<PROPAGATOR>", Quote(pd->propagator));
3973              
3974                  puts(os, r);
3975              
3976                  // Put the value if any.
3977              
3978                  if (pd->value)
3979                      putl(os, "    &%s_%s_value,", alias.c_str(), pd->name);
3980                  else
3981                      putl(os, "    NULL,");
3982              
3983                  putl(os, "};");
3984                  nl(os);
3985              }
3986              
3987              //==============================================================================
3988              //
3989              // GenPropertyDecls()
3990 mike     1.1 //
3991              //     This function generates an array of property declaration objects for
3992              //     the given class.
3993              //
3994              //==============================================================================
3995              
3996              static void GenPropertyDecls(
3997                  Parser& parser,
3998                  FILE* os, 
3999                  const MI_ClassDecl* cd)
4000              {
4001                  const string alias = AliasOf(cd->name);
4002              
4003                  // Generate a property declaration for each property.
4004                  for (size_t i = 0; i < cd->numProperties; i++)
4005                  {
4006                      const MI_PropertyDecl* pd = cd->properties[i];
4007              
4008                      // Only generate property declarations if this class is the owner.
4009                      if (Strcasecmp(cd->name, pd->propagator) == 0)
4010                      {
4011 mike     1.1             GenPropertyDecl(parser, os, cd, pd);
4012                      }
4013                  }
4014              
4015                  // Generate the array of property declarations (if any)
4016              
4017                  if (cd->numProperties)
4018                  {
4019                      putl(os, "static MI_PropertyDecl MI_CONST* MI_CONST %s_props[] =", 
4020                          alias.c_str());
4021                      putl(os, "{");
4022              
4023                      for (size_t i = 0; i < cd->numProperties; i++)
4024                      {
4025                          const MI_PropertyDecl* pd = cd->properties[i];
4026                          const string ownerAlias = AliasOf(pd->propagator);
4027                          putl(os, "    &%s_%s_prop,", ownerAlias.c_str(), pd->name);
4028                      }
4029              
4030                      putl(os, "};");
4031                  }
4032 mike     1.1 
4033                  nl(os);
4034              }
4035              
4036              //==============================================================================
4037              //
4038              // GenParameterDecl()
4039              //
4040              //     This function generates a parameter declaration for the given method and
4041              //     class.
4042              //
4043              //==============================================================================
4044              
4045              static void GenParameterDecl(
4046                  Parser& parser,
4047                  FILE* os, 
4048                  const MI_ClassDecl* cd,
4049                  const MI_MethodDecl* md,
4050                  const MI_ParameterDecl* pd)
4051              {
4052                  const string alias = AliasOf(cd->name);
4053 mike     1.1 
4054                  // Generate the qualifiers first.
4055                  size_t numQualifiers = GenQualifiers(
4056                      parser,
4057                      os, 
4058                      pd->qualifiers, 
4059                      pd->numQualifiers,
4060                      AliasOf(cd->name) + "_" + md->name + "_" + pd->name);
4061              
4062                  static const char T[] =
4063                      "/* parameter <CLASS>.<METH>(): <PARAM> */\n"
4064                      "static MI_CONST MI_ParameterDecl <CLASS>_<METH>_<PARAM>_param =\n"
4065                      "{\n"
4066                      "    <FLAGS>, /* flags */\n"
4067                      "    <CODE>, /* code */\n"
4068                      "    MI_T(\"<PARAM>\"), /* name */\n"
4069                      "    <QUALS>, /* qualifiers */\n"
4070                      "    <NQUALS>, /* numQualifiers */\n"
4071                      "    <TYPE>, /* type */\n"
4072                      "    <CLASSNAME>, /* className */\n"
4073                      "    <SUBSCRIPT>, /* subscript */\n"
4074 mike     1.1         "    <OFFSET>, /* offset */\n"
4075                      "};\n"
4076                      "\n";
4077              
4078                  string r = T;
4079              
4080                  if (pd->flags & MI_FLAG_STREAM)
4081                      r = sub(r, "<OFFSET>", "0xFFFFFFFF");
4082                  else
4083                      r = sub(r, "<OFFSET>", "offsetof(<CLASS>_<METH>, <PARAM>)");
4084              
4085                  r = sub(r, "<CLASS>", alias);
4086                  r = subx(r, "<CODE>", HashCode(pd->name));
4087                  r = sub(r, "<METH>", md->name);
4088                  r = sub(r, "<PARAM>", pd->name);
4089                  r = sub(r, "<FLAGS>", MakeFlags(pd->flags));
4090              
4091                  /* check for embedded instances */
4092                  if (MI_STRING == (pd->type & ~MI_ARRAY_BIT) 
4093                      && IsPropertyRefOrInstance(pd))
4094                  {
4095 mike     1.1         r = sub(r, "<TYPE>", ((pd->type & MI_ARRAY_BIT) != 0 ? "MI_INSTANCEA" : "MI_INSTANCE"));
4096                  }
4097                  else
4098                      r = sub(r, "<TYPE>", MakeType(pd->type));
4099              
4100                  if (numQualifiers)
4101                  {
4102                      string s = AliasOf(cd->name) + "_" + md->name + "_" +pd->name +"_quals";
4103                      r = sub(r, "<QUALS>", s);
4104                      r = sub(r, "<NQUALS>", "MI_COUNT(" + s + ")");
4105                  }
4106                  else
4107                  {
4108                      r = sub(r, "<QUALS>", "NULL");
4109                      r = sub(r, "<NQUALS>", "0");
4110                  }
4111              
4112                  if (!GetPropertyClassname(pd).empty())
4113                      r = sub(r, "<CLASSNAME>", Quote(GetPropertyClassname(pd)));
4114                  else
4115                      r = sub(r, "<CLASSNAME>", "NULL");
4116 mike     1.1 
4117                  r = subu(r, "<SUBSCRIPT>", pd->subscript);
4118              
4119                  puts(os, r);
4120              }
4121              
4122              //==============================================================================
4123              //
4124              // GenMethodDecl()
4125              //
4126              //     This function generates a method declaration for the given class.
4127              //
4128              //==============================================================================
4129              
4130              static void GenMethodDecl(
4131                  Parser& parser,
4132                  FILE* os, 
4133                  const MI_ClassDecl* cd,
4134                  const MI_MethodDecl* md)
4135              {
4136                  // Generate the qualifiers first.
4137 mike     1.1     size_t numQualifiers = GenQualifiers(
4138                      parser,
4139                      os, 
4140                      md->qualifiers, 
4141                      md->numQualifiers,
4142                      AliasOf(cd->name) + "_" + md->name);
4143              
4144                  const string alias = AliasOf(cd->name);
4145              
4146                  // Generate each parameter declartions.
4147                  for (size_t i = 0; i < md->numParameters; i++)
4148                  {
4149                      const MI_ParameterDecl* pd = md->parameters[i];
4150                      GenParameterDecl(parser, os, cd, md, pd);
4151                  }
4152              
4153                  // Generate the return parameter declarations.
4154                  {
4155                      MI_ParameterDecl pd;
4156                      memset(&pd, 0, sizeof(pd));
4157                      pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT;
4158 mike     1.1         pd.name = (char*)"MIReturn";
4159                      pd.type = md->returnType;
4160                      pd.offset = sizeof(MI_Instance);
4161                      pd.numQualifiers = md->numQualifiers;
4162                      pd.qualifiers = md->qualifiers;
4163                      GenParameterDecl(parser, os, cd, md, &pd);
4164                  }
4165              
4166                  // Generate the parmaeter declaration array.
4167                  {
4168                      putl(os, "static MI_ParameterDecl MI_CONST* MI_CONST %s_%s_params[] =",
4169                          alias.c_str(), md->name);
4170                      putl(os, "{");
4171              
4172                      putl(os, "    &%s_%s_MIReturn_param,", alias.c_str(), md->name);
4173              
4174                      for (size_t i = 0; i < md->numParameters; i++)
4175                      {
4176                          const MI_ParameterDecl* pd = md->parameters[i];
4177                          putl(os, "    &%s_%s_%s_param,", alias.c_str(), md->name, pd->name);
4178                      }
4179 mike     1.1 
4180                      putl(os, "};");
4181                      nl(os);
4182                  }
4183              
4184                  static const char T[] =
4185                      "/* method <ALIAS>.<METH>() */\n"
4186                      "MI_CONST MI_MethodDecl <ALIAS>_<METH>_rtti =\n"
4187                      "{\n"
4188                      "    <FLAGS>, /* flags */\n"
4189                      "    <CODE>, /* code */\n"
4190                      "    MI_T(\"<METH>\"), /* name */\n"
4191                      "    <QUALS>, /* qualifiers */\n"
4192                      "    <NQUALS>, /* numQualifiers */\n"
4193                      "    <ALIAS>_<METH>_params, /* parameters */\n"
4194                      "    MI_COUNT(<ALIAS>_<METH>_params), /* numParameters */\n"
4195                      "    sizeof(<ALIAS>_<METH>), /* size */\n"
4196                      "    <TYPE>, /* returnType */\n"
4197                      "    <ORIGIN>, /* origin */\n"
4198                      "    <PROPAGATOR>, /* propagator */\n"
4199                      "    &<SCHEMA>, /* schema */\n"
4200 mike     1.1         "    <STUB>, /* method */\n"
4201                      "};\n"
4202                      "\n";
4203              
4204                  string r = T;
4205              
4206                  if (s_options.schema.size())
4207                      r = sub(r, "<SCHEMA>", s_options.schema.c_str());
4208                  else
4209                      r = sub(r, "<SCHEMA>", "schemaDecl");
4210              
4211                  r = sub(r, "<ALIAS>", alias);
4212                  r = subx(r, "<CODE>", HashCode(md->name));
4213                  r = sub(r, "<METH>", md->name);
4214                  r = sub(r, "<FLAGS>", MakeFlags(md->flags));
4215              
4216                  /* check for embedded instances */
4217                  if (MI_STRING == (md->returnType & ~MI_ARRAY_BIT) 
4218                      && ExistInstanceQualifier(md))
4219                  {
4220                      r = sub(r, "<TYPE>", ((md->returnType & MI_ARRAY_BIT) != 0 ? "MI_INSTANCEA" : "MI_INSTANCE"));
4221 mike     1.1     }
4222                  else
4223                      r = sub(r, "<TYPE>", MakeType(md->returnType));
4224              
4225                  r = sub(r, "<ORIGIN>", Quote(md->origin));
4226                  r = sub(r, "<PROPAGATOR>", Quote(md->propagator));
4227              
4228                  // If there is no provider for this class, set to NULL
4229                  if (providerClasses.find(cd->name) == providerClasses.end())
4230                  {
4231                      r = sub(r, "<STUB>", "NULL");
4232                  }
4233                  else
4234                  {
4235                      static const char T_template[] =
4236                          "(MI_ProviderFT_Invoke)<ALIAS>_Invoke_<METH>";
4237                      string t = T_template;
4238                      t = sub(t, "<ALIAS>", alias);
4239                      t = sub(t, "<METH>", md->name);
4240                      r = sub(r, "<STUB>", t);
4241                  }
4242 mike     1.1 
4243                  if (numQualifiers)
4244                  {
4245                      string s = AliasOf(cd->name) + "_" + md->name + "_quals";
4246                      r = sub(r, "<QUALS>", s);
4247                      r = sub(r, "<NQUALS>", "MI_COUNT(" + s + ")");
4248                  }
4249                  else
4250                  {
4251                      r = sub(r, "<QUALS>", "NULL");
4252                      r = sub(r, "<NQUALS>", "0");
4253                  }
4254              
4255                  puts(os, r);
4256              }
4257              
4258              //==============================================================================
4259              //
4260              // GenMethodDecls()
4261              //
4262              //     This function generates a method declaration array for the given class.
4263 mike     1.1 //
4264              //==============================================================================
4265              
4266              static void GenMethodDecls(
4267                  Parser& parser,
4268                  FILE* os, 
4269                  const MI_ClassDecl* cd)
4270              {
4271                  const string alias = AliasOf(cd->name);
4272              
4273                  if (cd->numMethods == 0)
4274                      return;
4275              
4276                  // Generate a property declaration for each property.
4277                  for (size_t i = 0; i < cd->numMethods; i++)
4278                  {
4279                      const MI_MethodDecl* md = cd->methods[i];
4280              
4281                      // Only generate this definition for the propagating class unless
4282                      // the derived class is a class for which there will be a provider.
4283                      // In that case we must generate this declaration so it can hold
4284 mike     1.1         // the extrinsic method stub for that provider.
4285                      if (Strcasecmp(cd->name, md->propagator) == 0 ||
4286                          providerClasses.find(cd->name) != providerClasses.end())
4287                      {
4288                          GenMethodDecl(parser, os, cd, md);
4289                      }
4290                  }
4291              
4292                  // Generate the array of property declarations.
4293              
4294                  putl(os, "static MI_MethodDecl MI_CONST* MI_CONST %s_meths[] =", 
4295                      alias.c_str());
4296                  putl(os, "{");
4297              
4298                  for (size_t i = 0; i < cd->numMethods; i++)
4299                  {
4300                      const MI_MethodDecl* md = cd->methods[i];
4301              
4302                      if (Strcasecmp(cd->name, md->propagator) == 0 ||
4303                          providerClasses.find(cd->name) != providerClasses.end())
4304                      {
4305 mike     1.1             putl(os, "    &%s_%s_rtti,", alias.c_str(), md->name);
4306                      }
4307                      else
4308                      {
4309                          const string ownerAlias = AliasOf(md->propagator);
4310                          putl(os, "    &%s_%s_rtti,", ownerAlias.c_str(), md->name);
4311                      }
4312                  }
4313              
4314                  putl(os, "};");
4315                  nl(os);
4316              }
4317              
4318              //==============================================================================
4319              //
4320              // GenFunctionTable()
4321              //
4322              //     This function generates the function table for the given class. This
4323              //     table contains pointers to the provider stubs.
4324              //
4325              //==============================================================================
4326 mike     1.1 
4327              static void GenFunctionTable(
4328                  FILE* os, 
4329                  const MI_ClassDecl* cd)
4330              {
4331                  const char ROLES[] = 
4332                      "static void MI_CALL <ALIAS>_AssociatorInstances(\n"
4333                      "    <ALIAS>_Self* self,\n"
4334                      "    MI_Context* context,\n"
4335                      "    const MI_Char* nameSpace,\n"
4336                      "    const MI_Char* className,\n"
4337                      "    const MI_Instance* instanceName,\n"
4338                      "    const MI_Char* resultClass,\n"
4339                      "    const MI_Char* role,\n"
4340                      "    const MI_Char* resultRole,\n"
4341                      "    const MI_PropertySet* propertySet,\n"
4342                      "    MI_Boolean keysOnly,\n"
4343                      "    const MI_Filter* filter)\n"
4344                      "{\n"
4345                      "    if (<ALIAS1>_IsA(instanceName))\n"
4346                      "    {\n"
4347 mike     1.1         "        if (_Match(role, MI_T(\"<ROLE1>\")) && \n"
4348                      "            _Match(resultRole, MI_T(\"<ROLE2>\")))\n"
4349                      "        {\n"
4350                      "            <ALIAS>_AssociatorInstances<ROLE1>(\n"
4351                      "                self, \n"
4352                      "                context, \n"
4353                      "                nameSpace, \n"
4354                      "                className, \n"
4355                      "                (<ALIAS1>*)instanceName, \n"
4356                      "                resultClass, \n"
4357                      "                propertySet, \n"
4358                      "                keysOnly, \n"
4359                      "                filter);\n"
4360                      "            return;\n"
4361                      "        }\n"
4362                      "    }\n"
4363                      "\n"
4364                      "    if (<ALIAS2>_IsA(instanceName))\n"
4365                      "    {\n"
4366                      "        if (_Match(role, MI_T(\"<ROLE2>\")) && \n"
4367                      "            _Match(resultRole, MI_T(\"<ROLE1>\")))\n"
4368 mike     1.1         "        {\n"
4369                      "            <ALIAS>_AssociatorInstances<ROLE2>(\n"
4370                      "                self, \n"
4371                      "                context, \n"
4372                      "                nameSpace, \n"
4373                      "                className, \n"
4374                      "                (<ALIAS2>*)instanceName, \n"
4375                      "                resultClass, \n"
4376                      "                propertySet, \n"
4377                      "                keysOnly, \n"
4378                      "                filter);\n"
4379                      "            return;\n"
4380                      "        }\n"
4381                      "    }\n"
4382                      "\n"
4383 krisbash 1.5         "    MI_Context_PostResult(context, MI_RESULT_OK);\n"
4384 mike     1.1         "}\n"
4385                      "\n"
4386                      "static void MI_CALL <ALIAS>_ReferenceInstances(\n"
4387                      "    <ALIAS>_Self* self,\n"
4388                      "    MI_Context* context,\n"
4389                      "    const MI_Char* nameSpace,\n"
4390                      "    const MI_Char* className,\n"
4391                      "    const MI_Instance* instanceName,\n"
4392                      "    const MI_Char* role,\n"
4393                      "    const MI_PropertySet* propertySet,\n"
4394                      "    MI_Boolean keysOnly,\n"
4395                      "    const MI_Filter* filter)\n"
4396                      "{\n"
4397                      "    if (<ALIAS1>_IsA(instanceName))\n"
4398                      "    {\n"
4399                      "        if (_Match(role, MI_T(\"<ROLE1>\")))\n"
4400                      "        {\n"
4401                      "            <ALIAS>_ReferenceInstances<ROLE1>(\n"
4402                      "                self, \n"
4403                      "                context, \n"
4404                      "                nameSpace, \n"
4405 mike     1.1         "                className, \n"
4406                      "                (<ALIAS1>*)instanceName, \n"
4407                      "                propertySet, \n"
4408                      "                keysOnly, \n"
4409                      "                filter);\n"
4410                      "            return;\n"
4411                      "        }\n"
4412                      "    }\n"
4413                      "\n"
4414                      "    if (<ALIAS2>_IsA(instanceName))\n"
4415                      "    {\n"
4416                      "        if (_Match(role, MI_T(\"<ROLE2>\")))\n"
4417                      "        {\n"
4418                      "            <ALIAS>_ReferenceInstances<ROLE2>(\n"
4419                      "                self, \n"
4420                      "                context, \n"
4421                      "                nameSpace, \n"
4422                      "                className, \n"
4423                      "                (<ALIAS2>*)instanceName, \n"
4424                      "                propertySet, \n"
4425                      "                keysOnly, \n"
4426 mike     1.1         "                filter);\n"
4427                      "            return;\n"
4428                      "        }\n"
4429                      "    }\n"
4430                      "\n"
4431 krisbash 1.5         "    MI_Context_PostResult(context, MI_RESULT_OK);\n"
4432 mike     1.1         "}\n"
4433                      "\n";
4434              
4435                  const string alias = AliasOf(cd->name);
4436              
4437                  // Generate the array of property declarations.
4438              
4439                  if (cd->flags & MI_FLAG_ASSOCIATION)
4440                  {
4441 krisbash 1.5         if (CanGenerateAssocRoles(cd))
4442 mike     1.1         {
4443 krisbash 1.5             if (!s_options.association)
4444                          {
4445                              string r = ROLES;
4446                              r = sub(r, "<ALIAS>", alias);
4447                              SubRoles(cd, r);
4448                              puts(os, r);
4449                          }
4450 mike     1.1         }
4451 krisbash 1.5         else
4452                          errRefPropCount(cd->name);
4453 mike     1.1 
4454                      const char T[] =
4455                        "static MI_CONST MI_ProviderFT <ALIAS>_funcs =\n"
4456                        "{\n"
4457                        "  (MI_ProviderFT_Load)<ALIAS>_Load,\n"
4458                        "  (MI_ProviderFT_Unload)<ALIAS>_Unload,\n"
4459                        "  (MI_ProviderFT_GetInstance)<GETINSTANCE>,\n"
4460                        "  (MI_ProviderFT_EnumerateInstances)<ALIAS>_EnumerateInstances,\n"
4461                        "  (MI_ProviderFT_CreateInstance)<ALIAS>_CreateInstance,\n"
4462                        "  (MI_ProviderFT_ModifyInstance)<ALIAS>_ModifyInstance,\n"
4463                        "  (MI_ProviderFT_DeleteInstance)<ALIAS>_DeleteInstance,\n"
4464                        "  (MI_ProviderFT_AssociatorInstances)<ALIAS>_AssociatorInstances,\n"
4465                        "  (MI_ProviderFT_ReferenceInstances)<ALIAS>_ReferenceInstances,\n"
4466                        "  (MI_ProviderFT_EnableIndications)NULL,\n"
4467                        "  (MI_ProviderFT_DisableIndications)NULL,\n"
4468                        "  (MI_ProviderFT_Subscribe)NULL,\n"
4469                        "  (MI_ProviderFT_Unsubscribe)NULL,\n"
4470                        "  (MI_ProviderFT_Invoke)NULL,\n"
4471                        "};\n"
4472                        "\n";
4473              
4474 mike     1.1         /* Create substitution for <GETINSTANCE> */
4475                      string gi;
4476                      if (Contains(s_options.noGetInstance, cd->name))
4477                          gi = "NULL";
4478                      else
4479                          gi = sub("<ALIAS>_GetInstance", "<ALIAS>", alias);
4480              
4481                      string r = sub(T, "<ALIAS>", alias);
4482                      r = sub(r, "<GETINSTANCE>", gi);
4483              
4484                      puts(os, r);
4485                  }
4486                  else if (cd->flags & MI_FLAG_INDICATION)
4487                  {
4488                      const char T[] =
4489                        "static MI_CONST MI_ProviderFT <ALIAS>_funcs =\n"
4490                        "{\n"
4491                        "  (MI_ProviderFT_Load)<ALIAS>_Load,\n"
4492                        "  (MI_ProviderFT_Unload)<ALIAS>_Unload,\n"
4493                        "  (MI_ProviderFT_GetInstance)NULL,\n"
4494                        "  (MI_ProviderFT_EnumerateInstances)NULL,\n"
4495 mike     1.1           "  (MI_ProviderFT_CreateInstance)NULL,\n"
4496                        "  (MI_ProviderFT_ModifyInstance)NULL,\n"
4497                        "  (MI_ProviderFT_DeleteInstance)NULL,\n"
4498                        "  (MI_ProviderFT_AssociatorInstances)NULL,\n"
4499                        "  (MI_ProviderFT_ReferenceInstances)NULL,\n"
4500                        "  (MI_ProviderFT_EnableIndications)<ALIAS>_EnableIndications,\n"
4501                        "  (MI_ProviderFT_DisableIndications)<ALIAS>_DisableIndications,\n"
4502                        "  (MI_ProviderFT_Subscribe)<ALIAS>_Subscribe,\n"
4503                        "  (MI_ProviderFT_Unsubscribe)<ALIAS>_Unsubscribe,\n"
4504                        "  (MI_ProviderFT_Invoke)NULL,\n"
4505                        "};\n"
4506                        "\n";
4507                      string r = sub(T, "<ALIAS>", alias);
4508                      puts(os, r);
4509                  }
4510                  else
4511                  {
4512                      const char T1[] =
4513                        "static MI_CONST MI_ProviderFT <ALIAS>_funcs =\n"
4514                        "{\n"
4515                        "  (MI_ProviderFT_Load)<ALIAS>_Load,\n"
4516 mike     1.1           "  (MI_ProviderFT_Unload)<ALIAS>_Unload,\n"
4517                        "  (MI_ProviderFT_GetInstance)<GETINSTANCE>,\n"
4518                        "  (MI_ProviderFT_EnumerateInstances)<ALIAS>_EnumerateInstances,\n"
4519                        "  (MI_ProviderFT_CreateInstance)<ALIAS>_CreateInstance,\n"
4520                        "  (MI_ProviderFT_ModifyInstance)<ALIAS>_ModifyInstance,\n"
4521                        "  (MI_ProviderFT_DeleteInstance)<ALIAS>_DeleteInstance,\n"
4522                        "  (MI_ProviderFT_AssociatorInstances)NULL,\n"
4523                        "  (MI_ProviderFT_ReferenceInstances)NULL,\n"
4524                        "  (MI_ProviderFT_EnableIndications)NULL,\n"
4525                        "  (MI_ProviderFT_DisableIndications)NULL,\n"
4526                        "  (MI_ProviderFT_Subscribe)NULL,\n"
4527                        "  (MI_ProviderFT_Unsubscribe)NULL,\n"
4528                        "  (MI_ProviderFT_Invoke)NULL,\n"
4529                        "};\n"
4530                        "\n";
4531                      const char T2[] =
4532                        "static MI_CONST MI_ProviderFT <ALIAS>_funcs =\n"
4533                        "{\n"
4534                        "  (MI_ProviderFT_Load)<ALIAS>_Load,\n"
4535                        "  (MI_ProviderFT_Unload)<ALIAS>_Unload,\n"
4536                        "  (MI_ProviderFT_GetInstance)NULL,\n"
4537 mike     1.1           "  (MI_ProviderFT_EnumerateInstances)NULL,\n"
4538                        "  (MI_ProviderFT_CreateInstance)NULL,\n"
4539                        "  (MI_ProviderFT_ModifyInstance)NULL,\n"
4540                        "  (MI_ProviderFT_DeleteInstance)NULL,\n"
4541                        "  (MI_ProviderFT_AssociatorInstances)NULL,\n"
4542                        "  (MI_ProviderFT_ReferenceInstances)NULL,\n"
4543                        "  (MI_ProviderFT_EnableIndications)NULL,\n"
4544                        "  (MI_ProviderFT_DisableIndications)NULL,\n"
4545                        "  (MI_ProviderFT_Subscribe)NULL,\n"
4546                        "  (MI_ProviderFT_Unsubscribe)NULL,\n"
4547                        "  (MI_ProviderFT_Invoke)NULL,\n"
4548                        "};\n"
4549                        "\n";
4550              
4551              
4552                      // Only generate intrinsics for keyless classes:
4553                      if (HasKeys(cd))
4554                      {
4555                          /* Create substitution for <GETINSTANCE> */
4556                          string gi;
4557                          if (Contains(s_options.noGetInstance, cd->name))
4558 mike     1.1                 gi = "NULL";
4559                          else
4560                              gi = sub("<ALIAS>_GetInstance", "<ALIAS>", alias);
4561              
4562                          string r = sub(T1, "<ALIAS>", alias);
4563                          r = sub(r, "<GETINSTANCE>", gi);
4564                          puts(os, r);
4565                      }
4566                      else
4567                      {
4568                          string r = sub(T2, "<ALIAS>", alias);
4569                          puts(os, r);
4570                      }
4571                  }
4572              }
4573              
4574              //==============================================================================
4575              //
4576              // GenClassDecl()
4577              //
4578              //     This function generates the class declaration for a MOF clas.
4579 mike     1.1 //
4580              //==============================================================================
4581              
4582              static void GenClassDecl(
4583                  Parser& parser,
4584                  FILE* os, 
4585                  const MI_ClassDecl* cd)
4586              {
4587                  const string alias = AliasOf(cd->name);
4588              
4589                  // Generate the qualifiers first.
4590                  size_t numQualifiers = GenQualifiers(
4591                      parser,
4592                      os, 
4593                      cd->qualifiers, 
4594                      cd->numQualifiers,
4595                      AliasOf(cd->name));
4596              
4597                  const char T[] =
4598                      "/* class <ALIAS> */\n"
4599                      "MI_CONST <STATIC>MI_ClassDecl <ALIAS>_rtti =\n"
4600 mike     1.1         "{\n"
4601                      "    <FLAGS>, /* flags */\n"
4602                      "    <CODE>, /* code */\n"
4603                      "    MI_T(\"<CLASS>\"), /* name */\n"
4604                      "    <QUALS>, /* qualifiers */\n"
4605                      "    <NQUALS>, /* numQualifiers */\n"
4606                      "    <PROPS>, /* properties */\n"
4607                      "    <NPROPS>, /* numProperties */\n"
4608                      "    sizeof(<ALIAS>), /* size */\n"
4609                      "    <SUPER>, /* superClass */\n"
4610                      "    <SUPERCLASSDECL>, /* superClassDecl */\n"
4611                      "<METHODS>"
4612                      "    &<SCHEMA>, /* schema */\n"
4613                      "    <FUNCS>, /* functions */\n"
4614 mike     1.2         "    NULL, /* owningClass */\n"
4615 mike     1.1         "};\n";
4616              
4617                  string r = T;
4618                  r = sub(r, "<ALIAS>", alias);
4619                  r = subx(r, "<CODE>", HashCode(cd->name));
4620                  r = sub(r, "<CLASS>", cd->name);
4621                  r = sub(r, "<FLAGS>", MakeFlags(cd->flags));
4622              
4623                  if (s_options.schema.size())
4624                      r = sub(r, "<SCHEMA>", s_options.schema.c_str());
4625                  else
4626                      r = sub(r, "<SCHEMA>", "schemaDecl");
4627              
4628 krisbash 1.5     r = sub(r, "<STATIC>", "");
4629 mike     1.1 
4630                  if (cd->numProperties)
4631                  {
4632                      string s = alias + "_props";
4633                      r = sub(r, "<PROPS>", s);
4634                      r = sub(r, "<NPROPS>", "MI_COUNT(" + s + ")");
4635                  }
4636                  else
4637                  {
4638                      r = sub(r, "<PROPS>", "NULL");
4639                      r = sub(r, "<NPROPS>", "0");
4640                  }
4641              
4642                  if (numQualifiers)
4643                  {
4644                      string s = alias + "_quals";
4645                      r = sub(r, "<QUALS>", s);
4646                      r = sub(r, "<NQUALS>", "MI_COUNT(" + s + ")");
4647                  }
4648                  else
4649                  {
4650 mike     1.1         r = sub(r, "<QUALS>", "NULL");
4651                      r = sub(r, "<NQUALS>", "0");
4652                  }
4653              
4654                  if (cd->superClass)
4655                  {
4656                      r = sub(r, "<SUPER>", Quote(cd->superClass));
4657                      string t = "&" + AliasOf(cd->superClass) + "_rtti";
4658                      r = sub(r, "<SUPERCLASSDECL>", t);
4659                  }
4660                  else
4661                  {
4662                      r = sub(r, "<SUPER>", "NULL");
4663                      r = sub(r, "<SUPERCLASSDECL>", "NULL");
4664                  }
4665              
4666                  if (cd->numMethods)
4667                  {
4668                      const char T2[] =
4669                          "    <ALIAS>_meths, /* methods */\n"
4670                          "    MI_COUNT(<ALIAS>_meths), /* numMethods */\n";
4671 mike     1.1         string t2 = sub(T2, "<ALIAS>", alias);
4672                      r = sub(r, "<METHODS>", t2);
4673                  }
4674                  else
4675                  {
4676                      const char T2[] =
4677                          "    NULL, /* methods */\n"
4678                          "    0, /* numMethods */\n";
4679                      r = sub(r, "<METHODS>", T2);
4680                  }
4681              
4682                  if (providerClasses.find(cd->name) == providerClasses.end())
4683                  {
4684                      r = sub(r, "<FUNCS>", "NULL");
4685                  }
4686                  else
4687                  {
4688                      r = sub(r, "<FUNCS>", "&" + alias + "_funcs");
4689                  }
4690              
4691                  puts(os, r);
4692 mike     1.1     nl(os);
4693              }
4694              
4695              //==============================================================================
4696              //
4697              // GenQualifierDecl()
4698              //
4699              //     This function generates a single qualifier declaration.
4700              //
4701              //==============================================================================
4702              
4703              static void GenQualifierDecl(FILE* os, const MI_QualifierDecl* qd)
4704              {
4705                  const char T[] =
4706                      "static MI_CONST MI_QualifierDecl <NAME>_qual_decl =\n"
4707                      "{\n"
4708                      "    MI_T(\"<NAME>\"), /* name */\n"
4709                      "    <TYPE>, /* type */\n"
4710                      "    <SCOPE>, /* scope */\n"
4711                      "    <FLAVOR>, /* flavor */\n"
4712                      "    <SUBSCRIPT>, /* subscript */\n"
4713 mike     1.1         "    <VALUE>, /* value */\n"
4714                      "};\n"
4715                      "\n";
4716              
4717                  string stem = string(qd->name) + "_qual_decl";
4718              
4719                  // Generate the value.
4720                  if (qd->value)
4721                  {
4722                      if (qd->flavor & MI_FLAG_TRANSLATABLE)
4723                          GenValue(os, stem, qd->type, qd->value, true);
4724                      else
4725                          GenValue(os, stem, qd->type, qd->value, false);
4726                  }
4727              
4728                  string r = T;
4729              
4730                  r = sub(r, "<NAME>", qd->name);
4731                  r = sub(r, "<TYPE>", MakeType(qd->type));
4732                  r = subu(r, "<SUBSCRIPT>", qd->subscript);
4733                  r = sub(r, "<FLAVOR>", MakeFlavor(qd->flavor));
4734 mike     1.1     r = sub(r, "<SCOPE>", MakeScope(qd->scope));
4735              
4736                  if (qd->value)
4737                      r = sub(r, "<VALUE>", "&" + stem + "_value");
4738                  else
4739                      r = sub(r, "<VALUE>", "NULL");
4740              
4741                  puts(os, r);
4742              }
4743              
4744              //==============================================================================
4745              //
4746              // GenQualifierDecls()
4747              //
4748              //     This function generates an array of qualifier declarations.
4749              //
4750              //==============================================================================
4751              
4752              size_t GenQualifierDecls(Parser& parser, FILE* os)
4753              {
4754                  size_t count = 0;
4755 mike     1.1 
4756                  /* Check if qualifiers are ignored */
4757                  if (s_options.ignoreAllQualifiers)
4758                      return 0;
4759              
4760                  // Put the comment box.
4761                  PutCommentBox(os, "Qualifier declarations");
4762                  nl(os);
4763              
4764                  vector<string> names;
4765                  parser.getQualifierDeclNames(names);
4766              
4767                  // Generate the individual qualifier declarations.
4768                  for (size_t i = 0; i < names.size(); i++)
4769                  {
4770                      const MI_QualifierDecl* qd = parser.findQualifierDecl(names[i]);
4771              
4772                      if (!qd)
4773                      {
4774                          err(ID_UNKNOWN_QUALIFIER, "unknown qualifier: %s", 
4775                              names[i].c_str());
4776 mike     1.1         }
4777              
4778                      // Do not generate standard qualifiers.
4779                      if (!s_options.standardQualifiers && 
4780                          FindStandardQualifierDecl(qd->name))
4781                      {
4782                          continue;
4783                      }
4784              
4785                      GenQualifierDecl(os, qd);
4786                      count++;
4787                  }
4788              
4789                  // Generate the qualifier declaration array.
4790                  if (count)
4791                  {
4792                      putl(os, 
4793                          "static MI_QualifierDecl MI_CONST* MI_CONST qualifierDecls[] =");
4794                      putl(os, "{");
4795              
4796                      for (size_t i = 0; i < names.size(); i++)
4797 mike     1.1         {
4798                          const MI_QualifierDecl* qd = parser.findQualifierDecl(names[i]);
4799              
4800                          // Do not generate standard qualifiers.
4801                          if (!s_options.standardQualifiers && 
4802                              FindStandardQualifierDecl(qd->name))
4803                          {
4804                              continue;
4805                          }
4806              
4807                          if (!qd)
4808                          {
4809                              err(ID_UNKNOWN_QUALIFIER, "unknown qualifier: %s", 
4810                                  names[i].c_str());
4811                          }
4812              
4813                          put(os, "    &%s_qual_decl,\n", qd->name);
4814                      }
4815              
4816                      putl(os, "};");
4817                      nl(os);
4818 mike     1.1     }
4819              
4820                  return count;
4821              }
4822              
4823              //==============================================================================
4824              //
4825              // GenClassSchema()
4826              //
4827              //     This function generates one class for the schema source file.
4828              //
4829              //==============================================================================
4830              
4831              static void GenClassSchema(
4832                  Parser& parser,
4833                  FILE* os,
4834                  const MI_ClassDecl* cd,
4835                  const vector<string>& classNames)
4836              {
4837                  // Prevent recursion.
4838                  {
4839 mike     1.1         if (s_generated.find(cd->name) != s_generated.end())
4840                          return;
4841              
4842                      s_generated.insert(cd->name);
4843                  }
4844              
4845                  // Find direct dependencies of this class.
4846                  vector<string> deps;
4847                  FindDirectDependencies(cd, deps);
4848              
4849                  // Recurse on dependencies.
4850                  for (size_t i = 0; i < deps.size(); i++)
4851                  {
4852                      const MI_ClassDecl* tcd = parser.findClassDecl(deps[i].c_str());
4853              
4854                      if (!tcd)
4855                          err(ID_UNKNOWN_CLASS, "unknown class: %s", deps[i].c_str());
4856              
4857                      GenClassSchema(parser, os, tcd, classNames);
4858                  }
4859              
4860 mike     1.1     // Refuse to generate same class more than once.
4861                  if (generated_classes.find(cd->name) != generated_classes.end())
4862                      return;
4863              
4864                  generated_classes.insert(cd->name);
4865              
4866                  // Generate comment box for this class.
4867                  const string al = AliasOf(cd->name);
4868                  PutCommentBox(os, al);
4869                  nl(os);
4870              
4871                  // Generate declarations.
4872                  GenPropertyDecls(parser, os, cd);
4873              
4874                  // Generate method declarations.
4875                  GenMethodDecls(parser, os, cd);
4876              
4877                  // Generate provider function table.
4878                  if (providerClasses.find(cd->name) != providerClasses.end())
4879                      GenFunctionTable(os, cd);
4880              
4881 mike     1.1     // Generate the class declaration.
4882                  GenClassDecl(parser, os, cd);
4883              }
4884              
4885              //==============================================================================
4886              //
4887              // GenSchemaSourceFile()
4888              //
4889              //     This function generates the schema.c source file, which contains the
4890              //     qualifier declarations, class declarations, and the schema object that
4891              //     refers to arrays of each.
4892              //
4893              //==============================================================================
4894              
4895              static void GenSchemaSourceFile(
4896                  Parser& parser,
4897                  const vector<string>& classNames,
4898                  const set<string>& /*classIdentifiers*/)
4899              {
4900                  // Open the file.
4901                  string path = ExpandPath("schema.c");
4902 mike     1.1 
4903 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
4904 mike     1.1 
4905                  if (!os)
4906                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
4907              
4908                  GenStatikGenLine(os);
4909              
4910                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
4911              
4912                  // Print warning box.
4913                  PutCommentBox(os, WARNING);
4914              
4915                  // Include <MI.h> header.
4916                  putl(os, "#include <ctype.h>");
4917                  putl(os, "#include <MI.h>");
4918              
4919                  bool generateMatch = false;
4920              
4921                  // Include each direct header file (headers will indirectly include others).
4922                  for (size_t i = 0; i < classNames.size(); i++)
4923                  {
4924                      // Find the class.
4925 mike     1.1         const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str());
4926              
4927                      if (!cd)
4928                          err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str());
4929              
4930 krisbash 1.5         if (cd->flags & MI_FLAG_ASSOCIATION)
4931 mike     1.1         {
4932 krisbash 1.5             if (CanGenerateAssocRoles(cd))
4933                          {
4934                              if (!s_options.association)
4935                                  generateMatch = true;
4936                          }
4937                          else
4938                              errRefPropCount(cd->name);
4939 mike     1.1         }
4940              
4941                      // Include the class header.
4942                      const string alias = AliasOf(cd->name);
4943                      putl(os, "#include \"%s.h\"", alias.c_str());
4944                  }
4945              
4946                  nl(os);
4947              
4948                  // Generate forward reference to schema declaration.
4949                  {
4950                      PutCommentBox(os, "Schema Declaration");
4951                      nl(os);
4952              
4953                      if (s_options.schema.size())
4954                          putl(os, "extern MI_SchemaDecl %s;", s_options.schema.c_str());
4955                      else
4956                          putl(os, "extern MI_SchemaDecl schemaDecl;");
4957              
4958                      nl(os);
4959                  }
4960 mike     1.1 
4961                  // Generate match function (if necessary)
4962                  if (generateMatch)
4963                  {
4964                      const char MATCH[] =
4965                          "static int _Match(const MI_Char* p, const MI_Char* q)\n"
4966                          "{\n"
4967                          "    if (!p || !q || !p[0] || !q[0])\n"
4968                          "        return 1;\n"
4969                          "\n"
4970                          "    while (*p && *q)\n"
4971                          "        if (toupper((MI_Uint16)*p++) - toupper((MI_Uint16)*q++))\n"
4972                          "            return 0;\n"
4973                          "\n"
4974                          "    return *p == '\\0' && *q == '\\0';\n"
4975                          "}\n"
4976                          "\n";
4977              
4978                      PutCommentBox(os, "_Match()");
4979                      nl(os);
4980                      puts(os, MATCH);
4981 mike     1.1     }
4982              
4983                  // Gen qualifier declarations.
4984                  size_t numQualifierDecls = GenQualifierDecls(parser, os);
4985              
4986                  // Generate class declarations.
4987                  for (size_t i = 0; i < classNames.size(); i++)
4988                  {
4989                      // Find the class.
4990                      const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str());
4991              
4992                      if (!cd)
4993                          err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str());
4994              
4995                      GenClassSchema(parser, os, cd, classNames);
4996                  }
4997              
4998                  // Generate server declaration.
4999                  PutCommentBox(os, "__mi_server");
5000                  nl(os);
5001                  putl(os, "MI_Server* __mi_server;");
5002 mike     1.1 
5003                  // Generate MI_SchemaDecl.
5004              
5005                  PutCommentBox(os, "Schema");
5006                  nl(os);
5007              
5008                  putl(os, "static MI_ClassDecl MI_CONST* MI_CONST classes[] =");
5009                  putl(os, "{");
5010              
5011                  set<string>::const_iterator p = generated_classes.begin();
5012                  set<string>::const_iterator end = generated_classes.end();
5013              
5014                  for (; p != end; p++)
5015                  {
5016                      // Find the class.
5017                      const MI_ClassDecl* cd = 
5018                          parser.findClassDecl((*p).c_str());
5019              
5020                      if (!cd)
5021                          err(ID_UNKNOWN_CLASS, "unknown class: %s", (*p).c_str());
5022              
5023 mike     1.1         const string alias = AliasOf(cd->name);
5024                      putl(os, "    &%s_rtti,", alias.c_str());
5025                  }
5026              
5027                  putl(os, "};");
5028                  nl(os);
5029              
5030                  {
5031                      static const char T[] =
5032                          "MI_SchemaDecl <SCHEMADECL> =\n"
5033                          "{\n"
5034                          "    <QUALIFIERDECLS>, /* qualifierDecls */\n"
5035                          "    <NUMQUALIFIERDECLS>, /* numQualifierDecls */\n"
5036                          "    classes, /* classDecls */\n"
5037                          "    MI_COUNT(classes), /* classDecls */\n"
5038                          "};\n"
5039                          "\n";
5040              
5041                      string r = T;
5042              
5043                      if (s_options.schema.size())
5044 mike     1.1             r = sub(r, "<SCHEMADECL>", s_options.schema);
5045                      else
5046                          r = sub(r, "<SCHEMADECL>", "schemaDecl");
5047              
5048                      if (numQualifierDecls)
5049                      {
5050                          r = sub(r, "<QUALIFIERDECLS>", "qualifierDecls");
5051                          r = sub(r, "<NUMQUALIFIERDECLS>", "MI_COUNT(qualifierDecls)");
5052                      }
5053                      else
5054                      {
5055                          r = sub(r, "<QUALIFIERDECLS>", "NULL");
5056                          r = sub(r, "<NUMQUALIFIERDECLS>", "0");
5057                      }
5058              
5059                      puts(os, r);
5060                  }
5061              
5062                  // Generate MI_Server methods.
5063 krisbash 1.5     if (!s_options.noProviders)
5064 mike     1.1     {
5065                      const char T[] =
5066                          "MI_Result MI_CALL MI_Server_GetVersion(\n"
5067                          "    MI_Uint32* version)"
5068                          "{\n"
5069                          "    return __mi_server->serverFT->GetVersion(version);\n"
5070                          "}\n"
5071                          "\n"
5072                          "MI_Result MI_CALL MI_Server_GetSystemName(\n"
5073                          "    const MI_Char** systemName)\n"
5074                          "{\n"
5075                          "    return __mi_server->serverFT->GetSystemName(systemName);\n"
5076                          "}\n";
5077              
5078                      PutCommentBox(os, "MI_Server Methods");
5079                      nl(os);
5080                      puts(os, T);
5081                      nl(os);
5082                  }
5083              
5084              #if 0
5085 mike     1.1     // Generate cross-check with class identifiers:
5086                  {
5087                      set<string>::const_iterator first = classIdentifiers.begin();
5088                      set<string>::const_iterator last = classIdentifiers.end();
5089              
5090                      while (first != last)
5091                      {
5092                          const string& s = *first++;
5093                          putl(os, "#ifndef %s", s.c_str());
5094                          putl(os, "# error \"generational inconsistency: %s is undefined\"", 
5095                              s.c_str());
5096                          putl(os, "#endif\n");
5097                      }
5098                  }
5099              #endif
5100              
5101                  // Close the file.
5102                  fclose(os);
5103              }
5104              
5105              //==============================================================================
5106 mike     1.1 //
5107              // GenerateMI_Main()
5108              //
5109              //     This function generates the MI_Main() entry point. It returns a 
5110              //     string instead of writing to the output stream directory. This is to
5111              //     support patching of module.c.
5112              //
5113              //==============================================================================
5114              
5115              string GenerateMI_Main()
5116              {
5117                  string result;
5118              
5119                  // MI_Main() preamble:
5120                  {
5121                      string r = MODULE_C_TEMPLATE_2;
5122              
5123                      if (s_options.schema.size()) 
5124                          r = sub(r, "<SCHEMADECL>", s_options.schema);
5125                      else
5126                          r = sub(r, "<SCHEMADECL>", "schemaDecl");
5127 mike     1.1 
5128                      if (s_options.entryPoint.size()) 
5129                          r = sub(r, "<ENTRYPOINT>", s_options.entryPoint);
5130                      else
5131                          r = sub(r, "<ENTRYPOINT>", "MI_Main");
5132              
5133                      result += r;
5134                  }
5135              
5136                  // MI_Main() flags:
5137                  {
5138                      string r;
5139              
5140                      if (!s_options.ignoreAllQualifiers)
5141                      {
5142                          if (!s_options.standardQualifiers)
5143                              r += "    module.flags |= MI_MODULE_FLAG_STANDARD_QUALIFIERS;\n";
5144              
5145                          if (s_options.descriptions)
5146                              r += "    module.flags |= MI_MODULE_FLAG_DESCRIPTIONS;\n";
5147              
5148 mike     1.1             if (s_options.values)
5149                              r += "    module.flags |= MI_MODULE_FLAG_VALUES;\n";
5150              
5151                          if (s_options.mappingStrings)
5152                              r += "    module.flags |= MI_MODULE_FLAG_MAPPING_STRINGS;\n";
5153              
5154                          if (s_options.booleanQualifiers)
5155                              r += "    module.flags |= MI_MODULE_FLAG_BOOLEANS;\n";
5156                      }
5157              
5158                      if (s_options.cpp)
5159                          r += "    module.flags |= MI_MODULE_FLAG_CPLUSPLUS;\n";
5160              
5161                      if (s_options.localize)
5162                          r += "    module.flags |= MI_MODULE_FLAG_LOCALIZED;\n";
5163              
5164                      if (s_options.filterSupport)
5165                          r += "    module.flags |= MI_MODULE_FLAG_FILTER_SUPPORT;\n";
5166              
5167                      result += r;
5168                  }
5169 mike     1.1 
5170                  // MI_Main() postamble:
5171                  {
5172                      string r = MODULE_C_TEMPLATE_3;
5173              
5174                      if (s_options.schema.size()) 
5175                          r = sub(r, "<SCHEMADECL>", s_options.schema);
5176                      else
5177                          r = sub(r, "<SCHEMADECL>", "schemaDecl");
5178              
5179                      {
5180                          char buf[64];
5181                          Snprintf(buf, MI_COUNT(buf), "MI_MAKE_VERSION(%u,%u,%u)", 
5182 krisbash 1.5                 MI_MAJOR, MI_MINOR, MI_REVISION);
5183 mike     1.1             r = sub(r, "<VERSION>", buf);
5184                      }
5185              
5186                      result += r;
5187                  }
5188              
5189                  return result;
5190              }
5191              
5192              //==============================================================================
5193              //
5194              // SkipSpace()
5195              //
5196              //     Skip over whitespace. Return true when the '\0' character is found.
5197              //
5198              //==============================================================================
5199              
5200              static bool SkipSpace(const char*& p)
5201              {
5202                  while (isspace((unsigned char)*p))
5203                      p++;
5204 mike     1.1 
5205                  return *p == '\0';
5206              }
5207              
5208              //==============================================================================
5209              //
5210              // GenModuleSourceFile()
5211              //
5212              //     This function generates the module.c source file, which contains the
5213              //     MI_Main() entry point.
5214              //
5215              //==============================================================================
5216              
5217              static void GenModuleSourceFile()
5218              {
5219                  // Open the file.
5220                  const string path = ExpandPath("module.c");
5221              
5222                  if (Exists(path.c_str()))
5223                  {
5224                      // Read file into memory.
5225 mike     1.1         vector<char> data;
5226              
5227                      if (!Inhale(path.c_str(), data))
5228                      {
5229                          err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
5230                              path.c_str());
5231                      }
5232              
5233              
5234                      // Replace MI_Main() body with new MI_Main() body.
5235                      const char* start = &data[0];
5236                      const char* end = &data[data.size()-1];
5237                      const char* p = start;
5238                      bool found = false;
5239              
5240                      // Match "MI_EXTERN_C MI_EXPORT MI_Module* MI_MAIN_CALL MI_Main(...) {}
5241                      while (p != end)
5242                      {
5243                          const char* first = p;
5244              
5245                          // Expect 'MI_EXTERN_C' [optionally]
5246 mike     1.1             if (strncmp(p, "MI_EXTERN_C", 11) == 0)
5247                          {
5248                              p += 11;
5249              
5250                              // Skip whitespace:
5251                              if (SkipSpace(p))
5252                                  break;
5253                          }
5254              
5255                          // Expect 'MI_EXPORT'
5256                          if (strncmp(p, "MI_EXPORT", 9) != 0)
5257                          {
5258                              p++;
5259                              continue;
5260                          }
5261                          p += 9;
5262              
5263                          // Skip whitespace:
5264                          if (SkipSpace(p))
5265                              break;
5266              
5267 mike     1.1             // Expect 'MI_Module'
5268                          if (strncmp(p, "MI_Module", 9) != 0)
5269                          {
5270                              p++;
5271                              continue;
5272                          }
5273                          p += 9;
5274              
5275                          // Skip whitespace:
5276                          if (SkipSpace(p))
5277                              break;
5278              
5279                          // Expect '*'
5280                          if (*p != '*')
5281                          {
5282                              p++;
5283                              continue;
5284                          }
5285                          p++;
5286              
5287                          // Skip whitespace:
5288 mike     1.1             if (SkipSpace(p))
5289                              break;
5290              
5291                          // Skip 'MI_MAIN_CALL'
5292                          {
5293                              const char TMP[] = "MI_MAIN_CALL";
5294              
5295                              if (strncmp(p, TMP, sizeof(TMP)-1) == 0)
5296                                  p += sizeof(TMP)-1;
5297                          }
5298              
5299                          // Skip whitespace:
5300                          if (SkipSpace(p))
5301                              break;
5302              
5303                          // Expect 'MI_Main'
5304                          {
5305                              const char *TMP = 
5306                                  (s_options.entryPoint.empty() ? "MI_Main" : s_options.entryPoint.c_str());
5307              
5308                              if (strncmp(p, TMP, strlen(TMP)) != 0)
5309 mike     1.1                 {
5310                                  p++;
5311                                  continue;
5312                              }
5313                              p += strlen(TMP);
5314                          }
5315              
5316                          // Skip whitespace:
5317                          if (SkipSpace(p))
5318                              break;
5319              
5320                          // Expect '('
5321                          if (*p != '(')
5322                          {
5323                              p++;
5324                              continue;
5325                          }
5326              
5327                          // Skip non ')' chars.
5328                          while (*p && *p != ')')
5329                              p++;
5330 mike     1.1 
5331                          // Expect ')'
5332                          if (*p != ')')
5333                          {
5334                              p++;
5335                              continue;
5336                          }
5337                          p++;
5338              
5339                          // Skip whitespace:
5340                          if (SkipSpace(p))
5341                              break;
5342              
5343                          // Expect '{'
5344                          if (*p != '{')
5345                          {
5346                              p++;
5347                              continue;
5348                          }
5349              
5350                          // Skip non '}' chars.
5351 mike     1.1             while (*p && *p != '}')
5352                              p++;
5353              
5354                          // Expect '}'
5355                          if (*p != '}')
5356                          {
5357                              p++;
5358                              continue;
5359                          }
5360                          p++;
5361              
5362                          const char* last = p;
5363              
5364                          found = true;
5365                          string tmp = &data[0];
5366                          string r;
5367                          r.append(start, first - start);
5368                          r.append(GenerateMI_Main());
5369                          r.append(last);
5370              
5371                          // Rewrite the file.
5372 mike     1.1             {
5373 krisbash 1.5                 FILE* os = File_Open(path.c_str(), "w");
5374 mike     1.1 
5375                              if (!os)
5376                              {
5377                                  err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", 
5378                                      path.c_str());
5379                              }
5380              
5381                              Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str());
5382                              put(os, "%s", r.c_str());
5383              
5384                              fclose(os);
5385                          }
5386                          break;
5387                      }
5388              
5389                      // If MI_Main() not found.
5390                      if (!found)
5391                      {
5392                          err(ID_FAILED_TO_PATCH_MODULE, 
5393                              "Unable to patch module.c: cannot find %s() body: %s",
5394                              (s_options.entryPoint.empty() ? 
5395 mike     1.1                     "MI_Main" : s_options.entryPoint.c_str()),
5396                              path.c_str());
5397                      }
5398              
5399                      return;
5400                  }
5401              
5402 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
5403 mike     1.1     
5404                  if (!os)
5405                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
5406              
5407                  GenStatikGenLine(os);
5408                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
5409              
5410                  // Generate part 1:
5411                  {
5412                      string r = MODULE_C_TEMPLATE_1;
5413              
5414                      if (s_options.schema.size()) 
5415                          r = sub(r, "<SCHEMADECL>", s_options.schema);
5416                      else
5417                          r = sub(r, "<SCHEMADECL>", "schemaDecl");
5418              
5419                      put(os, "%s", r.c_str());
5420                  }
5421              
5422                  // Generate MI_Main()
5423                  {
5424 mike     1.1         string r = GenerateMI_Main();
5425                      put(os, "%s\n", r.c_str());
5426                  }
5427              
5428                  // Close the file.
5429                  fclose(os);
5430              }
5431              
5432              //==============================================================================
5433              //
5434              // GenModuleCppSourceFile()
5435              //
5436              //     This function generates the module.cpp source file, which contains the
5437              //     Module class definiiton.
5438              //
5439              //==============================================================================
5440              
5441              static void GenModuleCppSourceFile()
5442              {
5443                  // Open the file.
5444                  const string path = ExpandPath("module.cpp");
5445 mike     1.1 
5446                  if (Exists(path.c_str()))
5447                  {
5448                      Fprintf(s_stdout, ID_SKIPPING, "Skipping %s\n", path.c_str());
5449                      return;
5450                  }
5451              
5452 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
5453 mike     1.1     
5454                  if (!os)
5455                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
5456              
5457                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
5458              
5459                  // simple template - no parameters
5460                  {
5461                      put(os, "%s\n", MODULE_CPP_TEMPLATE);
5462                  }
5463              
5464                  // Close the file.
5465                  fclose(os);
5466              }
5467              
5468              //==============================================================================
5469              //
5470              // GenModuleCppHeaderFile()
5471              //
5472              //     This function generates the module.h header file, which contains the
5473              //     Module class declaration.
5474 mike     1.1 //
5475              //==============================================================================
5476              
5477              static void GenModuleCppHeaderFile()
5478              {
5479                  // Open the file.
5480                  const string path = ExpandPath("module.h");
5481              
5482                  if (Exists(path.c_str()))
5483                  {
5484                      Fprintf(s_stdout, ID_SKIPPING, "Skipping %s\n", path.c_str());
5485                      return;
5486                  }
5487              
5488 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
5489 mike     1.1     
5490                  if (!os)
5491                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
5492              
5493                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
5494              
5495                  // simple template - no parameters
5496                  {
5497                      put(os, "%s\n", MODULE_H_TEMPLATE);
5498                  }
5499              
5500                  // Close the file.
5501                  fclose(os);
5502              }
5503              
5504              //==============================================================================
5505              //
5506              // GenModuleStubsFile()
5507              //
5508              //     This function generates the stubs.cpp source file, which contains the
5509              //     wrapper functions to convert 'c' style server calls into provider class 
5510 mike     1.1 //     calls
5511              //
5512              //==============================================================================
5513              
5514              static void GenModuleStubsFile(
5515                  Parser& parser,
5516                  const vector<string>& classNames)
5517              {
5518                  // Open the file.
5519                  string path = ExpandPath("stubs.cpp");
5520              
5521 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
5522 mike     1.1 
5523                  if (!os)
5524                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
5525              
5526                  GenStatikGenLine(os);
5527              
5528                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
5529              
5530                  // Print warning box.
5531                  PutCommentBox(os, WARNING);
5532              
5533                  // Include <MI.h> header.
5534                  putl(os, "#include <MI.h>");
5535                  putl(os, "#include \"module.h\"");
5536              
5537                  // Include each direct header file (headers will indirectly include others).
5538                  for (size_t i = 0; i < classNames.size(); i++)
5539                  {
5540                      // Find the class.
5541                      const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str());
5542              
5543 mike     1.1         if (!cd)
5544                          err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str());
5545              
5546                      /* skip not-requested classes */
5547                      if (providerClasses.find(cd->name) == providerClasses.end())
5548                          continue;
5549              
5550                      // Include the class header.
5551                      const string alias = AliasOf(cd->name);
5552                      putl(os, "#include \"%s_Class_Provider.h\"", alias.c_str());
5553                  }
5554              
5555                  nl(os);
5556                  putl(os, "using namespace mi;");
5557                  nl(os);
5558              
5559                  // generate c++ wrappers
5560                  for (size_t i = 0; i < classNames.size(); i++)
5561                  {
5562                      // Find the class.
5563                      const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str());
5564 mike     1.1 
5565                      if (!cd)
5566                          err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str());
5567              
5568                      /* skip not-requested classes */
5569                      if (providerClasses.find(cd->name) == providerClasses.end())
5570                          continue;
5571              
5572                      // generate stub for the class
5573                      GenerateClassStub( os, cd );
5574                  }
5575              
5576                  // Generate module-level load/unload
5577                  {
5578                      string r = STUBS_LOAD_UNLOAD_TEMPLATE;
5579              
5580                      if (s_options.schema.size()) 
5581                          r = sub(r, "<SCHEMADECL>", s_options.schema);
5582                      else
5583                          r = sub(r, "<SCHEMADECL>", "schemaDecl");
5584              
5585 mike     1.1         put(os, "%s", r.c_str());
5586                  }
5587              
5588                  // Generate MI_Main()
5589                  {
5590                      string r = GenerateMI_Main();
5591                      put(os, "%s\n", r.c_str());
5592                  }
5593              
5594                  nl(os);
5595              
5596                  // Close the file.
5597                  fclose(os);
5598              }
5599              
5600              //==============================================================================
5601              //
5602              // GenerateStringsFile()
5603              //
5604              //     This function generates the string.rc file, which contains the
5605              //     localized qualifier strings (only called if -l option present)
5606 mike     1.1 //
5607              //==============================================================================
5608              
5609              static void GenerateStringsFile()
5610              {
5611                  // Open the file.
5612                  const string path = ExpandPath("strings.rc");
5613 krisbash 1.5     FILE* os = File_Open(path.c_str(), "w");
5614 mike     1.1     
5615                  if (!os)
5616                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
5617              
5618                  GenStatikGenLine(os);
5619                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
5620              
5621                  // Generate file with the following format.
5622                  //
5623                  //     STRINGTABLE
5624                  //     {
5625                  //         <INTEGER-IDENTIFIER>, <STRING>
5626                  //     }
5627                  {
5628                      fprintf(os, "STRINGTABLE\n");
5629                      fprintf(os, "{\n");
5630              
5631                      for (size_t i = 0; i < s_localizations.size(); i++)
5632                      {
5633                          MI_Uint32 id = (MI_Uint32)(i + 1);
5634                          const string& str = s_localizations[i];
5635 mike     1.1             fprintf(os, "    %u, \"%s\"\n", id, str.c_str());
5636                      }
5637              
5638                      fprintf(os, "}\n");
5639                  }
5640              
5641                  // Close the file.
5642                  fclose(os);
5643              }
5644              
5645              static string _GetClassInheritanceRegistrationEntry(
5646                  const MI_ClassDecl* cd
5647                  )
5648              {
5649                  string res = cd->name;
5650              
5651                  while (cd->superClassDecl)
5652                  {
5653                      res += ",";
5654                      cd = cd->superClassDecl;
5655                      res += cd->name;
5656 mike     1.1     }
5657              
5658                  return res;
5659              }
5660              
5661              static string _GetClassRegistrationEntry(
5662                  Parser& parser,
5663                  const MI_ClassDecl* cd
5664                  )
5665              {
5666                  string res;
5667              
5668                  if (cd->flags & MI_FLAG_ASSOCIATION)
5669                  {
5670                      const MI_ClassDecl* cd_left = 0, *cd_right = 0;
5671                      // find two ref members
5672                      for (MI_Uint32 i = 0; i < cd->numProperties; i++)
5673                      {
5674                          if (cd->properties[i]->type == MI_REFERENCE)
5675                          {
5676                              const MI_ClassDecl* cd_ref = 
5677 mike     1.1                     parser.findClassDecl(cd->properties[i]->className);
5678              
5679                              if (!cd_ref)
5680                              {
5681                                  err(ID_UNKNOWN_CLASS, "unknown class: %s", 
5682                                      cd->properties[i]->className);
5683                              }
5684              
5685                              if (!cd_left)
5686                                  cd_left = cd_ref;
5687                              else
5688                                  cd_right = cd_ref;
5689                          }
5690                      }
5691              
5692                      if (!cd_right)
5693 krisbash 1.5             errRefPropCount(cd->name);
5694 mike     1.1 
5695                      res = _GetClassInheritanceRegistrationEntry(cd_left) +
5696                          "+" +
5697                          _GetClassInheritanceRegistrationEntry(cd) + 
5698                          "+" +
5699                          _GetClassInheritanceRegistrationEntry(cd_right);
5700                  }
5701                  else
5702                  {
5703                      res = _GetClassInheritanceRegistrationEntry(cd);
5704                  }
5705                  return res;
5706              }
5707              
5708              //==============================================================================
5709              //
5710              // GenerateRegistryFile()
5711              //
5712              //     This function generates skeleton of the provider registry file, 
5713              //     which contains information server will use to operate with provider 
5714              //     (only called if -reg option present)
5715 mike     1.1 //
5716              //==============================================================================
5717              
5718              static void GenerateRegistryFile( 
5719                  Parser& parser, 
5720                  const vector<string>& classNames)
5721              {
5722                  // Open the file.
5723                  const string path = ExpandPath(s_options.providerRegistryPath);
5724 krisbash 1.5     FILE* os = File_Open(path.c_str(), "a");
5725 mike     1.1     
5726                  if (!os)
5727                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str());
5728              
5729                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str());
5730              
5731                  // Generate file with the following format.
5732                  //
5733                  //     statik:test/c:MSFT_Person,MSFT_Animal,MSFT_Base + MSFT_Friends + 
5734                  //     MSFT_Person,MSFT_Animal,MSFT_Base:PersonProvider
5735                  //
5736                  {
5737                      fprintf(os, "# auto-generated skeleton of registry file\n");
5738                      fprintf(os, "# please update it with correct namespace[s]\n");
5739              
5740                      for (size_t i = 0; i < classNames.size(); i++)
5741                      {
5742                          const char* cn = classNames[i].c_str();
5743                          const MI_ClassDecl* cd = parser.findClassDecl(cn);
5744              
5745                          if (!cd)
5746 mike     1.1                 err(ID_UNKNOWN_CLASS, "unknown class: %s", cn);
5747              
5748                          fprintf(os, "statik:<ns>:%s:<provider>\n",
5749                              _GetClassRegistrationEntry(parser,cd).c_str());
5750              
5751                      }
5752              
5753                      for (size_t i = 0; i < s_localizations.size(); i++)
5754                      {
5755                          MI_Uint32 id = (MI_Uint32)(i + 1);
5756                          const string& str = s_localizations[i];
5757                          fprintf(os, "    %u, \"%s\"\n", id, str.c_str());
5758                      }
5759              
5760                      fprintf(os, "\n");
5761                  }
5762              
5763                  // Close the file.
5764                  fclose(os);
5765              }
5766              
5767 mike     1.1 //==============================================================================
5768              //
5769              // GenMakefile()
5770              //
5771              //     This function generates a 'GNUmakefile' for the given provider.
5772              //
5773              //==============================================================================
5774              
5775              static void GenMakefile(
5776                  const string& library,
5777                  const vector<string>& classNames,
5778                  const string& cmdLine)
5779              {
5780                  const char MAKEFILE[] = "GNUmakefile";
5781              
5782                  MI_UNUSED(library);
5783              
5784                  // If makefile already exists, quit:
5785                  if (Exists(MAKEFILE))
5786                  {
5787                      Fprintf(s_stdout, ID_SKIPPING, "Skipping %s\n", MAKEFILE);
5788 mike     1.1         return;
5789                  }
5790              
5791                  // Open Makefile:
5792 krisbash 1.5     FILE* os = File_Open(MAKEFILE, "w");
5793 mike     1.1     if (!os)
5794                      err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", MAKEFILE);
5795              
5796                  {
5797                      // 'OMIMAK' variable.
5798 krisbash 1.5         string OMIMAK = string(OMI_GetPath(ID_DATADIR)) + "/omi.mak";
5799 mike     1.1 
5800                      // 'PROVIDER' variable.
5801                      string PROVIDER = s_options.providerName;
5802              
5803                      // 'SOURCES' variable.
5804                      string SOURCES;
5805                      {
5806                          if (s_options.cpp)
5807                              SOURCES = "$(wildcard *.c *.cpp)";
5808                          else
5809                              SOURCES = "$(wildcard *.c)";
5810                      }
5811              
5812                      // 'CLASSNAMES' variable.
5813                      string CLASSES;
5814                      {
5815                          for (size_t i = 0; i < classNames.size(); i++)
5816                          {
5817                              CLASSES += classNames[i];
5818                              if (i + 1 == classNames.size())
5819                                  CLASSES += ' ';
5820 mike     1.1             }
5821                      }
5822              
5823                      string r;
5824              
5825                      if (s_options.cpp)
5826                          r = CXXMAKEFILE_TEMPLATE;
5827                      else
5828                          r = CMAKEFILE_TEMPLATE;
5829              
5830                      r = sub(r, "<OMIMAK>", OMIMAK);
5831                      r = sub(r, "<PROVIDER>", PROVIDER);
5832                      r = sub(r, "<SOURCES>", SOURCES);
5833                      r = sub(r, "<CLASSES>", CLASSES);
5834                      r = sub(r, "<CMDLINE>", cmdLine);
5835 krisbash 1.5         r = subu(r, "<MIAPIVERSION>", _MIAPIVERSION);
5836 mike     1.1         puts(os, r);
5837                  }
5838              
5839                  // Print creation message:
5840                  Fprintf(s_stdout, ID_CREATING, "Creating %s\n", MAKEFILE);
5841              
5842                  // Close file:
5843                  fclose(os);
5844              }
5845              //==============================================================================
5846              //
5847              // main()
5848              //
5849              //     This program generates source code from MOF definitions. The source 
5850              //     includes run-time type information for class declarations and qualifier
5851              //     declarations as well as class provider stubs.
5852              //
5853              //==============================================================================
5854              
5855              int GeneratorMain(
5856                  const std::string& programNameArg,
5857 mike     1.1     const std::vector<std::string>& mofFilesArg,
5858                  const std::vector<std::string>& classNamesArg,
5859                  const GeneratorOptions& optionsArg)
5860              {
5861                  arg0 = programNameArg.c_str();
5862              
5863                  // Make a copy of the vector whose strings we can later modify in place.
5864                  vector<string> localClassNamesArg;
5865                  {
5866                      for (size_t i = 0; i < classNamesArg.size(); i++)
5867                          localClassNamesArg.push_back(classNamesArg[i].c_str());
5868                  }
5869              
5870              #ifdef WIN32
5871 krisbash 1.5     // Platform-specific trick to get compatible float format
5872 mike     1.1     _set_output_format(_TWO_DIGIT_EXPONENT);
5873              #endif
5874              
5875                  // clear global params 
5876                  generated_headers.clear();
5877                  generated_classes.clear();
5878                  providerClasses.clear();
5879                  s_generated.clear();
5880                  aliases.clear();
5881                  s_localizations.clear();
5882              
5883                  // Save command-line options.
5884                  s_options = optionsArg;
5885              
5886                  // Create directory given by -d option.
5887                  if (s_options.dir.size())
5888                      Mkdir(s_options.dir.c_str(), 0777);
5889              
5890                  // Check schema given by -s otpion.
5891                  if (s_options.schema.size())
5892                  {
5893 mike     1.1         /* Check whether this is a valid C identifier */
5894                      if (!ValidIdent(s_options.schema))
5895                          err(ID_INVALID_SCHEMA_OPTION, "invalid schema option: %s", 
5896                              s_options.schema.c_str());
5897                  }
5898              
5899                  if ( s_options.quiet )
5900                  {
5901 krisbash 1.5         s_stdout = File_Open(NULL_FILE, "a");
5902 mike     1.1     }
5903                  else
5904                  {
5905                      s_stdout = stdout;
5906                  }
5907              
5908                  // Create the parser.
5909 krisbash 1.5     Parser parser(s_options.paths, !s_options.no_warnings);
5910 mike     1.1 
5911                  // Parse all the MOF files.
5912                  for (size_t i = 0; i < mofFilesArg.size(); i++)
5913                  {
5914                      const char* path = mofFilesArg[i].c_str();
5915              
5916                      if (parser.parse(path) != 0)
5917                      {
5918                          err(ID_FAILED_TO_PARSE_MOF_FILE, "failed to parse MOF file: %s",
5919                              path);
5920                      }
5921                  }
5922              
5923                  // Build the alias table, which maps a MOF classname to an alias name.
5924                  // Aliases are introduced by command-line classname arguments of the 
5925                  // form <CLASSNAME>=<ALIAS>. For each command line argument of this
5926                  // form, put an entry in the alias table. Use the lexographical case
5927                  // for the class define in MOF (rather than defined on the command line).
5928                  for (size_t i = 0; i < localClassNamesArg.size(); i++)
5929                  {
5930                      const char* className = localClassNamesArg[i].c_str();
5931 mike     1.1         char* alias = (char*)strchr(className, '=');
5932              
5933                      if (alias)
5934                      {
5935                          *alias++ = '\0';
5936              
5937                          const MI_ClassDecl* cd = parser.findClassDecl(className);
5938              
5939                          if (!cd)
5940                              err(ID_UNKNOWN_CLASS, "unknown class: %s", className);
5941              
5942                          aliases[cd->name] = alias;
5943                      }
5944                  }
5945              
5946                  // Form a complete list of class names (excluding duplicates).
5947              
5948                  vector<string> classNames;
5949              
5950                  if (s_options.all)
5951                  {
5952 mike     1.1         parser.getClassNames(classNames);
5953                  }
5954                  else
5955                  {
5956                      for (size_t i = 0; i < localClassNamesArg.size(); i++)
5957                      {
5958                          const char* className = localClassNamesArg[i].c_str();
5959                          const MI_ClassDecl* cd = parser.findClassDecl(className);
5960              
5961                          if (!cd)
5962                              err(ID_UNKNOWN_CLASS, "unknown, class: %s", className);
5963              
5964                          // Save class name.
5965                          if (!Contains(classNames, cd->name))
5966                              classNames.push_back(cd->name);
5967              
5968                          // Reject classes that are abstract.
5969 krisbash 1.5             if (cd->flags & MI_FLAG_ABSTRACT && !s_options.noProviders)
5970 mike     1.1             {
5971                              err(ID_REFUSED_TO_GENERATE_PROVIDER_FOR_ABSTRACT_CLASS, 
5972                                  "refused to generated provider for abstract class: %s", 
5973                                  cd->name);
5974                          }
5975                      }
5976                  }
5977              
5978                  // Form the set of classes for which there are providers (partial 
5979                  // generation is performed on dependent classes (for which there is
5980                  // no actual provider).
5981              
5982                  if (!s_options.noProviders)
5983                  {
5984                      for (size_t i = 0; i < classNames.size(); i++)
5985                      {
5986                          providerClasses.insert(classNames[i]);
5987                      }
5988                  }
5989              
5990                  // Add extra classes (given by -e option) to class list to be generated.
5991 mike     1.1 
5992                  for (size_t i = 0; i < s_options.extraClasses.size(); i++)
5993                  {
5994                      const MI_ClassDecl* cd = parser.findClassDecl(
5995                          s_options.extraClasses[i].c_str());
5996              
5997                      if (!cd)
5998                      {
5999                          err(ID_UNKNOWN_CLASS, "unknown class: %s", 
6000                              s_options.extraClasses[i].c_str());
6001                      }
6002              
6003                      classNames.push_back(cd->name);
6004                  }
6005              
6006                  // Generate the classes.
6007              
6008                  set<string> classIdentifiers;
6009              
6010                  for (size_t i = 0; i < classNames.size(); i++)
6011                  {
6012 mike     1.1         const char* cn = classNames[i].c_str();
6013                      const MI_ClassDecl* cd = parser.findClassDecl(cn);
6014              
6015                      if (!cd)
6016                          err(ID_UNKNOWN_CLASS, "unknown class: %s", cn);
6017              
6018                      GenClassHeader(parser, cd, classIdentifiers);
6019              
6020                      if (providerClasses.find(cd->name) != providerClasses.end())
6021                      {
6022                          if (s_options.cpp)
6023                              GenCppClassSource(cd);
6024                          else
6025                              GenClassSource(cd);
6026                      }
6027                  }
6028              
6029                  // Generate the schema.c file.
6030                  GenSchemaSourceFile(parser, classNames, classIdentifiers);
6031              
6032                  // generate c++ wrappers - stubs.cpp file
6033 mike     1.1     if (!s_options.noProviders && s_options.cpp)
6034                      GenModuleStubsFile(parser, classNames);
6035              
6036                  // Generate the module.h and module.c files.
6037                  if (!s_options.noProviders)
6038                  {
6039                      if (s_options.cpp)
6040                      {
6041                          GenModuleCppSourceFile();
6042                          GenModuleCppHeaderFile();
6043                      }
6044                      else
6045                          GenModuleSourceFile();
6046                  }
6047              
6048                  // Generate the strings.rc.
6049                  if (s_options.localize)
6050                      GenerateStringsFile();
6051              
6052                  // Generate provider registry file.
6053                  if (!s_options.providerRegistryPath.empty())
6054 mike     1.1         GenerateRegistryFile(parser, classNames);
6055              
6056                  if ( s_options.quiet )
6057                  {
6058                      fclose( s_stdout );
6059                      s_stdout = 0;
6060                  }
6061              
6062                  // Generate the GNUmakefile.
6063                  if (s_options.providerName.size())
6064                      GenMakefile(s_options.providerName, classNamesArg, s_options.cmdLine);
6065              
6066                  return 0;
6067              }

ViewCVS 0.9.2