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
;
104 static long FileLoadDrivers(char *dirSpec
, long plugin
);
105 static long NetLoadDrivers(char *dirSpec
);
106 static long LoadDriverMKext(char *fileSpec
);
107 static long LoadDriverPList(char *dirSpec
, char *name
);
108 static long LoadMatchedModules(void);
109 static long MatchPersonalities(void);
110 static long MatchLibraries(void);
111 static TagPtr
GetProperty(TagPtr dict
, char *key
);
112 static ModulePtr
FindModule(char *name
);
113 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
);
114 static long ParseNextTag(char *buffer
, TagPtr
*tag
);
115 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
);
116 static long ParseTagKey(char *buffer
, TagPtr
*tag
);
117 static long ParseTagString(char *buffer
, TagPtr
*tag
);
118 static long ParseTagInteger(char *buffer
, TagPtr
*tag
);
119 static long ParseTagData(char *buffer
, TagPtr
*tag
);
120 static long ParseTagDate(char *buffer
, TagPtr
*tag
);
121 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
);
122 static long GetNextTag(char *buffer
, char **tag
, long *start
);
123 static long FixDataMatchingTag(char *buffer
, char *tag
);
124 static TagPtr
NewTag(void);
125 static void FreeTag(TagPtr tag
);
126 static char *NewSymbol(char *string
);
127 static void FreeSymbol(char *string
);
128 static void DumpTag(TagPtr tag
, long depth
);
130 static ModulePtr gModuleHead
, gModuleTail
;
131 static TagPtr gPersonalityHead
, gPersonalityTail
;
132 static char gExtensionsSpec
[4096];
133 static char gDriverSpec
[4096];
134 static char gFileSpec
[4096];
138 long LoadDrivers(char *dirSpec
)
140 if (gBootFileType
== kNetworkDeviceType
) {
141 NetLoadDrivers(dirSpec
);
142 } else if (gBootFileType
== kBlockDeviceType
) {
143 strcpy(gExtensionsSpec
, dirSpec
);
144 strcat(gExtensionsSpec
, "System\\Library\\");
145 FileLoadDrivers(gExtensionsSpec
, 0);
150 MatchPersonalities();
154 LoadMatchedModules();
161 static long FileLoadDrivers(char *dirSpec
, long plugin
)
163 long ret
, length
, index
, flags
, time
, time2
;
167 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
168 if ((ret
== 0) && (flags
== kFlatFileType
)) {
169 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
170 if ((ret
!= 0) || (flags
!= kDirectoryFileType
) || (time
> time2
)) {
171 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
172 printf("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
173 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
177 strcat(dirSpec
, "Extensions");
180 printf("LoadDrivers: Loading from [%s]\n", dirSpec
);
184 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
185 if (ret
== -1) break;
187 // Make sure this is a directory.
188 if (flags
!= kDirectoryFileType
) continue;
190 // Make sure this is a kext.
191 length
= strlen(name
);
192 if (strcmp(name
+ length
- 5, ".kext")) continue;
195 sprintf(gDriverSpec
, "%s\\%s\\Contents\\PlugIns", dirSpec
, name
);
197 ret
= LoadDriverPList(dirSpec
, name
);
199 printf("LoadDrivers: failed\n");
203 ret
= FileLoadDrivers(gDriverSpec
, 1);
210 static long NetLoadDrivers(char *dirSpec
)
214 // Get the name of the kernel
215 cnt
= strlen(gBootFile
);
217 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
223 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, gBootFile
+ cnt
);
225 printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
229 if (LoadDriverMKext(gDriverSpec
) == 0) break;
231 if (tries
== -1) return -1;
237 static long LoadDriverMKext(char *fileSpec
)
239 long driversAddr
, driversLength
;
241 DriversPackage
*package
= (DriversPackage
*)kLoadAddr
;
244 if (LoadFile(fileSpec
) == -1) return -1;
247 if ((package
->signature1
!= kDriverPackageSignature1
) ||
248 (package
->signature2
!= kDriverPackageSignature2
)) return -1;
249 if (package
->length
> kLoadSize
) return -1;
250 if (package
->alder32
!= Alder32((char *)&package
->version
,
251 package
->length
- 0x10)) return -1;
253 // Make space for the MKext.
254 driversLength
= package
->length
;
255 driversAddr
= AllocateKernelMemory(driversLength
);
258 memcpy((void *)driversAddr
, (void *)kLoadAddr
, driversLength
);
260 // Add the MKext to the memory map.
261 sprintf(segName
, "DriversPackage-%x", driversAddr
);
262 AllocateMemoryRange(segName
, driversAddr
, driversLength
);
268 static long LoadDriverPList(char *dirSpec
, char *name
)
270 long length
, ret
, driverPathLength
;
273 TagPtr personalities
;
276 // Save the driver path.
277 sprintf(gFileSpec
, "%s\\%s\\Contents\\MacOS\\", dirSpec
, name
);
278 driverPathLength
= strlen(gFileSpec
);
279 tmpDriverPath
= malloc(driverPathLength
+ 1);
280 if (tmpDriverPath
== 0) return -1;
281 strcpy(tmpDriverPath
, gFileSpec
);
283 // Construct the file spec.
284 sprintf(gFileSpec
, "%s\\%s\\Contents\\Info.plist", dirSpec
, name
);
286 length
= LoadFile(gFileSpec
);
292 buffer
= malloc(length
+ 1);
297 strncpy(buffer
, (char *)kLoadAddr
, length
);
299 ret
= ParseXML(buffer
, &module, &personalities
);
306 // Allocate memory for the driver path and the plist.
307 module->driverPath
= AllocateBootXMemory(driverPathLength
+ 1);
308 module->plistAddr
= AllocateBootXMemory(length
+ 1);
310 if ((module->driverPath
== 0) | (module->plistAddr
== 0)) {
315 // Save the driver path in the module.
316 strcpy(module->driverPath
, tmpDriverPath
);
319 // Add the origin plist to the module.
320 strncpy(module->plistAddr
, (char *)kLoadAddr
, length
);
321 module->plistLength
= length
+ 1;
323 // Add the module to the end of the module list.
324 if (gModuleHead
== 0) gModuleHead
= module;
325 else gModuleTail
->nextModule
= module;
326 gModuleTail
= module;
328 // Add the persionalities to the personality list.
329 if (personalities
) personalities
= personalities
->tag
;
330 while (personalities
!= 0) {
331 if (gPersonalityHead
== 0) gPersonalityHead
= personalities
->tag
;
332 else gPersonalityTail
->tagNext
= personalities
->tag
;
333 gPersonalityTail
= personalities
->tag
;
335 personalities
= personalities
->tagNext
;
342 static long LoadMatchedModules(void)
346 char *fileName
, segName
[32];
347 DriverInfoPtr driver
;
348 long length
, driverAddr
, driverLength
;
350 module = gModuleHead
;
351 while (module != 0) {
352 if (module->willLoad
) {
353 prop
= GetProperty(module->dict
, kPropCFBundleExecutable
);
355 fileName
= prop
->string
;
356 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
357 length
= LoadFile(gFileSpec
);
360 // Make make in the image area.
361 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
362 driverAddr
= AllocateKernelMemory(driverLength
);
364 // Set up the DriverInfo.
365 driver
= (DriverInfoPtr
)driverAddr
;
366 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
367 driver
->plistLength
= module->plistLength
;
369 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
370 module->plistLength
);
371 driver
->moduleLength
= length
;
373 driver
->moduleAddr
= 0;
374 driver
->moduleLength
= 0;
377 // Save the plist and module.
378 strcpy(driver
->plistAddr
, module->plistAddr
);
380 memcpy(driver
->moduleAddr
, (void *)kLoadAddr
, driver
->moduleLength
);
383 // Add an entry to the memory map.
384 sprintf(segName
, "Driver-%x", driver
);
385 AllocateMemoryRange(segName
, driverAddr
, driverLength
);
389 module = module->nextModule
;
396 static long MatchPersonalities(void)
403 // Try to match each of the personalities.
404 for(persionality
= gPersonalityHead
; persionality
!= 0;
405 persionality
= persionality
->tagNext
) {
406 // Get the module name. Make sure it exists and has not
407 // already been marked for loading.
408 prop
= GetProperty(persionality
, kPropCFBundleIdentifier
);
409 if (prop
== 0) continue;
410 module = FindModule(prop
->string
);
411 if (module == 0) continue;
412 if (module->willLoad
) continue;
414 // Look for the exact match property.
415 // Try to match with it.
417 // Look for the old match property.
418 // Try to match with it.
420 prop
= GetProperty(persionality
, kPropIONameMatch
);
421 if ((prop
!= 0) && (prop
->tag
!= 0)) prop
= prop
->tag
;
423 ph
= SearchForNodeMatching(0, 1, prop
->string
);
426 prop
= prop
->tagNext
;
429 // If a node was found mark the module to be loaded.
431 module->willLoad
= 1;
439 static long MatchLibraries(void)
442 ModulePtr
module, module2
;
447 module = gModuleHead
;
448 while (module != 0) {
449 if (module->willLoad
== 1) {
450 prop
= GetProperty(module->dict
, kPropOSBundleLibraries
);
454 module2
= gModuleHead
;
455 while (module2
!= 0) {
456 prop2
= GetProperty(module2
->dict
, kPropCFBundleIdentifier
);
457 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
))) {
458 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
461 module2
= module2
->nextModule
;
463 prop
= prop
->tagNext
;
466 module->willLoad
= 2;
469 module = module->nextModule
;
477 static TagPtr
GetProperty(TagPtr dict
, char *key
)
481 if (dict
->type
!= kTagTypeDict
) return 0;
487 tagList
= tag
->tagNext
;
489 if ((tag
->type
!= kTagTypeKey
) || (tag
->string
== 0)) continue;
491 if (!strcmp(tag
->string
, key
)) return tag
->tag
;
498 static ModulePtr
FindModule(char *name
)
503 module = gModuleHead
;
505 while (module != 0) {
506 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
507 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
508 module = module->nextModule
;
515 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
)
518 TagPtr moduleDict
, required
;
523 length
= ParseNextTag(buffer
+ pos
, &moduleDict
);
524 if (length
== -1) break;
527 if (moduleDict
== 0) continue;
529 if (moduleDict
->type
== kTagTypeDict
) break;
534 if (length
== -1) return -1;
536 required
= GetProperty(moduleDict
, kPropOSBundleRequired
);
537 if ((required
== 0) || (required
->type
!= kTagTypeString
) ||
538 !strcmp(required
->string
, "Safe Boot")) {
543 tmpModule
= AllocateBootXMemory(sizeof(Module
));
544 if (tmpModule
== 0) {
548 tmpModule
->dict
= moduleDict
;
550 // For now, load any module that has OSBundleRequired != "Safe Boot".
551 tmpModule
->willLoad
= 1;
555 // Get the personalities.
556 *personalities
= GetProperty(moduleDict
, kPropIOKitPersonalities
);
562 static long ParseNextTag(char *buffer
, TagPtr
*tag
)
567 length
= GetNextTag(buffer
, &tagName
, 0);
568 if (length
== -1) return -1;
571 if (!strncmp(tagName
, kXMLTagPList
, 6)) {
573 } else if (!strcmp(tagName
, kXMLTagDict
)) {
574 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeDict
, 0);
575 } else if (!strcmp(tagName
, kXMLTagDict
"/")) {
576 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeDict
, 1);
577 } else if (!strcmp(tagName
, kXMLTagKey
)) {
578 length
= ParseTagKey(buffer
+ pos
, tag
);
579 } else if (!strcmp(tagName
, kXMLTagString
)) {
580 length
= ParseTagString(buffer
+ pos
, tag
);
581 } else if (!strcmp(tagName
, kXMLTagInteger
)) {
582 length
= ParseTagInteger(buffer
+ pos
, tag
);
583 } else if (!strcmp(tagName
, kXMLTagData
)) {
584 length
= ParseTagData(buffer
+ pos
, tag
);
585 } else if (!strcmp(tagName
, kXMLTagDate
)) {
586 length
= ParseTagDate(buffer
+ pos
, tag
);
587 } else if (!strcmp(tagName
, kXMLTagFalse
)) {
588 length
= ParseTagBoolean(buffer
+ pos
, tag
, kTagTypeFalse
);
589 } else if (!strcmp(tagName
, kXMLTagTrue
)) {
590 length
= ParseTagBoolean(buffer
+ pos
, tag
, kTagTypeTrue
);
591 } else if (!strcmp(tagName
, kXMLTagArray
)) {
592 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeArray
, 0);
593 } else if (!strcmp(tagName
, kXMLTagArray
"/")) {
594 length
= ParseTagList(buffer
+ pos
, tag
, kTagTypeArray
, 1);
600 if (length
== -1) return -1;
606 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
)
609 TagPtr tagList
, tmpTag
;
616 length
= ParseNextTag(buffer
+ pos
, &tmpTag
);
617 if (length
== -1) break;
620 if (tmpTag
== 0) break;
621 tmpTag
->tagNext
= tagList
;
639 tmpTag
->tag
= tagList
;
648 static long ParseTagKey(char *buffer
, TagPtr
*tag
)
650 long length
, length2
;
652 TagPtr tmpTag
, subTag
;
654 length
= FixDataMatchingTag(buffer
, kXMLTagKey
);
655 if (length
== -1) return -1;
657 length2
= ParseNextTag(buffer
+ length
, &subTag
);
658 if (length2
== -1) return -1;
666 string
= NewSymbol(buffer
);
673 tmpTag
->type
= kTagTypeKey
;
674 tmpTag
->string
= string
;
675 tmpTag
->tag
= subTag
;
680 return length
+ length2
;
684 static long ParseTagString(char *buffer
, TagPtr
*tag
)
690 length
= FixDataMatchingTag(buffer
, kXMLTagString
);
691 if (length
== -1) return -1;
694 if (tmpTag
== 0) return -1;
696 string
= NewSymbol(buffer
);
702 tmpTag
->type
= kTagTypeString
;
703 tmpTag
->string
= string
;
713 static long ParseTagInteger(char *buffer
, TagPtr
*tag
)
715 long length
, integer
;
718 length
= FixDataMatchingTag(buffer
, kXMLTagInteger
);
719 if (length
== -1) return -1;
722 if (tmpTag
== 0) return -1;
726 tmpTag
->type
= kTagTypeInteger
;
727 tmpTag
->string
= (char *)integer
;
737 static long ParseTagData(char *buffer
, TagPtr
*tag
)
742 length
= FixDataMatchingTag(buffer
, kXMLTagData
);
743 if (length
== -1) return -1;
746 if (tmpTag
== 0) return -1;
748 tmpTag
->type
= kTagTypeData
;
759 static long ParseTagDate(char *buffer
, TagPtr
*tag
)
764 length
= FixDataMatchingTag(buffer
, kXMLTagDate
);
765 if (length
== -1) return -1;
768 if (tmpTag
== 0) return -1;
770 tmpTag
->type
= kTagTypeDate
;
781 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
)
786 if (tmpTag
== 0) return -1;
799 static long GetNextTag(char *buffer
, char **tag
, long *start
)
803 if (tag
== 0) return -1;
805 // Find the start of the tag.
807 while ((buffer
[cnt
] != '\0') && (buffer
[cnt
] != '<')) cnt
++;
808 if (buffer
[cnt
] == '\0') return -1;
810 // Find the end of the tag.
812 while ((buffer
[cnt2
] != '\0') && (buffer
[cnt2
] != '>')) cnt2
++;
813 if (buffer
[cnt2
] == '\0') return -1;
816 *tag
= buffer
+ cnt
+ 1;
818 if (start
) *start
= cnt
;
824 static long FixDataMatchingTag(char *buffer
, char *tag
)
826 long length
, start
, stop
;
831 length
= GetNextTag(buffer
+ start
, &endTag
, &stop
);
832 if (length
== -1) return -1;
834 if ((*endTag
== '/') && !strcmp(endTag
+ 1, tag
)) break;
838 buffer
[start
+ stop
] = '\0';
840 return start
+ length
;
844 #define kTagsPerBlock (0x1000)
846 static TagPtr gTagsFree
;
848 static TagPtr
NewTag(void)
853 if (gTagsFree
== 0) {
854 tag
= (TagPtr
)AllocateBootXMemory(kTagsPerBlock
* sizeof(Tag
));
855 if (tag
== 0) return 0;
857 // Initalize the new tags.
858 for (cnt
= 0; cnt
< kTagsPerBlock
; cnt
++) {
859 tag
[cnt
].type
= kTagTypeNone
;
862 tag
[cnt
].tagNext
= tag
+ cnt
+ 1;
864 tag
[kTagsPerBlock
- 1].tagNext
= 0;
870 gTagsFree
= tag
->tagNext
;
876 static void FreeTag(TagPtr tag
)
879 if (tag
== 0) return;
881 if (tag
->string
) FreeSymbol(tag
->string
);
884 FreeTag(tag
->tagNext
);
886 // Clear and free the tag.
887 tag
->type
= kTagTypeNone
;
890 tag
->tagNext
= gTagsFree
;
900 typedef struct Symbol Symbol
, *SymbolPtr
;
902 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
);
904 static SymbolPtr gSymbolsHead
;
907 static char *NewSymbol(char *string
)
911 // Look for string in the list of symbols.
912 symbol
= FindSymbol(string
, 0);
914 // Add the new symbol.
916 symbol
= AllocateBootXMemory(sizeof(Symbol
) + strlen(string
));
917 if (symbol
== 0) return 0;
919 // Set the symbol's data.
920 symbol
->refCount
= 0;
921 strcpy(symbol
->string
, string
);
923 // Add the symbol to the list.
924 symbol
->next
= gSymbolsHead
;
925 gSymbolsHead
= symbol
;
928 // Update the refCount and return the string.
930 return symbol
->string
;
934 static void FreeSymbol(char *string
)
937 SymbolPtr symbol
, prev
;
939 // Look for string in the list of symbols.
940 symbol
= FindSymbol(string
, &prev
);
941 if (symbol
== 0) return;
943 // Update the refCount.
946 if (symbol
->refCount
!= 0) return;
948 // Remove the symbol from the list.
949 if (prev
!= 0) prev
->next
= symbol
->next
;
950 else gSymbolsHead
= symbol
->next
;
952 // Free the symbol's memory.
958 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
)
960 SymbolPtr symbol
, prev
;
962 symbol
= gSymbolsHead
;
965 while (symbol
!= 0) {
966 if (!strcmp(symbol
->string
, string
)) break;
969 symbol
= symbol
->next
;
972 if ((symbol
!= 0) && (prevSymbol
!= 0)) *prevSymbol
= prev
;
978 static void DumpTagDict(TagPtr tag
, long depth
);
979 static void DumpTagKey(TagPtr tag
, long depth
);
980 static void DumpTagString(TagPtr tag
, long depth
);
981 static void DumpTagInteger(TagPtr tag
, long depth
);
982 static void DumpTagData(TagPtr tag
, long depth
);
983 static void DumpTagDate(TagPtr tag
, long depth
);
984 static void DumpTagBoolean(TagPtr tag
, long depth
);
985 static void DumpTagArray(TagPtr tag
, long depth
);
986 static void DumpSpaces(long depth
);
988 static void DumpTag(TagPtr tag
, long depth
)
990 if (tag
== 0) return;
994 DumpTagDict(tag
, depth
);
998 DumpTagKey(tag
, depth
);
1001 case kTagTypeString
:
1002 DumpTagString(tag
, depth
);
1005 case kTagTypeInteger
:
1006 DumpTagInteger(tag
, depth
);
1010 DumpTagData(tag
, depth
);
1014 DumpTagDate(tag
, depth
);
1017 case kTagTypeFalse
:
1019 DumpTagBoolean(tag
, depth
);
1022 case kTagTypeArray
:
1023 DumpTagArray(tag
, depth
);
1032 static void DumpTagDict(TagPtr tag
, long depth
)
1036 if (tag
->tag
== 0) {
1038 printf("<%s/>\n", kXMLTagDict
);
1041 printf("<%s>\n", kXMLTagDict
);
1045 DumpTag(tagList
, depth
+ 1);
1046 tagList
= tagList
->tagNext
;
1050 printf("</%s>\n", kXMLTagDict
);
1055 static void DumpTagKey(TagPtr tag
, long depth
)
1058 printf("<%s>%s</%s>\n", kXMLTagKey
, tag
->string
, kXMLTagKey
);
1060 DumpTag(tag
->tag
, depth
);
1064 static void DumpTagString(TagPtr tag
, long depth
)
1067 printf("<%s>%s</%s>\n", kXMLTagString
, tag
->string
, kXMLTagString
);
1071 static void DumpTagInteger(TagPtr tag
, long depth
)
1074 printf("<%s>%x</%s>\n", kXMLTagInteger
, tag
->string
, kXMLTagInteger
);
1078 static void DumpTagData(TagPtr tag
, long depth
)
1081 printf("<%s>%x</%s>\n", kXMLTagData
, tag
->string
, kXMLTagData
);
1085 static void DumpTagDate(TagPtr tag
, long depth
)
1088 printf("<%s>%x</%s>\n", kXMLTagDate
, tag
->string
, kXMLTagDate
);
1092 static void DumpTagBoolean(TagPtr tag
, long depth
)
1095 printf("<%s>\n", (tag
->type
== kTagTypeTrue
) ? kXMLTagTrue
: kXMLTagFalse
);
1099 static void DumpTagArray(TagPtr tag
, long depth
)
1103 if (tag
->tag
== 0) {
1105 printf("<%s/>\n", kXMLTagArray
);
1108 printf("<%s>\n", kXMLTagArray
);
1112 DumpTag(tagList
, depth
+ 1);
1113 tagList
= tagList
->tagNext
;
1117 printf("</%s>\n", kXMLTagArray
);
1122 static void DumpSpaces(long depth
)
1126 for (cnt
= 0; cnt
< (depth
* 4); cnt
++) putchar(' ');