2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * drivers.c - Driver Loading Functions.
28 * Copyright (c) 2000 Apple Computer, Inc.
35 #define DRIVER_DEBUG 0
50 #define kXMLTagPList "plist "
51 #define kXMLTagDict "dict"
52 #define kXMLTagKey "key"
53 #define kXMLTagString "string"
54 #define kXMLTagInteger "integer"
55 #define kXMLTagData "data"
56 #define kXMLTagDate "date"
57 #define kXMLTagFalse "false/"
58 #define kXMLTagTrue "true/"
59 #define kXMLTagArray "array"
61 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
62 #define kPropCFBundleExecutable ("CFBundleExecutable")
63 #define kPropOSBundleRequired ("OSBundleRequired")
64 #define kPropOSBundleLibraries ("OSBundleLibraries")
65 #define kPropIOKitPersonalities ("IOKitPersonalities")
66 #define kPropIONameMatch ("IONameMatch")
74 typedef struct Tag Tag
, *TagPtr
;
77 struct Module
*nextModule
;
84 typedef struct Module Module
, *ModulePtr
;
92 typedef struct DriverInfo DriverInfo
, *DriverInfoPtr
;
94 #define kDriverPackageSignature1 'MKXT'
95 #define kDriverPackageSignature2 'MOSX'
97 struct DriversPackage
{
98 unsigned long signature1
;
99 unsigned long signature2
;
100 unsigned long length
;
101 unsigned long alder32
;
102 unsigned long version
;
103 unsigned long numDrivers
;
104 unsigned long reserved1
;
105 unsigned long reserved2
;
107 typedef struct DriversPackage DriversPackage
;
114 static long FileLoadDrivers(char *dirSpec
, long plugin
);
115 static long NetLoadDrivers(char *dirSpec
);
116 static long LoadDriverMKext(char *fileSpec
);
117 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
);
118 static long LoadMatchedModules(void);
119 static long MatchPersonalities(void);
120 static long MatchLibraries(void);
121 static TagPtr
GetProperty(TagPtr dict
, char *key
);
122 static ModulePtr
FindModule(char *name
);
123 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
);
124 static long ParseNextTag(char *buffer
, TagPtr
*tag
);
125 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
);
126 static long ParseTagKey(char *buffer
, TagPtr
*tag
);
127 static long ParseTagString(char *buffer
, TagPtr
*tag
);
128 static long ParseTagInteger(char *buffer
, TagPtr
*tag
);
129 static long ParseTagData(char *buffer
, TagPtr
*tag
);
130 static long ParseTagDate(char *buffer
, TagPtr
*tag
);
131 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
);
132 static long GetNextTag(char *buffer
, char **tag
, long *start
);
133 static long FixDataMatchingTag(char *buffer
, char *tag
);
134 static TagPtr
NewTag(void);
135 static void FreeTag(TagPtr tag
);
136 static char *NewSymbol(char *string
);
137 static void FreeSymbol(char *string
);
139 static void DumpTag(TagPtr tag
, long depth
);
142 static ModulePtr gModuleHead
, gModuleTail
;
143 static TagPtr gPersonalityHead
, gPersonalityTail
;
144 static char gDriverSpec
[4096];
145 static char gFileSpec
[4096];
146 static char gTempSpec
[4096];
147 static char gFileName
[4096];
151 long LoadDrivers(char *dirSpec
)
153 if (gBootFileType
== kNetworkDeviceType
) {
154 NetLoadDrivers(dirSpec
);
155 } else if (gBootFileType
== kBlockDeviceType
) {
156 FileLoadDrivers(dirSpec
, 0);
161 MatchPersonalities();
165 LoadMatchedModules();
172 static long FileLoadDrivers(char *dirSpec
, long plugin
)
174 long ret
, length
, index
, flags
, time
, time2
, bundleType
;
178 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
179 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
)) {
180 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
181 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
182 (((gBootMode
& kBootModeSafe
) == 0) && (time
> time2
))) {
183 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
184 printf("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
185 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
189 strcat(dirSpec
, "Extensions");
192 printf("LoadDrivers: Loading from [%s]\n", dirSpec
);
196 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
197 if (ret
== -1) break;
199 // Make sure this is a directory.
200 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
202 // Make sure this is a kext.
203 length
= strlen(name
);
204 if (strcmp(name
+ length
- 5, ".kext")) continue;
206 // Save the file name.
207 strcpy(gFileName
, name
);
209 // Determine the bundle type.
210 sprintf(gTempSpec
, "%s\\%s", dirSpec
, gFileName
);
211 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
212 if (ret
== 0) bundleType
= kCFBundleType2
;
213 else bundleType
= kCFBundleType3
;
216 sprintf(gDriverSpec
, "%s\\%s\\%sPlugIns", dirSpec
, gFileName
,
217 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
220 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
222 printf("LoadDrivers: failed\n");
226 ret
= FileLoadDrivers(gDriverSpec
, 1);
234 static long NetLoadDrivers(char *dirSpec
)
238 // Get the name of the kernel
239 cnt
= strlen(gBootFile
);
241 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
247 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, gBootFile
+ cnt
);
249 printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
253 if (LoadDriverMKext(gDriverSpec
) == 0) break;
255 if (tries
== -1) return -1;
261 static long LoadDriverMKext(char *fileSpec
)
263 unsigned long driversAddr
, driversLength
, length
;
265 DriversPackage
*package
= (DriversPackage
*)kLoadAddr
;
268 length
= LoadFile(fileSpec
);
269 if (length
== -1) return -1;
271 ThinFatBinary((void **)&package
, &length
);
274 if ((package
->signature1
!= kDriverPackageSignature1
) ||
275 (package
->signature2
!= kDriverPackageSignature2
)) return -1;
276 if (package
->length
> kLoadSize
) return -1;
277 if (package
->alder32
!= Alder32((char *)&package
->version
,
278 package
->length
- 0x10)) return -1;
280 // Make space for the MKext.
281 driversLength
= package
->length
;
282 driversAddr
= AllocateKernelMemory(driversLength
);
285 memcpy((void *)driversAddr
, (void *)package
, driversLength
);
287 // Add the MKext to the memory map.
288 sprintf(segName
, "DriversPackage-%x", driversAddr
);
289 AllocateMemoryRange(segName
, driversAddr
, driversLength
);
295 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
)
297 long length
, ret
, driverPathLength
;
300 TagPtr personalities
;
303 // Reset the malloc zone.
304 malloc_init((char *)kMallocAddr
, kMallocSize
);
306 // Save the driver path.
307 sprintf(gFileSpec
, "%s\\%s\\%s", dirSpec
, name
,
308 (bundleType
== kCFBundleType2
) ? "Contents\\MacOS\\" : "");
309 driverPathLength
= strlen(gFileSpec
);
310 tmpDriverPath
= malloc(driverPathLength
+ 1);
311 if (tmpDriverPath
== 0) return -1;
312 strcpy(tmpDriverPath
, gFileSpec
);
314 // Construct the file spec.
315 sprintf(gFileSpec
, "%s\\%s\\%sInfo.plist", dirSpec
, name
,
316 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
318 length
= LoadFile(gFileSpec
);
324 buffer
= malloc(length
+ 1);
329 strncpy(buffer
, (char *)kLoadAddr
, length
);
331 ret
= ParseXML(buffer
, &module, &personalities
);
338 // Allocate memory for the driver path and the plist.
339 module->driverPath
= AllocateBootXMemory(driverPathLength
+ 1);
340 module->plistAddr
= AllocateBootXMemory(length
+ 1);
342 if ((module->driverPath
== 0) | (module->plistAddr
== 0)) {
347 // Save the driver path in the module.
348 strcpy(module->driverPath
, tmpDriverPath
);
351 // Add the origin plist to the module.
352 strncpy(module->plistAddr
, (char *)kLoadAddr
, length
);
353 module->plistLength
= length
+ 1;
355 // Add the module to the end of the module list.
356 if (gModuleHead
== 0) gModuleHead
= module;
357 else gModuleTail
->nextModule
= module;
358 gModuleTail
= module;
360 // Add the persionalities to the personality list.
361 if (personalities
) personalities
= personalities
->tag
;
362 while (personalities
!= 0) {
363 if (gPersonalityHead
== 0) gPersonalityHead
= personalities
->tag
;
364 else gPersonalityTail
->tagNext
= personalities
->tag
;
365 gPersonalityTail
= personalities
->tag
;
367 personalities
= personalities
->tagNext
;
374 static long LoadMatchedModules(void)
378 char *fileName
, segName
[32];
379 DriverInfoPtr driver
;
380 unsigned long length
, driverAddr
, driverLength
;
381 void *driverModuleAddr
;
383 module = gModuleHead
;
384 while (module != 0) {
385 if (module->willLoad
) {
386 prop
= GetProperty(module->dict
, kPropCFBundleExecutable
);
388 fileName
= prop
->string
;
389 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
390 length
= LoadFile(gFileSpec
);
394 driverModuleAddr
= (void *)kLoadAddr
;
395 ThinFatBinary(&driverModuleAddr
, &length
);
398 // Make make in the image area.
399 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
400 driverAddr
= AllocateKernelMemory(driverLength
);
402 // Set up the DriverInfo.
403 driver
= (DriverInfoPtr
)driverAddr
;
404 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
405 driver
->plistLength
= module->plistLength
;
407 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
408 module->plistLength
);
409 driver
->moduleLength
= length
;
411 driver
->moduleAddr
= 0;
412 driver
->moduleLength
= 0;
415 // Save the plist and module.
416 strcpy(driver
->plistAddr
, module->plistAddr
);
418 memcpy(driver
->moduleAddr
, driverModuleAddr
, driver
->moduleLength
);
421 // Add an entry to the memory map.
422 sprintf(segName
, "Driver-%x", driver
);
423 AllocateMemoryRange(segName
, driverAddr
, driverLength
);
427 module = module->nextModule
;
434 static long MatchPersonalities(void)
441 // Try to match each of the personalities.
442 for(persionality
= gPersonalityHead
; persionality
!= 0;
443 persionality
= persionality
->tagNext
) {
444 // Get the module name. Make sure it exists and has not
445 // already been marked for loading.
446 prop
= GetProperty(persionality
, kPropCFBundleIdentifier
);
447 if (prop
== 0) continue;
448 module = FindModule(prop
->string
);
449 if (module == 0) continue;
450 if (module->willLoad
) continue;
452 // Look for the exact match property.
453 // Try to match with it.
455 // Look for the old match property.
456 // Try to match with it.
458 prop
= GetProperty(persionality
, kPropIONameMatch
);
459 if ((prop
!= 0) && (prop
->tag
!= 0)) prop
= prop
->tag
;
461 ph
= SearchForNodeMatching(0, 1, prop
->string
);
464 prop
= prop
->tagNext
;
467 // If a node was found mark the module to be loaded.
469 module->willLoad
= 1;
477 static long MatchLibraries(void)
480 ModulePtr
module, module2
;
485 module = gModuleHead
;
486 while (module != 0) {
487 if (module->willLoad
== 1) {
488 prop
= GetProperty(module->dict
, kPropOSBundleLibraries
);
492 module2
= gModuleHead
;
493 while (module2
!= 0) {
494 prop2
= GetProperty(module2
->dict
, kPropCFBundleIdentifier
);
495 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
))) {
496 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
499 module2
= module2
->nextModule
;
501 prop
= prop
->tagNext
;
504 module->willLoad
= 2;
507 module = module->nextModule
;
515 static TagPtr
GetProperty(TagPtr dict
, char *key
)
519 if (dict
->type
!= kTagTypeDict
) return 0;
525 tagList
= tag
->tagNext
;
527 if ((tag
->type
!= kTagTypeKey
) || (tag
->string
== 0)) continue;
529 if (!strcmp(tag
->string
, key
)) return tag
->tag
;
536 static ModulePtr
FindModule(char *name
)
541 module = gModuleHead
;
543 while (module != 0) {
544 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
545 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
546 module = module->nextModule
;
553 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
)
556 TagPtr moduleDict
, required
;
561 length
= ParseNextTag(buffer
+ pos
, &moduleDict
);
562 if (length
== -1) break;
565 if (moduleDict
== 0) continue;
567 if (moduleDict
->type
== kTagTypeDict
) break;
572 if (length
== -1) return -1;
574 required
= GetProperty(moduleDict
, kPropOSBundleRequired
);
575 if ((required
== 0) || (required
->type
!= kTagTypeString
) ||
576 !strcmp(required
->string
, "Safe Boot")) {
581 tmpModule
= AllocateBootXMemory(sizeof(Module
));
582 if (tmpModule
== 0) {
586 tmpModule
->dict
= moduleDict
;
588 // For now, load any module that has OSBundleRequired != "Safe Boot".
589 tmpModule
->willLoad
= 1;
593 // Get the personalities.
594 *personalities
= GetProperty(moduleDict
, kPropIOKitPersonalities
);
600 static long ParseNextTag(char *buffer
, TagPtr
*tag
)
605 length
= GetNextTag(buffer
, &tagName
, 0);
606 if (length
== -1) return -1;
609 if (!strncmp(tagName
, kXMLTagPList
, 6)) {
611 } else if (!strcmp(tagName
, kXMLTagDict
)) {
612 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeDict
, 0);
613 } else if (!strcmp(tagName
, kXMLTagDict
"/")) {
614 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeDict
, 1);
615 } else if (!strcmp(tagName
, kXMLTagKey
)) {
616 length
= ParseTagKey(buffer
+ pos
, tag
);
617 } else if (!strcmp(tagName
, kXMLTagString
)) {
618 length
= ParseTagString(buffer
+ pos
, tag
);
619 } else if (!strcmp(tagName
, kXMLTagInteger
)) {
620 length
= ParseTagInteger(buffer
+ pos
, tag
);
621 } else if (!strcmp(tagName
, kXMLTagData
)) {
622 length
= ParseTagData(buffer
+ pos
, tag
);
623 } else if (!strcmp(tagName
, kXMLTagDate
)) {
624 length
= ParseTagDate(buffer
+ pos
, tag
);
625 } else if (!strcmp(tagName
, kXMLTagFalse
)) {
626 length
= ParseTagBoolean(buffer
+ pos
, tag
, kTagTypeFalse
);
627 } else if (!strcmp(tagName
, kXMLTagTrue
)) {
628 length
= ParseTagBoolean(buffer
+ pos
, tag
, kTagTypeTrue
);
629 } else if (!strcmp(tagName
, kXMLTagArray
)) {
630 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeArray
, 0);
631 } else if (!strcmp(tagName
, kXMLTagArray
"/")) {
632 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeArray
, 1);
638 if (length
== -1) return -1;
644 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
)
647 TagPtr tagList
, tmpTag
;
654 length
= ParseNextTag(buffer
+ pos
, &tmpTag
);
655 if (length
== -1) break;
658 if (tmpTag
== 0) break;
659 tmpTag
->tagNext
= tagList
;
677 tmpTag
->tag
= tagList
;
686 static long ParseTagKey(char *buffer
, TagPtr
*tag
)
688 long length
, length2
;
690 TagPtr tmpTag
, subTag
;
692 length
= FixDataMatchingTag(buffer
, kXMLTagKey
);
693 if (length
== -1) return -1;
695 length2
= ParseNextTag(buffer
+ length
, &subTag
);
696 if (length2
== -1) return -1;
704 string
= NewSymbol(buffer
);
711 tmpTag
->type
= kTagTypeKey
;
712 tmpTag
->string
= string
;
713 tmpTag
->tag
= subTag
;
718 return length
+ length2
;
722 static long ParseTagString(char *buffer
, TagPtr
*tag
)
728 length
= FixDataMatchingTag(buffer
, kXMLTagString
);
729 if (length
== -1) return -1;
732 if (tmpTag
== 0) return -1;
734 string
= NewSymbol(buffer
);
740 tmpTag
->type
= kTagTypeString
;
741 tmpTag
->string
= string
;
751 static long ParseTagInteger(char *buffer
, TagPtr
*tag
)
753 long length
, integer
;
756 length
= FixDataMatchingTag(buffer
, kXMLTagInteger
);
757 if (length
== -1) return -1;
760 if (tmpTag
== 0) return -1;
764 tmpTag
->type
= kTagTypeInteger
;
765 tmpTag
->string
= (char *)integer
;
775 static long ParseTagData(char *buffer
, TagPtr
*tag
)
780 length
= FixDataMatchingTag(buffer
, kXMLTagData
);
781 if (length
== -1) return -1;
784 if (tmpTag
== 0) return -1;
786 tmpTag
->type
= kTagTypeData
;
797 static long ParseTagDate(char *buffer
, TagPtr
*tag
)
802 length
= FixDataMatchingTag(buffer
, kXMLTagDate
);
803 if (length
== -1) return -1;
806 if (tmpTag
== 0) return -1;
808 tmpTag
->type
= kTagTypeDate
;
819 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
)
824 if (tmpTag
== 0) return -1;
837 static long GetNextTag(char *buffer
, char **tag
, long *start
)
841 if (tag
== 0) return -1;
843 // Find the start of the tag.
845 while ((buffer
[cnt
] != '\0') && (buffer
[cnt
] != '<')) cnt
++;
846 if (buffer
[cnt
] == '\0') return -1;
848 // Find the end of the tag.
850 while ((buffer
[cnt2
] != '\0') && (buffer
[cnt2
] != '>')) cnt2
++;
851 if (buffer
[cnt2
] == '\0') return -1;
854 *tag
= buffer
+ cnt
+ 1;
856 if (start
) *start
= cnt
;
862 static long FixDataMatchingTag(char *buffer
, char *tag
)
864 long length
, start
, stop
;
869 length
= GetNextTag(buffer
+ start
, &endTag
, &stop
);
870 if (length
== -1) return -1;
872 if ((*endTag
== '/') && !strcmp(endTag
+ 1, tag
)) break;
876 buffer
[start
+ stop
] = '\0';
878 return start
+ length
;
882 #define kTagsPerBlock (0x1000)
884 static TagPtr gTagsFree
;
886 static TagPtr
NewTag(void)
891 if (gTagsFree
== 0) {
892 tag
= (TagPtr
)AllocateBootXMemory(kTagsPerBlock
* sizeof(Tag
));
893 if (tag
== 0) return 0;
895 // Initalize the new tags.
896 for (cnt
= 0; cnt
< kTagsPerBlock
; cnt
++) {
897 tag
[cnt
].type
= kTagTypeNone
;
900 tag
[cnt
].tagNext
= tag
+ cnt
+ 1;
902 tag
[kTagsPerBlock
- 1].tagNext
= 0;
908 gTagsFree
= tag
->tagNext
;
914 static void FreeTag(TagPtr tag
)
917 if (tag
== 0) return;
919 if (tag
->string
) FreeSymbol(tag
->string
);
922 FreeTag(tag
->tagNext
);
924 // Clear and free the tag.
925 tag
->type
= kTagTypeNone
;
928 tag
->tagNext
= gTagsFree
;
938 typedef struct Symbol Symbol
, *SymbolPtr
;
940 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
);
942 static SymbolPtr gSymbolsHead
;
945 static char *NewSymbol(char *string
)
949 // Look for string in the list of symbols.
950 symbol
= FindSymbol(string
, 0);
952 // Add the new symbol.
954 symbol
= AllocateBootXMemory(sizeof(Symbol
) + strlen(string
));
955 if (symbol
== 0) return 0;
957 // Set the symbol's data.
958 symbol
->refCount
= 0;
959 strcpy(symbol
->string
, string
);
961 // Add the symbol to the list.
962 symbol
->next
= gSymbolsHead
;
963 gSymbolsHead
= symbol
;
966 // Update the refCount and return the string.
968 return symbol
->string
;
972 static void FreeSymbol(char *string
)
975 SymbolPtr symbol
, prev
;
977 // Look for string in the list of symbols.
978 symbol
= FindSymbol(string
, &prev
);
979 if (symbol
== 0) return;
981 // Update the refCount.
984 if (symbol
->refCount
!= 0) return;
986 // Remove the symbol from the list.
987 if (prev
!= 0) prev
->next
= symbol
->next
;
988 else gSymbolsHead
= symbol
->next
;
990 // Free the symbol's memory.
996 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
)
998 SymbolPtr symbol
, prev
;
1000 symbol
= gSymbolsHead
;
1003 while (symbol
!= 0) {
1004 if (!strcmp(symbol
->string
, string
)) break;
1007 symbol
= symbol
->next
;
1010 if ((symbol
!= 0) && (prevSymbol
!= 0)) *prevSymbol
= prev
;
1016 static void DumpTagDict(TagPtr tag
, long depth
);
1017 static void DumpTagKey(TagPtr tag
, long depth
);
1018 static void DumpTagString(TagPtr tag
, long depth
);
1019 static void DumpTagInteger(TagPtr tag
, long depth
);
1020 static void DumpTagData(TagPtr tag
, long depth
);
1021 static void DumpTagDate(TagPtr tag
, long depth
);
1022 static void DumpTagBoolean(TagPtr tag
, long depth
);
1023 static void DumpTagArray(TagPtr tag
, long depth
);
1024 static void DumpSpaces(long depth
);
1026 static void DumpTag(TagPtr tag
, long depth
)
1028 if (tag
== 0) return;
1030 switch (tag
->type
) {
1032 DumpTagDict(tag
, depth
);
1036 DumpTagKey(tag
, depth
);
1039 case kTagTypeString
:
1040 DumpTagString(tag
, depth
);
1043 case kTagTypeInteger
:
1044 DumpTagInteger(tag
, depth
);
1048 DumpTagData(tag
, depth
);
1052 DumpTagDate(tag
, depth
);
1055 case kTagTypeFalse
:
1057 DumpTagBoolean(tag
, depth
);
1060 case kTagTypeArray
:
1061 DumpTagArray(tag
, depth
);
1070 static void DumpTagDict(TagPtr tag
, long depth
)
1074 if (tag
->tag
== 0) {
1076 printf("<%s/>\n", kXMLTagDict
);
1079 printf("<%s>\n", kXMLTagDict
);
1083 DumpTag(tagList
, depth
+ 1);
1084 tagList
= tagList
->tagNext
;
1088 printf("</%s>\n", kXMLTagDict
);
1093 static void DumpTagKey(TagPtr tag
, long depth
)
1096 printf("<%s>%s</%s>\n", kXMLTagKey
, tag
->string
, kXMLTagKey
);
1098 DumpTag(tag
->tag
, depth
);
1102 static void DumpTagString(TagPtr tag
, long depth
)
1105 printf("<%s>%s</%s>\n", kXMLTagString
, tag
->string
, kXMLTagString
);
1109 static void DumpTagInteger(TagPtr tag
, long depth
)
1112 printf("<%s>%x</%s>\n", kXMLTagInteger
, tag
->string
, kXMLTagInteger
);
1116 static void DumpTagData(TagPtr tag
, long depth
)
1119 printf("<%s>%x</%s>\n", kXMLTagData
, tag
->string
, kXMLTagData
);
1123 static void DumpTagDate(TagPtr tag
, long depth
)
1126 printf("<%s>%x</%s>\n", kXMLTagDate
, tag
->string
, kXMLTagDate
);
1130 static void DumpTagBoolean(TagPtr tag
, long depth
)
1133 printf("<%s>\n", (tag
->type
== kTagTypeTrue
) ? kXMLTagTrue
: kXMLTagFalse
);
1137 static void DumpTagArray(TagPtr tag
, long depth
)
1141 if (tag
->tag
== 0) {
1143 printf("<%s/>\n", kXMLTagArray
);
1146 printf("<%s>\n", kXMLTagArray
);
1150 DumpTag(tagList
, depth
+ 1);
1151 tagList
= tagList
->tagNext
;
1155 printf("</%s>\n", kXMLTagArray
);
1160 static void DumpSpaces(long depth
)
1164 for (cnt
= 0; cnt
< (depth
* 4); cnt
++) putchar(' ');