1 /*
2  * gjobread.c : a small test program for gnome jobs XML format
3  *
4  * See Copyright for the status of this software.
5  *
6  * Daniel.Veillard@w3.org
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 
13 /*
14  * This example should compile and run indifferently with libxml-1.8.8 +
15  * and libxml2-2.1.0 +
16  * Check the COMPAT comments below
17  */
18 
19 /*
20  * COMPAT using xml-config --cflags to get the include path this will
21  * work with both
22  */
23 #include <libxml/xmlmemory.h>
24 #include <libxml/parser.h>
25 
26 #define DEBUG(x) printf(x)
27 
28 /*
29  * A person record
30  * an xmlChar * is really an UTF8 encoded char string (0 terminated)
31  */
32 typedef struct person {
33     xmlChar *name;
34     xmlChar *email;
35     xmlChar *company;
36     xmlChar *organisation;
37     xmlChar *smail;
38     xmlChar *webPage;
39     xmlChar *phone;
40 } person, *personPtr;
41 
42 /*
43  * And the code needed to parse it
44  */
45 static personPtr
parsePerson(xmlDocPtr doc,xmlNsPtr ns,xmlNodePtr cur)46 parsePerson(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {
47     personPtr ret = NULL;
48 
49 DEBUG("parsePerson\n");
50     /*
51      * allocate the struct
52      */
53     ret = (personPtr) malloc(sizeof(person));
54     if (ret == NULL) {
55         fprintf(stderr,"out of memory\n");
56 	return(NULL);
57     }
58     memset(ret, 0, sizeof(person));
59 
60     /* We don't care what the top level element name is */
61     /* COMPAT xmlChildrenNode is a macro unifying libxml1 and libxml2 names */
62     cur = cur->xmlChildrenNode;
63     while (cur != NULL) {
64         if ((!xmlStrcmp(cur->name, (const xmlChar *)"Person")) &&
65 	    (cur->ns == ns))
66 	    ret->name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
67         if ((!xmlStrcmp(cur->name, (const xmlChar *)"Email")) &&
68 	    (cur->ns == ns))
69 	    ret->email = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
70 	cur = cur->next;
71     }
72 
73     return(ret);
74 }
75 
76 /*
77  * and to print it
78  */
79 static void
printPerson(personPtr cur)80 printPerson(personPtr cur) {
81     if (cur == NULL) return;
82     printf("------ Person\n");
83     if (cur->name) printf("	name: %s\n", cur->name);
84     if (cur->email) printf("	email: %s\n", cur->email);
85     if (cur->company) printf("	company: %s\n", cur->company);
86     if (cur->organisation) printf("	organisation: %s\n", cur->organisation);
87     if (cur->smail) printf("	smail: %s\n", cur->smail);
88     if (cur->webPage) printf("	Web: %s\n", cur->webPage);
89     if (cur->phone) printf("	phone: %s\n", cur->phone);
90     printf("------\n");
91 }
92 
93 /*
94  * a Description for a Job
95  */
96 typedef struct job {
97     xmlChar *projectID;
98     xmlChar *application;
99     xmlChar *category;
100     personPtr contact;
101     int nbDevelopers;
102     personPtr developers[100]; /* using dynamic alloc is left as an exercise */
103 } job, *jobPtr;
104 
105 /*
106  * And the code needed to parse it
107  */
108 static jobPtr
parseJob(xmlDocPtr doc,xmlNsPtr ns,xmlNodePtr cur)109 parseJob(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {
110     jobPtr ret = NULL;
111 
112 DEBUG("parseJob\n");
113     /*
114      * allocate the struct
115      */
116     ret = (jobPtr) malloc(sizeof(job));
117     if (ret == NULL) {
118         fprintf(stderr,"out of memory\n");
119 	return(NULL);
120     }
121     memset(ret, 0, sizeof(job));
122 
123     /* We don't care what the top level element name is */
124     cur = cur->xmlChildrenNode;
125     while (cur != NULL) {
126 
127         if ((!xmlStrcmp(cur->name, (const xmlChar *) "Project")) &&
128 	    (cur->ns == ns)) {
129 	    ret->projectID = xmlGetProp(cur, (const xmlChar *) "ID");
130 	    if (ret->projectID == NULL) {
131 		fprintf(stderr, "Project has no ID\n");
132 	    }
133 	}
134         if ((!xmlStrcmp(cur->name, (const xmlChar *) "Application")) &&
135             (cur->ns == ns))
136 	    ret->application =
137 		xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
138         if ((!xmlStrcmp(cur->name, (const xmlChar *) "Category")) &&
139 	    (cur->ns == ns))
140 	    ret->category =
141 		xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
142         if ((!xmlStrcmp(cur->name, (const xmlChar *) "Contact")) &&
143 	    (cur->ns == ns))
144 	    ret->contact = parsePerson(doc, ns, cur);
145 	cur = cur->next;
146     }
147 
148     return(ret);
149 }
150 
151 /*
152  * and to print it
153  */
154 static void
printJob(jobPtr cur)155 printJob(jobPtr cur) {
156     int i;
157 
158     if (cur == NULL) return;
159     printf("=======  Job\n");
160     if (cur->projectID != NULL) printf("projectID: %s\n", cur->projectID);
161     if (cur->application != NULL) printf("application: %s\n", cur->application);
162     if (cur->category != NULL) printf("category: %s\n", cur->category);
163     if (cur->contact != NULL) printPerson(cur->contact);
164     printf("%d developers\n", cur->nbDevelopers);
165 
166     for (i = 0;i < cur->nbDevelopers;i++) printPerson(cur->developers[i]);
167     printf("======= \n");
168 }
169 
170 /*
171  * A pool of Gnome Jobs
172  */
173 typedef struct gjob {
174     int nbJobs;
175     jobPtr jobs[500]; /* using dynamic alloc is left as an exercise */
176 } gJob, *gJobPtr;
177 
178 
179 static gJobPtr
parseGjobFile(char * filename)180 parseGjobFile(char *filename) {
181     xmlDocPtr doc;
182     gJobPtr ret;
183     jobPtr curjob;
184     xmlNsPtr ns;
185     xmlNodePtr cur;
186 
187 #ifdef LIBXML_SAX1_ENABLED
188     /*
189      * build an XML tree from a the file;
190      */
191     doc = xmlParseFile(filename);
192     if (doc == NULL) return(NULL);
193 #else
194     /*
195      * the library has been compiled without some of the old interfaces
196      */
197     return(NULL);
198 #endif /* LIBXML_SAX1_ENABLED */
199 
200     /*
201      * Check the document is of the right kind
202      */
203 
204     cur = xmlDocGetRootElement(doc);
205     if (cur == NULL) {
206         fprintf(stderr,"empty document\n");
207 	xmlFreeDoc(doc);
208 	return(NULL);
209     }
210     ns = xmlSearchNsByHref(doc, cur,
211 	    (const xmlChar *) "http://www.gnome.org/some-location");
212     if (ns == NULL) {
213         fprintf(stderr,
214 	        "document of the wrong type, GJob Namespace not found\n");
215 	xmlFreeDoc(doc);
216 	return(NULL);
217     }
218     if (xmlStrcmp(cur->name, (const xmlChar *) "Helping")) {
219         fprintf(stderr,"document of the wrong type, root node != Helping");
220 	xmlFreeDoc(doc);
221 	return(NULL);
222     }
223 
224     /*
225      * Allocate the structure to be returned.
226      */
227     ret = (gJobPtr) malloc(sizeof(gJob));
228     if (ret == NULL) {
229         fprintf(stderr,"out of memory\n");
230 	xmlFreeDoc(doc);
231 	return(NULL);
232     }
233     memset(ret, 0, sizeof(gJob));
234 
235     /*
236      * Now, walk the tree.
237      */
238     /* First level we expect just Jobs */
239     cur = cur->xmlChildrenNode;
240     while ( cur && xmlIsBlankNode ( cur ) ) {
241 	cur = cur -> next;
242     }
243     if ( cur == 0 ) {
244 	xmlFreeDoc(doc);
245 	free(ret);
246 	return ( NULL );
247     }
248     if ((xmlStrcmp(cur->name, (const xmlChar *) "Jobs")) || (cur->ns != ns)) {
249         fprintf(stderr,"document of the wrong type, was '%s', Jobs expected",
250 		cur->name);
251 	fprintf(stderr,"xmlDocDump follows\n");
252 #ifdef LIBXML_OUTPUT_ENABLED
253 	xmlDocDump ( stderr, doc );
254 	fprintf(stderr,"xmlDocDump finished\n");
255 #endif /* LIBXML_OUTPUT_ENABLED */
256 	xmlFreeDoc(doc);
257 	free(ret);
258 	return(NULL);
259     }
260 
261     /* Second level is a list of Job, but be laxist */
262     cur = cur->xmlChildrenNode;
263     while (cur != NULL) {
264         if ((!xmlStrcmp(cur->name, (const xmlChar *) "Job")) &&
265 	    (cur->ns == ns)) {
266 	    curjob = parseJob(doc, ns, cur);
267 	    if (curjob != NULL)
268 	        ret->jobs[ret->nbJobs++] = curjob;
269             if (ret->nbJobs >= 500) break;
270 	}
271 	cur = cur->next;
272     }
273 
274     return(ret);
275 }
276 
277 static void
handleGjob(gJobPtr cur)278 handleGjob(gJobPtr cur) {
279     int i;
280 
281     /*
282      * Do whatever you want and free the structure.
283      */
284     printf("%d Jobs registered\n", cur->nbJobs);
285     for (i = 0; i < cur->nbJobs; i++) printJob(cur->jobs[i]);
286 }
287 
main(int argc,char ** argv)288 int main(int argc, char **argv) {
289     int i;
290     gJobPtr cur;
291 
292     /* COMPAT: Do not genrate nodes for formatting spaces */
293     LIBXML_TEST_VERSION
294     xmlKeepBlanksDefault(0);
295 
296     for (i = 1; i < argc ; i++) {
297 	cur = parseGjobFile(argv[i]);
298 	if ( cur )
299 	  handleGjob(cur);
300 	else
301 	  fprintf( stderr, "Error parsing file '%s'\n", argv[i]);
302 
303     }
304 
305     /* Clean up everything else before quitting. */
306     xmlCleanupParser();
307 
308     return(0);
309 }
310