2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * drivers.c - Driver Loading Functions.
25 * Copyright (c) 2000 Apple Computer, Inc.
45 #define kXMLTagPList "plist "
46 #define kXMLTagDict "dict"
47 #define kXMLTagKey "key"
48 #define kXMLTagString "string"
49 #define kXMLTagInteger "integer"
50 #define kXMLTagData "data"
51 #define kXMLTagDate "date"
52 #define kXMLTagFalse "false/"
53 #define kXMLTagTrue "true/"
54 #define kXMLTagArray "array"
56 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
57 #define kPropCFBundleExecutable ("CFBundleExecutable")
58 #define kPropOSBundleRequired ("OSBundleRequired")
59 #define kPropOSBundleLibraries ("OSBundleLibraries")
60 #define kPropIOKitPersonalities ("IOKitPersonalities")
61 #define kPropIONameMatch ("IONameMatch")
69 typedef struct Tag Tag
, *TagPtr
;
72 struct Module
*nextModule
;
79 typedef struct Module Module
, *ModulePtr
;
87 typedef struct DriverInfo DriverInfo
, *DriverInfoPtr
;
89 #define kDriverPackageSignature1 'MKXT'
90 #define kDriverPackageSignature2 'MOSX'
92 struct DriversPackage
{
93 unsigned long signature1
;
94 unsigned long signature2
;
96 unsigned long alder32
;
97 unsigned long version
;
98 unsigned long numDrivers
;
99 unsigned long reserved1
;
100 unsigned long reserved2
;
102 typedef struct DriversPackage DriversPackage
;
109 static long FileLoadDrivers(char *dirSpec
, long plugin
);
110 static long NetLoadDrivers(char *dirSpec
);
111 static long LoadDriverMKext(char *fileSpec
);
112 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
);
113 static long LoadMatchedModules(void);
114 static long MatchPersonalities(void);
115 static long MatchLibraries(void);
116 static TagPtr
GetProperty(TagPtr dict
, char *key
);
117 static ModulePtr
FindModule(char *name
);
118 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
);
119 static long ParseNextTag(char *buffer
, TagPtr
*tag
);
120 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
);
121 static long ParseTagKey(char *buffer
, TagPtr
*tag
);
122 static long ParseTagString(char *buffer
, TagPtr
*tag
);
123 static long ParseTagInteger(char *buffer
, TagPtr
*tag
);
124 static long ParseTagData(char *buffer
, TagPtr
*tag
);
125 static long ParseTagDate(char *buffer
, TagPtr
*tag
);
126 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
);
127 static long GetNextTag(char *buffer
, char **tag
, long *start
);
128 static long FixDataMatchingTag(char *buffer
, char *tag
);
129 static TagPtr
NewTag(void);
130 static void FreeTag(TagPtr tag
);
131 static char *NewSymbol(char *string
);
132 static void FreeSymbol(char *string
);
133 static void DumpTag(TagPtr tag
, long depth
);
135 static ModulePtr gModuleHead
, gModuleTail
;
136 static TagPtr gPersonalityHead
, gPersonalityTail
;
137 static char gExtensionsSpec
[4096];
138 static char gDriverSpec
[4096];
139 static char gFileSpec
[4096];
140 static char gTempSpec
[4096];
141 static char gFileName
[4096];
145 long LoadDrivers(char *dirSpec
)
147 if (gBootFileType
== kNetworkDeviceType
) {
148 NetLoadDrivers(dirSpec
);
149 } else if (gBootFileType
== kBlockDeviceType
) {
150 strcpy(gExtensionsSpec
, dirSpec
);
151 strcat(gExtensionsSpec
, "System\\Library\\");
152 FileLoadDrivers(gExtensionsSpec
, 0);
157 MatchPersonalities();
161 LoadMatchedModules();
168 static long FileLoadDrivers(char *dirSpec
, long plugin
)
170 long ret
, length
, index
, flags
, time
, time2
, bundleType
;
174 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
175 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
)) {
176 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
177 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
178 (((gBootMode
& kBootModeSafe
) == 0) && (time
> time2
))) {
179 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
180 printf("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
181 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
185 strcat(dirSpec
, "Extensions");
188 printf("LoadDrivers: Loading from [%s]\n", dirSpec
);
192 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
193 if (ret
== -1) break;
195 // Make sure this is a directory.
196 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
198 // Make sure this is a kext.
199 length
= strlen(name
);
200 if (strcmp(name
+ length
- 5, ".kext")) continue;
202 // Save the file name.
203 strcpy(gFileName
, name
);
205 // Determine the bundle type.
206 sprintf(gTempSpec
, "%s\\%s", dirSpec
, gFileName
);
207 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
208 if (ret
== 0) bundleType
= kCFBundleType2
;
209 else bundleType
= kCFBundleType3
;
212 sprintf(gDriverSpec
, "%s\\%s\\%sPlugIns", dirSpec
, gFileName
,
213 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
216 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
218 printf("LoadDrivers: failed\n");
222 ret
= FileLoadDrivers(gDriverSpec
, 1);
230 static long NetLoadDrivers(char *dirSpec
)
234 // Get the name of the kernel
235 cnt
= strlen(gBootFile
);
237 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
243 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, gBootFile
+ cnt
);
245 printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
249 if (LoadDriverMKext(gDriverSpec
) == 0) break;
251 if (tries
== -1) return -1;
257 static long LoadDriverMKext(char *fileSpec
)
259 long driversAddr
, driversLength
;
261 DriversPackage
*package
= (DriversPackage
*)kLoadAddr
;
264 if (LoadFile(fileSpec
) == -1) return -1;
267 if ((package
->signature1
!= kDriverPackageSignature1
) ||
268 (package
->signature2
!= kDriverPackageSignature2
)) return -1;
269 if (package
->length
> kLoadSize
) return -1;
270 if (package
->alder32
!= Alder32((char *)&package
->version
,
271 package
->length
- 0x10)) return -1;
273 // Make space for the MKext.
274 driversLength
= package
->length
;
275 driversAddr
= AllocateKernelMemory(driversLength
);
278 memcpy((void *)driversAddr
, (void *)kLoadAddr
, driversLength
);
280 // Add the MKext to the memory map.
281 sprintf(segName
, "DriversPackage-%x", driversAddr
);
282 AllocateMemoryRange(segName
, driversAddr
, driversLength
);
288 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
)
290 long length
, ret
, driverPathLength
;
293 TagPtr personalities
;
296 // Reset the malloc zone.
297 malloc_init((char *)kMallocAddr
, kMallocSize
);
299 // Save the driver path.
300 sprintf(gFileSpec
, "%s\\%s\\%s", dirSpec
, name
,
301 (bundleType
== kCFBundleType2
) ? "Contents\\MacOS\\" : "");
302 driverPathLength
= strlen(gFileSpec
);
303 tmpDriverPath
= malloc(driverPathLength
+ 1);
304 if (tmpDriverPath
== 0) return -1;
305 strcpy(tmpDriverPath
, gFileSpec
);
307 // Construct the file spec.
308 sprintf(gFileSpec
, "%s\\%s\\%sInfo.plist", dirSpec
, name
,
309 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
311 length
= LoadFile(gFileSpec
);
317 buffer
= malloc(length
+ 1);
322 strncpy(buffer
, (char *)kLoadAddr
, length
);
324 ret
= ParseXML(buffer
, &module, &personalities
);
331 // Allocate memory for the driver path and the plist.
332 module->driverPath
= AllocateBootXMemory(driverPathLength
+ 1);
333 module->plistAddr
= AllocateBootXMemory(length
+ 1);
335 if ((module->driverPath
== 0) | (module->plistAddr
== 0)) {
340 // Save the driver path in the module.
341 strcpy(module->driverPath
, tmpDriverPath
);
344 // Add the origin plist to the module.
345 strncpy(module->plistAddr
, (char *)kLoadAddr
, length
);
346 module->plistLength
= length
+ 1;
348 // Add the module to the end of the module list.
349 if (gModuleHead
== 0) gModuleHead
= module;
350 else gModuleTail
->nextModule
= module;
351 gModuleTail
= module;
353 // Add the persionalities to the personality list.
354 if (personalities
) personalities
= personalities
->tag
;
355 while (personalities
!= 0) {
356 if (gPersonalityHead
== 0) gPersonalityHead
= personalities
->tag
;
357 else gPersonalityTail
->tagNext
= personalities
->tag
;
358 gPersonalityTail
= personalities
->tag
;
360 personalities
= personalities
->tagNext
;
367 static long LoadMatchedModules(void)
371 char *fileName
, segName
[32];
372 DriverInfoPtr driver
;
373 long length
, driverAddr
, driverLength
;
375 module = gModuleHead
;
376 while (module != 0) {
377 if (module->willLoad
) {
378 prop
= GetProperty(module->dict
, kPropCFBundleExecutable
);
380 fileName
= prop
->string
;
381 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
382 length
= LoadFile(gFileSpec
);
385 // Make make in the image area.
386 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
387 driverAddr
= AllocateKernelMemory(driverLength
);
389 // Set up the DriverInfo.
390 driver
= (DriverInfoPtr
)driverAddr
;
391 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
392 driver
->plistLength
= module->plistLength
;
394 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
395 module->plistLength
);
396 driver
->moduleLength
= length
;
398 driver
->moduleAddr
= 0;
399 driver
->moduleLength
= 0;
402 // Save the plist and module.
403 strcpy(driver
->plistAddr
, module->plistAddr
);
405 memcpy(driver
->moduleAddr
, (void *)kLoadAddr
, driver
->moduleLength
);
408 // Add an entry to the memory map.
409 sprintf(segName
, "Driver-%x", driver
);
410 AllocateMemoryRange(segName
, driverAddr
, driverLength
);
414 module = module->nextModule
;
421 static long MatchPersonalities(void)
428 // Try to match each of the personalities.
429 for(persionality
= gPersonalityHead
; persionality
!= 0;
430 persionality
= persionality
->tagNext
) {
431 // Get the module name. Make sure it exists and has not
432 // already been marked for loading.
433 prop
= GetProperty(persionality
, kPropCFBundleIdentifier
);
434 if (prop
== 0) continue;
435 module = FindModule(prop
->string
);
436 if (module == 0) continue;
437 if (module->willLoad
) continue;
439 // Look for the exact match property.
440 // Try to match with it.
442 // Look for the old match property.
443 // Try to match with it.
445 prop
= GetProperty(persionality
, kPropIONameMatch
);
446 if ((prop
!= 0) && (prop
->tag
!= 0)) prop
= prop
->tag
;
448 ph
= SearchForNodeMatching(0, 1, prop
->string
);
451 prop
= prop
->tagNext
;
454 // If a node was found mark the module to be loaded.
456 module->willLoad
= 1;
464 static long MatchLibraries(void)
467 ModulePtr
module, module2
;
472 module = gModuleHead
;
473 while (module != 0) {
474 if (module->willLoad
== 1) {
475 prop
= GetProperty(module->dict
, kPropOSBundleLibraries
);
479 module2
= gModuleHead
;
480 while (module2
!= 0) {
481 prop2
= GetProperty(module2
->dict
, kPropCFBundleIdentifier
);
482 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
))) {
483 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
486 module2
= module2
->nextModule
;
488 prop
= prop
->tagNext
;
491 module->willLoad
= 2;
494 module = module->nextModule
;
502 static TagPtr
GetProperty(TagPtr dict
, char *key
)
506 if (dict
->type
!= kTagTypeDict
) return 0;
512 tagList
= tag
->tagNext
;
514 if ((tag
->type
!= kTagTypeKey
) || (tag
->string
== 0)) continue;
516 if (!strcmp(tag
->string
, key
)) return tag
->tag
;
523 static ModulePtr
FindModule(char *name
)
528 module = gModuleHead
;
530 while (module != 0) {
531 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
532 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
533 module = module->nextModule
;
540 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
)
543 TagPtr moduleDict
, required
;
548 length
= ParseNextTag(buffer
+ pos
, &moduleDict
);
549 if (length
== -1) break;
552 if (moduleDict
== 0) continue;
554 if (moduleDict
->type
== kTagTypeDict
) break;
559 if (length
== -1) return -1;
561 required
= GetProperty(moduleDict
, kPropOSBundleRequired
);
562 if ((required
== 0) || (required
->type
!= kTagTypeString
) ||
563 !strcmp(required
->string
, "Safe Boot")) {
568 tmpModule
= AllocateBootXMemory(sizeof(Module
));
569 if (tmpModule
== 0) {
573 tmpModule
->dict
= moduleDict
;
575 // For now, load any module that has OSBundleRequired != "Safe Boot".
576 tmpModule
->willLoad
= 1;
580 // Get the personalities.
581 *personalities
= GetProperty(moduleDict
, kPropIOKitPersonalities
);
587 static long ParseNextTag(char *buffer
, TagPtr
*tag
)
592 length
= GetNextTag(buffer
, &tagName
, 0);
593 if (length
== -1) return -1;
596 if (!strncmp(tagName
, kXMLTagPList
, 6)) {
598 } else if (!strcmp(tagName
, kXMLTagDict
)) {
599 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeDict
, 0);
600 } else if (!strcmp(tagName
, kXMLTagDict
"/")) {
601 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeDict
, 1);
602 } else if (!strcmp(tagName
, kXMLTagKey
)) {
603 length
= ParseTagKey(buffer
+ pos
, tag
);
604 } else if (!strcmp(tagName
, kXMLTagString
)) {
605 length
= ParseTagString(buffer
+ pos
, tag
);
606 } else if (!strcmp(tagName
, kXMLTagInteger
)) {
607 length
= ParseTagInteger(buffer
+ pos
, tag
);
608 } else if (!strcmp(tagName
, kXMLTagData
)) {
609 length
= ParseTagData(buffer
+ pos
, tag
);
610 } else if (!strcmp(tagName
, kXMLTagDate
)) {
611 length
= ParseTagDate(buffer
+ pos
, tag
);
612 } else if (!strcmp(tagName
, kXMLTagFalse
)) {
613 length
= ParseTagBoolean(buffer
+ pos
, tag
, kTagTypeFalse
);
614 } else if (!strcmp(tagName
, kXMLTagTrue
)) {
615 length
= ParseTagBoolean(buffer
+ pos
, tag
, kTagTypeTrue
);
616 } else if (!strcmp(tagName
, kXMLTagArray
)) {
617 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeArray
, 0);
618 } else if (!strcmp(tagName
, kXMLTagArray
"/")) {
619 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeArray
, 1);
625 if (length
== -1) return -1;
631 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
)
634 TagPtr tagList
, tmpTag
;
641 length
= ParseNextTag(buffer
+ pos
, &tmpTag
);
642 if (length
== -1) break;
645 if (tmpTag
== 0) break;
646 tmpTag
->tagNext
= tagList
;
664 tmpTag
->tag
= tagList
;
673 static long ParseTagKey(char *buffer
, TagPtr
*tag
)
675 long length
, length2
;
677 TagPtr tmpTag
, subTag
;
679 length
= FixDataMatchingTag(buffer
, kXMLTagKey
);
680 if (length
== -1) return -1;
682 length2
= ParseNextTag(buffer
+ length
, &subTag
);
683 if (length2
== -1) return -1;
691 string
= NewSymbol(buffer
);
698 tmpTag
->type
= kTagTypeKey
;
699 tmpTag
->string
= string
;
700 tmpTag
->tag
= subTag
;
705 return length
+ length2
;
709 static long ParseTagString(char *buffer
, TagPtr
*tag
)
715 length
= FixDataMatchingTag(buffer
, kXMLTagString
);
716 if (length
== -1) return -1;
719 if (tmpTag
== 0) return -1;
721 string
= NewSymbol(buffer
);
727 tmpTag
->type
= kTagTypeString
;
728 tmpTag
->string
= string
;
738 static long ParseTagInteger(char *buffer
, TagPtr
*tag
)
740 long length
, integer
;
743 length
= FixDataMatchingTag(buffer
, kXMLTagInteger
);
744 if (length
== -1) return -1;
747 if (tmpTag
== 0) return -1;
751 tmpTag
->type
= kTagTypeInteger
;
752 tmpTag
->string
= (char *)integer
;
762 static long ParseTagData(char *buffer
, TagPtr
*tag
)
767 length
= FixDataMatchingTag(buffer
, kXMLTagData
);
768 if (length
== -1) return -1;
771 if (tmpTag
== 0) return -1;
773 tmpTag
->type
= kTagTypeData
;
784 static long ParseTagDate(char *buffer
, TagPtr
*tag
)
789 length
= FixDataMatchingTag(buffer
, kXMLTagDate
);
790 if (length
== -1) return -1;
793 if (tmpTag
== 0) return -1;
795 tmpTag
->type
= kTagTypeDate
;
806 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
)
811 if (tmpTag
== 0) return -1;
824 static long GetNextTag(char *buffer
, char **tag
, long *start
)
828 if (tag
== 0) return -1;
830 // Find the start of the tag.
832 while ((buffer
[cnt
] != '\0') && (buffer
[cnt
] != '<')) cnt
++;
833 if (buffer
[cnt
] == '\0') return -1;
835 // Find the end of the tag.
837 while ((buffer
[cnt2
] != '\0') && (buffer
[cnt2
] != '>')) cnt2
++;
838 if (buffer
[cnt2
] == '\0') return -1;
841 *tag
= buffer
+ cnt
+ 1;
843 if (start
) *start
= cnt
;
849 static long FixDataMatchingTag(char *buffer
, char *tag
)
851 long length
, start
, stop
;
856 length
= GetNextTag(buffer
+ start
, &endTag
, &stop
);
857 if (length
== -1) return -1;
859 if ((*endTag
== '/') && !strcmp(endTag
+ 1, tag
)) break;
863 buffer
[start
+ stop
] = '\0';
865 return start
+ length
;
869 #define kTagsPerBlock (0x1000)
871 static TagPtr gTagsFree
;
873 static TagPtr
NewTag(void)
878 if (gTagsFree
== 0) {
879 tag
= (TagPtr
)AllocateBootXMemory(kTagsPerBlock
* sizeof(Tag
));
880 if (tag
== 0) return 0;
882 // Initalize the new tags.
883 for (cnt
= 0; cnt
< kTagsPerBlock
; cnt
++) {
884 tag
[cnt
].type
= kTagTypeNone
;
887 tag
[cnt
].tagNext
= tag
+ cnt
+ 1;
889 tag
[kTagsPerBlock
- 1].tagNext
= 0;
895 gTagsFree
= tag
->tagNext
;
901 static void FreeTag(TagPtr tag
)
904 if (tag
== 0) return;
906 if (tag
->string
) FreeSymbol(tag
->string
);
909 FreeTag(tag
->tagNext
);
911 // Clear and free the tag.
912 tag
->type
= kTagTypeNone
;
915 tag
->tagNext
= gTagsFree
;
925 typedef struct Symbol Symbol
, *SymbolPtr
;
927 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
);
929 static SymbolPtr gSymbolsHead
;
932 static char *NewSymbol(char *string
)
936 // Look for string in the list of symbols.
937 symbol
= FindSymbol(string
, 0);
939 // Add the new symbol.
941 symbol
= AllocateBootXMemory(sizeof(Symbol
) + strlen(string
));
942 if (symbol
== 0) return 0;
944 // Set the symbol's data.
945 symbol
->refCount
= 0;
946 strcpy(symbol
->string
, string
);
948 // Add the symbol to the list.
949 symbol
->next
= gSymbolsHead
;
950 gSymbolsHead
= symbol
;
953 // Update the refCount and return the string.
955 return symbol
->string
;
959 static void FreeSymbol(char *string
)
962 SymbolPtr symbol
, prev
;
964 // Look for string in the list of symbols.
965 symbol
= FindSymbol(string
, &prev
);
966 if (symbol
== 0) return;
968 // Update the refCount.
971 if (symbol
->refCount
!= 0) return;
973 // Remove the symbol from the list.
974 if (prev
!= 0) prev
->next
= symbol
->next
;
975 else gSymbolsHead
= symbol
->next
;
977 // Free the symbol's memory.
983 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
)
985 SymbolPtr symbol
, prev
;
987 symbol
= gSymbolsHead
;
990 while (symbol
!= 0) {
991 if (!strcmp(symbol
->string
, string
)) break;
994 symbol
= symbol
->next
;
997 if ((symbol
!= 0) && (prevSymbol
!= 0)) *prevSymbol
= prev
;
1003 static void DumpTagDict(TagPtr tag
, long depth
);
1004 static void DumpTagKey(TagPtr tag
, long depth
);
1005 static void DumpTagString(TagPtr tag
, long depth
);
1006 static void DumpTagInteger(TagPtr tag
, long depth
);
1007 static void DumpTagData(TagPtr tag
, long depth
);
1008 static void DumpTagDate(TagPtr tag
, long depth
);
1009 static void DumpTagBoolean(TagPtr tag
, long depth
);
1010 static void DumpTagArray(TagPtr tag
, long depth
);
1011 static void DumpSpaces(long depth
);
1013 static void DumpTag(TagPtr tag
, long depth
)
1015 if (tag
== 0) return;
1017 switch (tag
->type
) {
1019 DumpTagDict(tag
, depth
);
1023 DumpTagKey(tag
, depth
);
1026 case kTagTypeString
:
1027 DumpTagString(tag
, depth
);
1030 case kTagTypeInteger
:
1031 DumpTagInteger(tag
, depth
);
1035 DumpTagData(tag
, depth
);
1039 DumpTagDate(tag
, depth
);
1042 case kTagTypeFalse
:
1044 DumpTagBoolean(tag
, depth
);
1047 case kTagTypeArray
:
1048 DumpTagArray(tag
, depth
);
1057 static void DumpTagDict(TagPtr tag
, long depth
)
1061 if (tag
->tag
== 0) {
1063 printf("<%s/>\n", kXMLTagDict
);
1066 printf("<%s>\n", kXMLTagDict
);
1070 DumpTag(tagList
, depth
+ 1);
1071 tagList
= tagList
->tagNext
;
1075 printf("</%s>\n", kXMLTagDict
);
1080 static void DumpTagKey(TagPtr tag
, long depth
)
1083 printf("<%s>%s</%s>\n", kXMLTagKey
, tag
->string
, kXMLTagKey
);
1085 DumpTag(tag
->tag
, depth
);
1089 static void DumpTagString(TagPtr tag
, long depth
)
1092 printf("<%s>%s</%s>\n", kXMLTagString
, tag
->string
, kXMLTagString
);
1096 static void DumpTagInteger(TagPtr tag
, long depth
)
1099 printf("<%s>%x</%s>\n", kXMLTagInteger
, tag
->string
, kXMLTagInteger
);
1103 static void DumpTagData(TagPtr tag
, long depth
)
1106 printf("<%s>%x</%s>\n", kXMLTagData
, tag
->string
, kXMLTagData
);
1110 static void DumpTagDate(TagPtr tag
, long depth
)
1113 printf("<%s>%x</%s>\n", kXMLTagDate
, tag
->string
, kXMLTagDate
);
1117 static void DumpTagBoolean(TagPtr tag
, long depth
)
1120 printf("<%s>\n", (tag
->type
== kTagTypeTrue
) ? kXMLTagTrue
: kXMLTagFalse
);
1124 static void DumpTagArray(TagPtr tag
, long depth
)
1128 if (tag
->tag
== 0) {
1130 printf("<%s/>\n", kXMLTagArray
);
1133 printf("<%s>\n", kXMLTagArray
);
1137 DumpTag(tagList
, depth
+ 1);
1138 tagList
= tagList
->tagNext
;
1142 printf("</%s>\n", kXMLTagArray
);
1147 static void DumpSpaces(long depth
)
1151 for (cnt
= 0; cnt
< (depth
* 4); cnt
++) putchar(' ');