]> git.saurik.com Git - apple/bootx.git/blobdiff - bootx.tproj/sl.subproj/drivers.c
BootX-75.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / drivers.c
index a3bdf120c1c28015ad3f80b6b1f480ecf5caef3d..d0c324d1e439e71086b5408fed2184af11aeb55a 100644 (file)
 /*
  *  drivers.c - Driver Loading Functions.
  *
- *  Copyright (c) 2000 Apple Computer, Inc.
+ *  Copyright (c) 2000-2005 Apple Computer, Inc.
  *
  *  DRI: Josh de Cesare
  */
 
 #include <sl.h>
 
-enum {
-  kTagTypeNone = 0,
-  kTagTypeDict,
-  kTagTypeKey,
-  kTagTypeString,
-  kTagTypeInteger,
-  kTagTypeData,
-  kTagTypeDate,
-  kTagTypeFalse,
-  kTagTypeTrue,
-  kTagTypeArray
-};
-
-#define kXMLTagPList   "plist "
-#define kXMLTagDict    "dict"
-#define kXMLTagKey     "key"
-#define kXMLTagString  "string"
-#define kXMLTagInteger "integer"
-#define kXMLTagData    "data"
-#define kXMLTagDate    "date"
-#define kXMLTagFalse   "false/"
-#define kXMLTagTrue    "true/"
-#define kXMLTagArray   "array"
+#define DRIVER_DEBUG 0
 
 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
 #define kPropCFBundleExecutable ("CFBundleExecutable")
@@ -60,14 +38,6 @@ enum {
 #define kPropIOKitPersonalities ("IOKitPersonalities")
 #define kPropIONameMatch        ("IONameMatch")
 
-struct Tag {
-  long       type;
-  char       *string;
-  struct Tag *tag;
-  struct Tag *tagNext;
-};
-typedef struct Tag Tag, *TagPtr;
-
 struct Module {  
   struct Module *nextModule;
   long          willLoad;
@@ -93,7 +63,7 @@ struct DriversPackage {
   unsigned long signature1;
   unsigned long signature2;
   unsigned long length;
-  unsigned long alder32;
+  unsigned long adler32;
   unsigned long version;
   unsigned long numDrivers;
   unsigned long reserved1;
@@ -113,28 +83,11 @@ static long LoadDriverPList(char *dirSpec, char *name, long bundleType);
 static long LoadMatchedModules(void);
 static long MatchPersonalities(void);
 static long MatchLibraries(void);
-static TagPtr GetProperty(TagPtr dict, char *key);
 static ModulePtr FindModule(char *name);
-static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
-static long ParseNextTag(char *buffer, TagPtr *tag);
-static long ParseTagList(char *buffer, TagPtr *tag, long type, long empty);
-static long ParseTagKey(char *buffer, TagPtr *tag);
-static long ParseTagString(char *buffer, TagPtr *tag);
-static long ParseTagInteger(char *buffer, TagPtr *tag);
-static long ParseTagData(char *buffer, TagPtr *tag);
-static long ParseTagDate(char *buffer, TagPtr *tag);
-static long ParseTagBoolean(char *buffer, TagPtr *tag, long type);
-static long GetNextTag(char *buffer, char **tag, long *start);
-static long FixDataMatchingTag(char *buffer, char *tag);
-static TagPtr NewTag(void);
-static void FreeTag(TagPtr tag);
-static char *NewSymbol(char *string);
-static void FreeSymbol(char *string);
-static void DumpTag(TagPtr tag, long depth);
+static long XML2Module(char *buffer, ModulePtr *module, TagPtr *personalities);
 
 static ModulePtr gModuleHead, gModuleTail;
 static TagPtr    gPersonalityHead, gPersonalityTail;
-static char      gExtensionsSpec[4096];
 static char      gDriverSpec[4096];
 static char      gFileSpec[4096];
 static char      gTempSpec[4096];
@@ -145,11 +98,9 @@ static char      gFileName[4096];
 long LoadDrivers(char *dirSpec)
 {
   if (gBootFileType == kNetworkDeviceType) {
-    NetLoadDrivers(dirSpec);
+    if(NetLoadDrivers(dirSpec) < 0) return -1;
   } else if (gBootFileType == kBlockDeviceType) {
-    strcpy(gExtensionsSpec, dirSpec);
-    strcat(gExtensionsSpec, "System\\Library\\");
-    FileLoadDrivers(gExtensionsSpec, 0);
+    FileLoadDrivers(dirSpec, 0);       // never returns errors
   } else {
     return 0;
   }
@@ -165,6 +116,7 @@ long LoadDrivers(char *dirSpec)
 
 // Private Functions
 
+// XX FileLoadDrivers could use some more error checking
 static long FileLoadDrivers(char *dirSpec, long plugin)
 {
   long ret, length, index, flags, time, time2, bundleType;
@@ -174,24 +126,29 @@ static long FileLoadDrivers(char *dirSpec, long plugin)
     ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time);
     if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat)) {
       ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
-      if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) ||
-         (((gBootMode & kBootModeSafe) == 0) && (time > time2))) {
+      // use mkext if if it looks right or if the folder was bad
+      if ((ret != 0) ||
+         ((flags & kFileTypeMask) != kFileTypeDirectory) ||
+         (((gBootMode & kBootModeSafe) == 0) && (time == (time2 + 1)))) {
        sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec);
-       printf("LoadDrivers: Loading from [%s]\n", gDriverSpec);
+       printf("FileLoadDrivers: Loading from [%s]\n", gDriverSpec);
        if (LoadDriverMKext(gDriverSpec) == 0) return 0;
-      }
+      } else if(time != (time2 + 1)) {
+         printf("mkext timestamp isn't quite right (delta: %d); ignoring...\n",
+             time2 - time);
+       }
     }
     
     strcat(dirSpec, "Extensions");
   }
   
-  printf("LoadDrivers: Loading from [%s]\n", dirSpec);
+  printf("FileLoadDrivers: Loading from [%s]\n", dirSpec);
   
   index = 0;
   while (1) {
     ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
     if (ret == -1) break;
-    
+
     // Make sure this is a directory.
     if ((flags & kFileTypeMask ) != kFileTypeDirectory) continue;
     
@@ -214,9 +171,6 @@ static long FileLoadDrivers(char *dirSpec, long plugin)
     }
     
     ret = LoadDriverPList(dirSpec, gFileName, bundleType);
-    if (ret != 0) {
-      printf("LoadDrivers: failed\n");
-    }
     
     if (!plugin) {
       ret = FileLoadDrivers(gDriverSpec, 1);
@@ -256,18 +210,22 @@ static long NetLoadDrivers(char *dirSpec)
 
 static long LoadDriverMKext(char *fileSpec)
 {
-  long           driversAddr, driversLength;
+  unsigned long  driversAddr, driversLength, length;
   char           segName[32];
-  DriversPackage *package = (DriversPackage *)kLoadAddr;
+  DriversPackage *package;
   
   // Load the MKext.
-  if (LoadFile(fileSpec) == -1) return -1;
+  length = LoadThinFatFile(fileSpec, (void **)&package);
+  if (length == -1) return -1;
   
   // Verify the MKext.
   if ((package->signature1 != kDriverPackageSignature1) ||
       (package->signature2 != kDriverPackageSignature2)) return -1;
-  if (package->length > kLoadSize) return -1;
-  if (package->alder32 != Alder32((char *)&package->version,
+  if (package->length > kMaxMKextSize) {
+    printf("mkext segment too big (%ld bytes)\n", package->length);
+    return -1;
+  }
+  if (package->adler32 != Adler32((char *)&package->version,
                                  package->length - 0x10)) return -1;
   
   // Make space for the MKext.
@@ -275,7 +233,7 @@ static long LoadDriverMKext(char *fileSpec)
   driversAddr = AllocateKernelMemory(driversLength);
   
   // Copy the MKext.
-  memcpy((void *)driversAddr, (void *)kLoadAddr, driversLength);
+  memcpy((void *)driversAddr, (void *)package, driversLength);
   
   // Add the MKext to the memory map.
   sprintf(segName, "DriversPackage-%x", driversAddr);
@@ -309,6 +267,7 @@ static long LoadDriverPList(char *dirSpec, char *name, long bundleType)
          (bundleType == kCFBundleType2) ? "Contents\\" : "");
   
   length = LoadFile(gFileSpec);
+  *((char*)kLoadAddr + length) = '\0';  // terminate for parser safety
   if (length == -1) {
     free(tmpDriverPath);
     return -1;
@@ -321,9 +280,10 @@ static long LoadDriverPList(char *dirSpec, char *name, long bundleType)
   }
   strncpy(buffer, (char *)kLoadAddr, length);
   
-  ret = ParseXML(buffer, &module, &personalities);
+  ret = XML2Module(buffer, &module, &personalities);
   free(buffer);
   if (ret != 0) {
+    // could trap ret == -2 and report missing OSBundleRequired
     free(tmpDriverPath);
     return -1;
   }
@@ -350,7 +310,7 @@ static long LoadDriverPList(char *dirSpec, char *name, long bundleType)
   else gModuleTail->nextModule = module;
   gModuleTail = module;
   
-  // Add the persionalities to the personality list.
+  // Add the extracted personalities to the list.
   if (personalities) personalities = personalities->tag;
   while (personalities != 0) {
     if (gPersonalityHead == 0) gPersonalityHead = personalities->tag;
@@ -370,7 +330,8 @@ static long LoadMatchedModules(void)
   ModulePtr     module;
   char          *fileName, segName[32];
   DriverInfoPtr driver;
-  long          length, driverAddr, driverLength;
+  unsigned long length, driverAddr, driverLength;
+  void          *driverModuleAddr;
   
   module = gModuleHead;
   while (module != 0) {
@@ -379,7 +340,7 @@ static long LoadMatchedModules(void)
       if (prop != 0) {
        fileName = prop->string;
        sprintf(gFileSpec, "%s%s", module->driverPath, fileName);
-       length = LoadFile(gFileSpec);
+       length = LoadThinFatFile(gFileSpec, &driverModuleAddr);
       } else length = 0;
       if (length != -1) {
        // Make make in the image area.
@@ -402,7 +363,7 @@ static long LoadMatchedModules(void)
        // Save the plist and module.
        strcpy(driver->plistAddr, module->plistAddr);
        if (length != 0) {
-         memcpy(driver->moduleAddr, (void *)kLoadAddr, driver->moduleLength);
+         memcpy(driver->moduleAddr, driverModuleAddr, driver->moduleLength);
        }
        
        // Add an entry to the memory map.
@@ -499,27 +460,6 @@ static long MatchLibraries(void)
 }
 
 
-static TagPtr GetProperty(TagPtr dict, char *key)
-{
-  TagPtr tagList, tag;
-  
-  if (dict->type != kTagTypeDict) return 0;
-  
-  tag = 0;
-  tagList = dict->tag;
-  while (tagList) {
-    tag = tagList;
-    tagList = tag->tagNext;
-    
-    if ((tag->type != kTagTypeKey) || (tag->string == 0)) continue;
-    
-    if (!strcmp(tag->string, key)) return tag->tag;
-  }
-  
-  return 0;
-}
-
-
 static ModulePtr FindModule(char *name)
 {
   ModulePtr module;
@@ -536,33 +476,20 @@ static ModulePtr FindModule(char *name)
   return module;
 }
 
-
-static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities)
+/* turn buffer of XML into a ModulePtr for driver analysis */
+static long XML2Module(char *buffer, ModulePtr *module, TagPtr *personalities)
 {
-  long           length, pos;
-  TagPtr         moduleDict, required;
+  TagPtr         moduleDict = NULL, required;
   ModulePtr      tmpModule;
-  
-  pos = 0;
-  while (1) {
-    length = ParseNextTag(buffer + pos, &moduleDict);
-    if (length == -1) break;
-    pos += length;
-    
-    if (moduleDict == 0) continue;
-    
-    if (moduleDict->type == kTagTypeDict) break;
-    
-    FreeTag(moduleDict);
-  }
-  
-  if (length == -1) return -1;
-  
+
+  if(ParseXML(buffer, &moduleDict) < 0)
+    return -1;
+
   required = GetProperty(moduleDict, kPropOSBundleRequired);
   if ((required == 0) || (required->type != kTagTypeString) ||
       !strcmp(required->string, "Safe Boot")) {
     FreeTag(moduleDict);
-    return -1;
+    return -2;
   }
   
   tmpModule = AllocateBootXMemory(sizeof(Module));
@@ -582,572 +509,3 @@ static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities)
   
   return 0;
 }
-
-
-static long ParseNextTag(char *buffer, TagPtr *tag)
-{
-  long length, pos;
-  char *tagName;
-  
-  length = GetNextTag(buffer, &tagName, 0);
-  if (length == -1) return -1;
-  
-  pos = length;
-  if (!strncmp(tagName, kXMLTagPList, 6)) {
-    length = 0;
-  } else if (!strcmp(tagName, kXMLTagDict)) {
-    length = ParseTagList(buffer + pos, tag, kTagTypeDict, 0);
-  } else if (!strcmp(tagName, kXMLTagDict "/")) {
-    length = ParseTagList(buffer + pos, tag, kTagTypeDict, 1);
-  } else if (!strcmp(tagName, kXMLTagKey)) {
-    length = ParseTagKey(buffer + pos, tag);
-  } else if (!strcmp(tagName, kXMLTagString)) {
-    length = ParseTagString(buffer + pos, tag);
-  } else if (!strcmp(tagName, kXMLTagInteger)) {
-    length = ParseTagInteger(buffer + pos, tag);
-  } else if (!strcmp(tagName, kXMLTagData)) {
-    length = ParseTagData(buffer + pos, tag);
-  } else if (!strcmp(tagName, kXMLTagDate)) {
-    length = ParseTagDate(buffer + pos, tag);
-  } else if (!strcmp(tagName, kXMLTagFalse)) {
-    length = ParseTagBoolean(buffer + pos, tag, kTagTypeFalse);
-  } else if (!strcmp(tagName, kXMLTagTrue)) {
-    length = ParseTagBoolean(buffer + pos, tag, kTagTypeTrue);
-  } else if (!strcmp(tagName, kXMLTagArray)) {
-    length = ParseTagList(buffer + pos, tag, kTagTypeArray, 0);
-  } else if (!strcmp(tagName, kXMLTagArray "/")) {
-    length = ParseTagList(buffer + pos, tag, kTagTypeArray, 1);
-  } else {
-    *tag = 0;
-    length = 0;
-  }
-  
-  if (length == -1) return -1;
-  
-  return pos + length;
-}
-
-
-static long ParseTagList(char *buffer, TagPtr *tag, long type, long empty)
-{
-  long   length, pos;
-  TagPtr tagList, tmpTag;
-  
-  tagList = 0;
-  pos = 0;
-  
-  if (!empty) {
-    while (1) {
-      length = ParseNextTag(buffer + pos, &tmpTag);
-      if (length == -1) break;
-      pos += length;
-      
-      if (tmpTag == 0) break;
-      tmpTag->tagNext = tagList;
-      tagList = tmpTag;
-    }
-    
-    if (length == -1) {
-      FreeTag(tagList);
-      return -1;
-    }
-  }
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) {
-    FreeTag(tagList);
-    return -1;
-  }
-  
-  tmpTag->type = type;
-  tmpTag->string = 0;
-  tmpTag->tag = tagList;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return pos;
-}
-
-
-static long ParseTagKey(char *buffer, TagPtr *tag)
-{
-  long   length, length2;
-  char   *string;
-  TagPtr tmpTag, subTag;
-  
-  length = FixDataMatchingTag(buffer, kXMLTagKey);
-  if (length == -1) return -1;
-  
-  length2 = ParseNextTag(buffer + length, &subTag);
-  if (length2 == -1) return -1;
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) {
-    FreeTag(subTag);
-    return -1;
-  }
-  
-  string = NewSymbol(buffer);
-  if (string == 0) {
-    FreeTag(subTag);
-    FreeTag(tmpTag);
-    return -1;
-  }
-  
-  tmpTag->type = kTagTypeKey;
-  tmpTag->string = string;
-  tmpTag->tag = subTag;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return length + length2;
-}
-
-
-static long ParseTagString(char *buffer, TagPtr *tag)
-{
-  long   length;
-  char   *string;
-  TagPtr tmpTag;
-  
-  length = FixDataMatchingTag(buffer, kXMLTagString);
-  if (length == -1) return -1;
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) return -1;
-  
-  string = NewSymbol(buffer);
-  if (string == 0) {
-    FreeTag(tmpTag);
-    return -1;
-  }
-  
-  tmpTag->type = kTagTypeString;
-  tmpTag->string = string;
-  tmpTag->tag = 0;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return length;
-}
-
-
-static long ParseTagInteger(char *buffer, TagPtr *tag)
-{
-  long   length, integer;
-  TagPtr tmpTag;
-  
-  length = FixDataMatchingTag(buffer, kXMLTagInteger);
-  if (length == -1) return -1;
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) return -1;
-  
-  integer = 0;
-  
-  tmpTag->type = kTagTypeInteger;
-  tmpTag->string = (char *)integer;
-  tmpTag->tag = 0;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return length;
-}
-
-
-static long ParseTagData(char *buffer, TagPtr *tag)
-{
-  long   length;
-  TagPtr tmpTag;
-  
-  length = FixDataMatchingTag(buffer, kXMLTagData);
-  if (length == -1) return -1;
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) return -1;
-  
-  tmpTag->type = kTagTypeData;
-  tmpTag->string = 0;
-  tmpTag->tag = 0;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return length;
-}
-
-
-static long ParseTagDate(char *buffer, TagPtr *tag)
-{
-  long   length;
-  TagPtr tmpTag;
-  
-  length = FixDataMatchingTag(buffer, kXMLTagDate);
-  if (length == -1) return -1;
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) return -1;
-  
-  tmpTag->type = kTagTypeDate;
-  tmpTag->string = 0;
-  tmpTag->tag = 0;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return length;
-}
-
-
-static long ParseTagBoolean(char *buffer, TagPtr *tag, long type)
-{
-  TagPtr tmpTag;
-  
-  tmpTag = NewTag();
-  if (tmpTag == 0) return -1;
-  
-  tmpTag->type = type;
-  tmpTag->string = 0;
-  tmpTag->tag = 0;
-  tmpTag->tagNext = 0;
-  
-  *tag = tmpTag;
-  
-  return 0;
-}
-
-
-static long GetNextTag(char *buffer, char **tag, long *start)
-{
-  long cnt, cnt2;
-  
-  if (tag == 0) return -1;
-  
-  // Find the start of the tag.
-  cnt = 0;
-  while ((buffer[cnt] != '\0') && (buffer[cnt] != '<')) cnt++;
-  if (buffer[cnt] == '\0') return -1;
-  
-  // Find the end of the tag.
-  cnt2 = cnt + 1;
-  while ((buffer[cnt2] != '\0') && (buffer[cnt2] != '>')) cnt2++;
-  if (buffer[cnt2] == '\0') return -1;
-  
-  // Fix the tag data.
-  *tag = buffer + cnt + 1;
-  buffer[cnt2] = '\0';
-  if (start) *start = cnt;
-  
-  return cnt2 + 1;
-}
-
-
-static long FixDataMatchingTag(char *buffer, char *tag)
-{
-  long length, start, stop;
-  char *endTag;
-  
-  start = 0;
-  while (1) {
-    length = GetNextTag(buffer + start, &endTag, &stop);
-    if (length == -1) return -1;
-    
-    if ((*endTag == '/') && !strcmp(endTag + 1, tag)) break;
-    start += length;
-  }
-  
-  buffer[start + stop] = '\0';
-  
-  return start + length;
-}
-
-
-#define kTagsPerBlock (0x1000)
-
-static TagPtr gTagsFree;
-
-static TagPtr NewTag(void)
-{
-  long   cnt;
-  TagPtr tag;
-  
-  if (gTagsFree == 0) {
-    tag = (TagPtr)AllocateBootXMemory(kTagsPerBlock * sizeof(Tag));
-    if (tag == 0) return 0;
-    
-    // Initalize the new tags.
-    for (cnt = 0; cnt < kTagsPerBlock; cnt++) {
-      tag[cnt].type = kTagTypeNone;
-      tag[cnt].string = 0;
-      tag[cnt].tag = 0;
-      tag[cnt].tagNext = tag + cnt + 1;
-    }
-    tag[kTagsPerBlock - 1].tagNext = 0;
-    
-    gTagsFree = tag;
-  }
-  
-  tag = gTagsFree;
-  gTagsFree = tag->tagNext;
-  
-  return tag;
-}
-
-
-static void FreeTag(TagPtr tag)
-{
-  return;
-  if (tag == 0) return;
-  
-  if (tag->string) FreeSymbol(tag->string);
-  
-  FreeTag(tag->tag);
-  FreeTag(tag->tagNext);
-  
-  // Clear and free the tag.
-  tag->type = kTagTypeNone;
-  tag->string = 0;
-  tag->tag = 0;
-  tag->tagNext = gTagsFree;
-  gTagsFree = tag;
-}
-
-
-struct Symbol {
-  long          refCount;
-  struct Symbol *next;
-  char          string[1];
-};
-typedef struct Symbol Symbol, *SymbolPtr;
-
-static SymbolPtr FindSymbol(char *string, SymbolPtr *prevSymbol);
-
-static SymbolPtr gSymbolsHead;
-
-
-static char *NewSymbol(char *string)
-{
-  SymbolPtr symbol;
-  
-  // Look for string in the list of symbols.
-  symbol = FindSymbol(string, 0);
-  
-  // Add the new symbol.
-  if (symbol == 0) {
-    symbol = AllocateBootXMemory(sizeof(Symbol) + strlen(string));
-    if (symbol == 0) return 0;
-    
-    // Set the symbol's data.
-    symbol->refCount = 0;
-    strcpy(symbol->string, string);
-    
-    // Add the symbol to the list.
-    symbol->next = gSymbolsHead;
-    gSymbolsHead = symbol;
-  }
-  
-  // Update the refCount and return the string.
-  symbol->refCount++;
-  return symbol->string;
-}
-
-
-static void FreeSymbol(char *string)
-{ 
-#if 0
-  SymbolPtr symbol, prev;
-  
-  // Look for string in the list of symbols.
-  symbol = FindSymbol(string, &prev);
-  if (symbol == 0) return;
-  
-  // Update the refCount.
-  symbol->refCount--;
-  
-  if (symbol->refCount != 0) return;
-  
-  // Remove the symbol from the list.
-  if (prev != 0) prev->next = symbol->next;
-  else gSymbolsHead = symbol->next;
-  
-  // Free the symbol's memory.
-  free(symbol);
-#endif
-}
-
-
-static SymbolPtr FindSymbol(char *string, SymbolPtr *prevSymbol)
-{
-  SymbolPtr symbol, prev;
-  
-  symbol = gSymbolsHead;
-  prev = 0;
-  
-  while (symbol != 0) {
-    if (!strcmp(symbol->string, string)) break;
-    
-    prev = symbol;
-    symbol = symbol->next;
-  }
-  
-  if ((symbol != 0) && (prevSymbol != 0)) *prevSymbol = prev;
-  
-  return symbol;
-}
-
-#if 0
-static void DumpTagDict(TagPtr tag, long depth);
-static void DumpTagKey(TagPtr tag, long depth);
-static void DumpTagString(TagPtr tag, long depth);
-static void DumpTagInteger(TagPtr tag, long depth);
-static void DumpTagData(TagPtr tag, long depth);
-static void DumpTagDate(TagPtr tag, long depth);
-static void DumpTagBoolean(TagPtr tag, long depth);
-static void DumpTagArray(TagPtr tag, long depth);
-static void DumpSpaces(long depth);
-
-static void DumpTag(TagPtr tag, long depth)
-{
-  if (tag == 0) return;
-  
-  switch (tag->type) {
-  case kTagTypeDict :
-    DumpTagDict(tag, depth);
-    break;
-    
-  case kTagTypeKey :
-    DumpTagKey(tag, depth);
-    break;
-    
-  case kTagTypeString :
-    DumpTagString(tag, depth);
-    break;
-    
-  case kTagTypeInteger :
-    DumpTagInteger(tag, depth);
-    break;
-    
-  case kTagTypeData :
-    DumpTagData(tag, depth);
-    break;
-    
-  case kTagTypeDate :
-    DumpTagDate(tag, depth);
-    break;
-    
-  case kTagTypeFalse :
-  case kTagTypeTrue :
-    DumpTagBoolean(tag, depth);
-    break;
-    
-  case kTagTypeArray :
-    DumpTagArray(tag, depth);
-    break;
-    
-  default :
-    break;
-  }
-}
-
-
-static void DumpTagDict(TagPtr tag, long depth)
-{
-  TagPtr tagList;
-  
-  if (tag->tag == 0) {
-    DumpSpaces(depth);
-    printf("<%s/>\n", kXMLTagDict);
-  } else {
-    DumpSpaces(depth);
-    printf("<%s>\n", kXMLTagDict);
-    
-    tagList = tag->tag;
-    while (tagList) {
-      DumpTag(tagList, depth + 1);
-      tagList = tagList->tagNext;
-    }
-    
-    DumpSpaces(depth);
-    printf("</%s>\n", kXMLTagDict);
-  }
-}
-
-
-static void DumpTagKey(TagPtr tag, long depth)
-{
-  DumpSpaces(depth);
-  printf("<%s>%s</%s>\n", kXMLTagKey, tag->string, kXMLTagKey);
-  
-  DumpTag(tag->tag, depth);
-}
-
-
-static void DumpTagString(TagPtr tag, long depth)
-{
-  DumpSpaces(depth);
-  printf("<%s>%s</%s>\n", kXMLTagString, tag->string, kXMLTagString);
-}
-
-
-static void DumpTagInteger(TagPtr tag, long depth)
-{
-  DumpSpaces(depth);
-  printf("<%s>%x</%s>\n", kXMLTagInteger, tag->string, kXMLTagInteger);
-}
-
-
-static void DumpTagData(TagPtr tag, long depth)
-{
-  DumpSpaces(depth);
-  printf("<%s>%x</%s>\n", kXMLTagData, tag->string, kXMLTagData);
-}
-
-
-static void DumpTagDate(TagPtr tag, long depth)
-{
-  DumpSpaces(depth);
-  printf("<%s>%x</%s>\n", kXMLTagDate, tag->string, kXMLTagDate);
-}
-
-
-static void DumpTagBoolean(TagPtr tag, long depth)
-{
-  DumpSpaces(depth);
-  printf("<%s>\n", (tag->type == kTagTypeTrue) ? kXMLTagTrue : kXMLTagFalse);
-}
-
-
-static void DumpTagArray(TagPtr tag, long depth)
-{
-  TagPtr tagList;
-  
-  if (tag->tag == 0) {
-    DumpSpaces(depth);
-    printf("<%s/>\n", kXMLTagArray);
-  } else {
-    DumpSpaces(depth);
-    printf("<%s>\n", kXMLTagArray);
-    
-    tagList = tag->tag;
-    while (tagList) {
-      DumpTag(tagList, depth + 1);
-      tagList = tagList->tagNext;
-    }
-    
-    DumpSpaces(depth);
-    printf("</%s>\n", kXMLTagArray);
-  }
-}
-
-
-static void DumpSpaces(long depth)
-{
-  long cnt;
-  
-  for (cnt = 0; cnt < (depth * 4); cnt++) putchar(' ');
-}
-#endif