"Initial commit to Gerrit"
[profile/ivi/libcroco.git] / csslint / csslint.c
1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
2
3 /*
4  * csslint.c : a small tester program for libcroco.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2.1 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  *
20  * Initial Author: Gael Chamoulaud.
21  * Main programmer: Dodji Seketeli
22  * Contributor: Rob Buis
23  * See COPYRGIGHTS file for copyright information.
24  */
25
26 #include "libcroco.h"
27 #include <libxml/xpath.h>
28
29 #include <glib.h>
30 #include <string.h>
31
32 /**
33  *The options data structure.
34  *The variable of this data structure are set
35  *during the  parsing the command line by the
36  *parse_command_line() function.
37  */
38 struct Options {
39         gboolean show_version;
40         gboolean use_cssom;
41         gboolean display_help;
42         gboolean evaluate;
43         gboolean dump_location;
44         gchar *author_sheet_path;
45         gchar *user_sheet_path;
46         gchar *ua_sheet_path;
47         gchar *xml_path;
48         gchar *xpath;
49         gchar **css_files_list;
50 };
51
52 struct SacContext {
53         gint level;
54
55 };
56
57 static enum CRStatus sac_parse_and_display_locations (guchar * a_file_uri);
58
59 static void parse_cmd_line (int a_argc, char **a_argv,
60                             struct Options *a_options);
61
62 static void display_version (void);
63
64 static void display_usage (void);
65
66 static enum CRStatus cssom_parse (guchar * a_file_uri);
67
68 static enum CRStatus get_and_dump_node_style (xmlNode * a_node,
69                                               CRSelEng * a_sel_eng,
70                                               CRCascade * a_cascade);
71
72 static enum CRStatus evaluate_selectors (gchar * a_xml_path,
73                                          gchar * a_author_sheet_path,
74                                          gchar * a_user_sheet_path,
75                                          gchar * a_ua_sheet_path,
76                                          gchar * a_xpath);
77
78 /**
79  *Parses the command line.
80  *@param a_argc the argc parameter of the main routine.
81  *@param the argv parameter of the main routine.
82  *@param a_options out parameter the parsed options.
83  */
84 static void
85 parse_cmd_line (int a_argc, char **a_argv, struct Options *a_options)
86 {
87         int i = 0;
88
89         g_return_if_fail (a_options);
90
91         if (a_argc <= 1) {
92                 display_usage ();
93         }
94
95         for (i = 1; i < a_argc; i++) {
96                 if (a_argv[i][0] != '-')
97                         break;
98
99                 if ((!strcmp (a_argv[i], "-version")) ||
100                     (!strcmp (a_argv[i], "-v"))) {
101                         a_options->show_version = TRUE;
102                 } else if (!strcmp (a_argv[i], "--evaluate") ||
103                            !strcmp (a_argv[i], "-e")) {
104                         for (i++; i < a_argc; i++) {
105                                 if (!strcmp (a_argv[i], "--author-sheet")) {
106                                         if (a_options->author_sheet_path) {
107                                                 display_usage ();
108                                                 exit (-1);
109                                         }
110                                         i++;
111                                         if (i >= a_argc
112                                             || a_argv[i][0] == '-') {
113                                                 g_print ("--author-sheet should be followed by a path to the sheet\n");
114                                                 display_usage ();
115                                                 exit (-1);
116                                         }
117                                         a_options->author_sheet_path =
118                                                 a_argv[i];
119                                 } else if (!strcmp
120                                            (a_argv[i], "--user-sheet")) {
121                                         if (a_options->user_sheet_path) {
122                                                 display_usage ();
123                                                 exit (-1);
124                                         }
125                                         i++;
126                                         if (i >= a_argc
127                                             || a_argv[i][0] == '-') {
128                                                 g_print ("--user-sheet should be followed by a path to the sheet\n");
129                                                 display_usage ();
130                                                 exit (-1);
131                                         }
132                                         a_options->user_sheet_path =
133                                                 a_argv[i];
134                                 } else if (!strcmp (a_argv[i], "--ua-sheet")) {
135                                         if (a_options->ua_sheet_path) {
136                                                 display_usage ();
137                                                 exit (-1);
138                                         }
139                                         i++;
140                                         if (i >= a_argc
141                                             || a_argv[i][0] == '-') {
142                                                 g_print ("--ua-sheet should be followed by a path to the sheet\n");
143                                                 display_usage ();
144                                                 exit (-1);
145                                         }
146                                         a_options->ua_sheet_path = a_argv[i];
147                                 } else if (!strcmp (a_argv[i], "--xml")) {
148                                         i++;
149                                         if (i >= a_argc
150                                             || a_argv[i][0] == '-') {
151                                                 g_print ("--xml should be followed by a path to the xml document\n");
152                                                 display_usage ();
153                                                 exit (-1);
154                                         }
155                                         a_options->xml_path = a_argv[i];
156                                 } else if (!strcmp (a_argv[i], "--xpath")) {
157                                         i++;
158                                         if (i >= a_argc
159                                             || a_argv[i][0] == '-') {
160                                                 g_print ("--xpath should be followed by an xpath expresion\n");
161                                                 display_usage ();
162                                                 exit (-1);
163                                         }
164                                         a_options->xpath = a_argv[i];
165                                 } else {
166                                         break;
167                                 }
168                         }
169                         if (!a_options->author_sheet_path
170                             && !a_options->user_sheet_path &&
171                             !a_options->ua_sheet_path) {
172                                 g_print ("Error: you must specify at least one stylesheet\n");
173                                 display_usage ();
174                                 exit (-1);
175
176                         }
177                         if (!a_options->xpath) {
178                                 g_printerr
179                                         ("Error: you must specify an xpath expression using the --xpath option\n");
180                                 display_usage ();
181                                 exit (-1);
182
183                         }
184                         a_options->evaluate = TRUE;
185                 } else if (!strcmp (a_argv[i], "--dump-location")) {
186                         a_options->dump_location = TRUE;
187                         a_options->use_cssom = FALSE;
188                 } else if (!strcmp (a_argv[i], "--help") ||
189                            !strcmp (a_argv[i], "-h")) {
190                         a_options->display_help = TRUE;
191                 } else {
192                         display_usage ();
193                         exit (-1);
194                 }
195         }
196
197         if (i >= a_argc) {
198                 a_options->css_files_list = NULL;
199         } else {
200                 if (a_argv[i][0] == '-') {
201                         display_usage ();
202                         exit (-1);
203                 }
204                 a_options->css_files_list = &a_argv[i];
205         }
206 }
207
208 /**
209  *Displays the version text.
210  *@param a_argc the argc variable passed to the main function.
211  *@param a_argv the argv variable passed to the main function.
212  */
213 static void
214 display_version (void)
215 {
216         g_print ("%s\n", LIBCROCO_VERSION);
217 }
218
219 /**
220  *Displays the usage text.
221  *@param a_argc the argc variable passed to the main function.
222  *@param a_argv the argv variable passed to the main function.
223  */
224 static void
225 display_usage (void)
226 {
227         g_print ("Usage: csslint <path to a css file>\n");
228         g_print ("\t| csslint -v|--version\n");
229         g_print ("\t| csslint --dump-location <path to a css file>\n");
230         g_print ("\t| csslint <--evaluate | -e> [--author-sheet <path> --user-sheet <path> --ua-sheet <path>\n\t   ] --xml <path> --xpath <xpath expression>\n");
231 }
232
233 /**
234  *The test of the cr_input_read_byte() method.
235  *Reads the each byte of a_file_uri using the
236  *cr_input_read_byte() method. Each byte is send to
237  *stdout.
238  *@param a_file_uri the file to read.
239  *@return CR_OK upon successfull completion of the
240  *function, an error code otherwise.
241  */
242 static enum CRStatus
243 cssom_parse (guchar * a_file_uri)
244 {
245         enum CRStatus status = CR_OK;
246         CROMParser *parser = NULL;
247         CRStyleSheet *stylesheet = NULL;
248
249         g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR);
250
251         parser = cr_om_parser_new (NULL);
252         status = cr_om_parser_parse_file (parser,
253                                           a_file_uri, CR_ASCII, &stylesheet);
254         if (status == CR_OK && stylesheet) {
255                 cr_stylesheet_dump (stylesheet, stdout);
256                 g_print ("\n");
257                 cr_stylesheet_destroy (stylesheet);
258         }
259         cr_om_parser_destroy (parser);
260
261         return status;
262 }
263
264 static enum CRStatus
265 get_and_dump_node_style (xmlNode * a_node,
266                          CRSelEng * a_sel_eng, CRCascade * a_cascade)
267 {
268         CRPropList *prop_list = NULL,
269                 *pair = NULL,
270                 *prev_pair = NULL;
271         enum CRStatus status = CR_OK;
272
273         g_return_val_if_fail (a_node && a_sel_eng && a_cascade,
274                               CR_BAD_PARAM_ERROR);
275
276         status = cr_sel_eng_get_matched_properties_from_cascade
277                 (a_sel_eng, a_cascade, a_node, &prop_list);
278         if (status != CR_OK) {
279                 g_printerr ("Error: unable to run the selection engine\n");
280                 return CR_OK;
281         }
282         g_print ("Properties of xml element %s are:\n", a_node->name);
283         for (pair = prop_list; pair; pair = cr_prop_list_get_next (pair)) {
284                 CRDeclaration *decl = NULL;
285
286                 cr_prop_list_get_decl (pair, &decl);
287                 if (decl) {
288                         prev_pair = cr_prop_list_get_prev (pair);
289                         if (prev_pair) {
290                                 g_print ("\n");
291                                 prev_pair = NULL;
292                         }
293                         cr_declaration_dump_one (decl, stdout, 2);
294                         decl = NULL;
295                 }
296         }
297         g_print ("\n=====================\n\n");
298
299         if (prop_list) {
300                 cr_prop_list_destroy (prop_list);
301                 prop_list = NULL;
302         }
303
304         return CR_OK;
305 }
306
307 static enum CRStatus
308 evaluate_selectors (gchar * a_xml_path,
309                     gchar * a_author_sheet_path,
310                     gchar * a_user_sheet_path,
311                     gchar * a_ua_sheet_path, gchar * a_xpath)
312 {
313         CRSelEng *sel_eng = NULL;
314         xmlDoc *xml_doc = NULL;
315         xmlXPathContext *xpath_context = NULL;
316         xmlXPathObject *xpath_object = NULL;
317         CRStyleSheet *author_sheet = NULL,
318                 *user_sheet = NULL,
319                 *ua_sheet = NULL;
320         CRCascade *cascade = NULL;
321         xmlNode *cur_node = NULL;
322         gint i = 0;
323         enum CRStatus status = CR_OK;
324
325         g_return_val_if_fail (a_xml_path && a_xpath, CR_BAD_PARAM_ERROR);
326
327         xml_doc = xmlParseFile (a_xml_path);
328         if (!xml_doc) {
329                 g_printerr ("Error: Could not parse file %s\n", a_xml_path);
330                 return CR_ERROR;
331         }
332         if (a_author_sheet_path) {
333                 status = cr_om_parser_simply_parse_file
334                         (a_author_sheet_path, CR_ASCII, &author_sheet);
335                 if (!author_sheet) {
336                         g_printerr ("Error: Could not parse author sheet\n");
337                 }
338         }
339         if (a_user_sheet_path) {
340                 status = cr_om_parser_simply_parse_file
341                         (a_user_sheet_path, CR_ASCII, &user_sheet);
342                 if (!user_sheet) {
343                         g_printerr ("Error: Could not parse author sheet\n");
344                 }
345         }
346         if (a_ua_sheet_path) {
347                 status = cr_om_parser_simply_parse_file
348                         (a_ua_sheet_path, CR_ASCII, &ua_sheet);
349                 if (!ua_sheet) {
350                         g_printerr ("Error: Could not parse ua sheet\n");
351                 }
352         }
353         cascade = cr_cascade_new (author_sheet, user_sheet, ua_sheet);
354         if (!cascade) {
355                 g_printerr ("Could not instanciate the cascade\n");
356                 return CR_ERROR;
357         }
358         sel_eng = cr_sel_eng_new ();
359         if (!sel_eng) {
360                 g_printerr
361                         ("Error: Could not instanciate the selection engine\n");
362                 return CR_ERROR;
363         }
364         xpath_context = xmlXPathNewContext (xml_doc);
365         if (!xpath_context) {
366                 g_printerr
367                         ("Error: Could not instanciate the xpath context\n");
368                 return CR_ERROR;
369         }
370         xpath_object = xmlXPathEvalExpression (a_xpath, xpath_context);
371         if (!xpath_object) {
372                 g_printerr ("Error: Could not evaluate xpath expression\n");
373                 return CR_ERROR;
374         }
375         if (xpath_object->type != XPATH_NODESET || !xpath_object->nodesetval) {
376                 g_printerr
377                         ("Error: xpath does not evalualuate to a node set\n");
378                 return CR_ERROR;
379         }
380
381         for (i = 0; i < xpath_object->nodesetval->nodeNr; i++) {
382                 cur_node = xpath_object->nodesetval->nodeTab[i];
383                 if (cur_node->type == XML_ELEMENT_NODE) {
384                         status = get_and_dump_node_style (cur_node, sel_eng,
385                                                           cascade);
386                 }
387         }
388
389         if (xpath_context) {
390                 xmlXPathFreeContext (xpath_context);
391                 xpath_context = NULL;
392         }
393         if (xpath_context) {
394                 xmlXPathFreeObject (xpath_object);
395                 xpath_object = NULL;
396         }
397         if (sel_eng) {
398                 cr_sel_eng_destroy (sel_eng);
399                 sel_eng = NULL;
400         }
401         if (cascade) {
402                 cr_cascade_destroy (cascade);
403         }
404         return CR_OK;
405 }
406
407 /***************************
408  *SAC related stuff for the
409  *line/col annotation stylesheet
410  *dumping
411  ***************************/
412 static void
413 start_document (CRDocHandler * a_this)
414 {
415         struct SacContext *context = NULL;
416
417         g_return_if_fail (a_this);
418
419         context = g_try_malloc (sizeof (struct SacContext));
420         if (!context) {
421                 cr_utils_trace_info ("instanciation of sac context failed");
422                 return;
423         }
424         cr_doc_handler_set_ctxt (a_this, context);
425 }
426
427 static void
428 end_document (CRDocHandler * a_this)
429 {
430         struct SacContext *context = NULL;
431
432         g_return_if_fail (a_this);
433
434         cr_doc_handler_get_ctxt (a_this, (gpointer *) (gpointer) & context);
435         if (context) {
436                 g_free (context);
437                 context = NULL;
438         }
439 }
440
441 static void
442 charset (CRDocHandler *a_this, 
443          CRString *a_charset,
444          CRParsingLocation *a_charset_sym_location)
445 {
446         gchar *str = NULL ;
447
448         g_return_if_fail (a_this && a_charset && a_charset_sym_location) ;
449
450         str = (gchar*)cr_string_peek_raw_str (a_charset) ;
451         if (str) {
452                 g_print ("\n\n@charset \"%s\";\n\n", str) ;
453                 str = NULL ;
454         } else {
455                 return ;
456         }
457         g_print ("/********************************************\n") ;
458         g_print (" * Parsing location information of the @charset rule\n") ;
459         g_print (" ********************************************/\n") ;
460         if (a_charset_sym_location) {
461                 str = cr_parsing_location_to_string (a_charset_sym_location, 0) ;
462                 if (str) {
463                         g_print ("  /*@charset*/\n") ;
464                         g_print ("  /*%s*/\n", str) ;
465                         g_free (str) ;
466                         str = NULL ;
467                 }
468         }
469         str = (gchar*) cr_string_peek_raw_str (a_charset) ;
470         if (str) {
471                 g_print ("  /*%s*/\n", str) ;
472                 str = NULL ;
473         }
474         str = cr_parsing_location_to_string (&a_charset->location, 0) ;
475         if (str) {
476                 g_print ("  /*%s*/\n\n", str) ;
477                 g_free (str) ;
478                 str = NULL ;
479         }
480 }
481
482 static void
483 import_style (CRDocHandler *a_this,
484               GList *a_media_list,
485               CRString *a_uri,
486               CRString *a_uri_default_ns,
487               CRParsingLocation *a_location)
488 {
489         gchar *str = NULL ;
490         GString *gstr = NULL ;
491         GList *cur_media = NULL ;
492
493         g_return_if_fail (a_this && a_location) ;
494
495         gstr = g_string_new (NULL) ;
496         if (!gstr) {
497                 cr_utils_trace_info ("Out of memory error") ;
498                 return ;
499         }
500         for (cur_media = a_media_list ; 
501              cur_media ;
502              cur_media = g_list_next (cur_media)) {
503                 str = (gchar*)cr_string_peek_raw_str
504                         ((CRString*)cur_media->data) ;
505                 if (str) {
506                         if (g_list_previous (cur_media)) {
507                                 g_string_append_printf (gstr, ", %s", 
508                                                         str) ;
509                         } else {
510                                 g_string_append_printf (gstr, "%s",
511                                                         str) ;
512                         }
513                 }
514         }
515         str = (gchar*)cr_string_peek_raw_str (a_uri) ;
516         if (str) {
517                 g_print ("@import url(\"%s\") ", str) ;
518                 if (gstr) {
519                         g_print ("%s;\n\n", gstr->str) ;
520                 }
521                 str = NULL ;
522         }
523         str = cr_parsing_location_to_string (a_location, 0) ;
524         if (str) {
525                 g_print ("/*****************************************************\n") ;
526                 g_print (" *Parsing location inforamtion for the @import rule\n") ;
527                 g_print (" ******************************************************/\n\n") ;
528                 g_print ("  /*@import*/\n") ;
529                 g_print ("  /*%s*/\n\n", str) ;
530                 g_free (str) ;
531                 str = NULL ;
532         }
533
534         str = (gchar*)cr_string_peek_raw_str (a_uri) ;
535         if (str) {
536                 g_print ("  /*%s*/\n", str) ;
537                 str = cr_parsing_location_to_string 
538                         (&a_uri->location, 0) ;
539                 if (str) {
540                         g_print ("  /*%s*/\n\n", str) ;
541                         g_free (str) ;
542                         str = NULL ;
543                 }
544         }
545
546         for (cur_media = a_media_list ; 
547              cur_media ;
548              cur_media = g_list_next (cur_media)) {
549                 str = (gchar*)cr_string_peek_raw_str
550                         ((CRString*)cur_media->data) ;
551                 if (str) {
552                         g_print ("  /*%s*/\n", str) ;
553                 }
554                 str = cr_parsing_location_to_string 
555                         (&((CRString*)cur_media->data)->location, 0) ;
556                 if (str) {
557                         g_print ("  /*%s*/\n\n", str) ;
558                         g_free (str) ;
559                         str = NULL ;
560                 }
561         }
562
563         if (gstr) {
564                 g_string_free (gstr, TRUE) ;
565                 gstr = NULL ;
566         }
567 }
568
569 static void
570 start_font_face (CRDocHandler *a_this,
571                  CRParsingLocation *a_location)
572 {
573         gchar *str = NULL ;
574
575         g_print ("@font-face {\n") ;
576         g_print ("/******************************************************\n") ;
577         g_print (" Parsing location information for the @font-face rule\n") ;
578         g_print (" ******************************************************/\n\n") ;
579
580         g_print ("  /*@font-face*/\n") ;
581         if (a_location) {
582                 str = cr_parsing_location_to_string (a_location, 0) ;
583         }
584         if (str) {
585                 g_print ("  /*%s*/\n", str) ;
586                 g_free (str) ;
587                 str = NULL ;
588         }
589 }
590
591 static void
592 end_font_face (CRDocHandler *a_this)
593 {
594         g_print ("}\n") ;
595 }
596
597 static void
598 start_media (CRDocHandler *a_this,
599              GList *a_media_list,
600              CRParsingLocation *a_location)
601 {
602         GList *cur_media = NULL ;
603         gchar *str = NULL ;
604
605         g_print ("@media ") ;
606         for (cur_media = a_media_list ;
607              cur_media ;
608              cur_media = g_list_next (cur_media)) {
609                 CRString *crstr = cur_media->data ;
610                 if (crstr) {
611                         str = (gchar*)cr_string_peek_raw_str (crstr) ;
612                         if (str) {
613                                 if (cur_media->prev) {
614                                         g_print (", %s", str) ;
615                                 } else {
616                                         g_print ("%s", str) ;
617                                 }
618                         }
619                 }
620         }
621         /*****************************
622          *new print parsing locations
623          *****************************/
624         g_print ("\n  /*@media*/\n") ;
625         if (a_location)
626                 str = cr_parsing_location_to_string (a_location,
627                                                      0) ;
628         if (str) {
629                 g_print ("  /*%s*/\n", str) ;
630                 g_free (str) ;
631                 str = NULL ;
632         }
633         for (cur_media = a_media_list ;
634              cur_media ;
635              cur_media = g_list_next (cur_media)) {
636                 CRString *crstr = cur_media->data ;
637                 if (crstr) {
638                         str = (gchar*)cr_string_peek_raw_str (crstr) ;
639                         if (str) {
640                                 g_print ("  /*%s*/\n", str) ;
641                                 str = cr_parsing_location_to_string 
642                                         (&crstr->location, 0) ;
643                                 if (str) {
644                                         g_print ("  /*%s*/\n", str) ;
645                                         g_free (str) ;
646                                         str = NULL ;
647                                 }
648                         }
649                 }
650         }
651         g_print ("\n{\n") ;
652 }
653
654 static void
655 end_media (CRDocHandler *a_this,
656            GList *a_media_list)
657 {        
658         g_print ("\n}\n") ;
659 }
660
661 static void
662 start_page (CRDocHandler *a_this,
663             CRString *a_name,
664             CRString *a_pseudo_page,
665             CRParsingLocation *a_location)
666 {
667         gchar *str = NULL ;
668         
669         g_print ("@page ") ;
670         if (a_name)
671                 str = (gchar*)cr_string_peek_raw_str (a_name) ;
672         if (str) {
673                 g_print ("%s ", str) ;
674         }
675         if (a_pseudo_page)
676                 str = (gchar*) cr_string_peek_raw_str (a_pseudo_page) ;
677         if (str) {
678                 g_print (":%s", str) ;
679                 str = NULL ;
680         }
681         /*************************************
682          *print parsing location informations
683          ************************************/
684         g_print ("\n\n  /*@page*/\n") ;
685         if (a_location)
686                 str = cr_parsing_location_to_string 
687                         (a_location, 0) ;
688         if (str) {
689                 g_print ("  /*%s*/\n", str) ;
690                 g_free (str) ;
691                 str = NULL ;
692         }
693         if (a_name)
694                 str = (gchar*)cr_string_peek_raw_str (a_name) ;
695         if (str) {
696                 g_print ("  /*%s*/\n", str) ;
697                 str = cr_parsing_location_to_string 
698                         (&a_name->location, 0) ;
699                 if (str) {
700                         g_print ("  /*%s*/\n", str) ;
701                         g_free (str) ;
702                         str = NULL ;
703                 }
704         }
705         if (a_pseudo_page)
706                 str = (gchar*) cr_string_peek_raw_str 
707                         (a_pseudo_page) ;
708         if (str) {
709                 g_print ("  /*%s*/\n", str) ;
710                 str = cr_parsing_location_to_string 
711                         (&a_pseudo_page->location, 0) ;
712                 if (str) {
713                         g_print ("  /*%s*/\n", str) ;
714                         g_free (str) ;
715                         str = NULL ;
716                 }
717         }
718         g_print ("\n{\n") ;        
719 }
720
721 static void
722 end_page (CRDocHandler *a_this,
723           CRString *a_name,
724           CRString *pseudo_page)
725 {
726         g_print ("}\n") ;
727 }
728
729 static void
730 dump_location_annotated_simple_sel (CRSimpleSel *a_this)
731 {
732         CRSimpleSel *cur_simple_sel = a_this ;
733         CRAdditionalSel *cur_add_sel = NULL ;
734         gchar *str0 = NULL ;
735
736         g_return_if_fail (a_this) ;
737
738         /*first, display the entire simple sel*/
739         str0 = cr_simple_sel_one_to_string
740                 (cur_simple_sel) ;
741         if (str0) {
742                 g_print ("/*%s*/\n", str0) ;
743                 g_free (str0) ;
744                 str0 = NULL ;
745         }
746         g_print ("/*") ;
747         cr_parsing_location_dump
748                 (&cur_simple_sel->location, 0,
749                  stdout);
750         g_print ("*/\n") ;
751
752         /*now display the details of the simple sel*/
753         if (cur_simple_sel->name) {
754                 str0 = (gchar*) cr_string_peek_raw_str
755                         (cur_simple_sel->name) ;
756                 if (str0) {
757                         g_print ("  /*%s*/\n", str0) ;
758                         str0 = NULL ;
759                 }
760                 str0 = cr_parsing_location_to_string
761                         (&cur_simple_sel->name->location,
762                          0) ;
763                 if (str0) {
764                         g_print ("  /*%s*/\n", str0) ;
765                         g_free (str0) ;
766                         str0 = NULL ;
767                 }
768         }
769         for (cur_add_sel = cur_simple_sel->add_sel; 
770              cur_add_sel;
771              cur_add_sel = cur_add_sel->next) {
772                 str0 = cr_additional_sel_one_to_string 
773                         (cur_add_sel) ;
774                 if (str0) {
775                         g_print ("\n  /*%s*/\n", str0) ;
776                         g_free (str0) ;
777                         str0 = NULL ;
778                 }
779                 str0 = cr_parsing_location_to_string 
780                         (&cur_add_sel->location, 0) ;
781                 if (str0) {
782                         g_print ("  /*%s*/\n", str0) ;
783                         g_free (str0) ;
784                         str0 = NULL ;
785                 }
786         }
787 }
788
789 static void
790 start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
791 {
792         struct SacContext *context = NULL;
793         CRSelector *cur_sel = NULL ;
794         CRSimpleSel *cur_simple_sel = NULL ;
795
796         g_return_if_fail (a_this);
797
798         cr_doc_handler_get_ctxt (a_this, (gpointer *) (gpointer) & context);
799         if (context) {
800                 context->level++;
801         }
802         cr_selector_dump (a_selector_list, stdout);
803         g_print (" {\n") ;
804         g_print ("/************************************************\n") ;
805         g_print (" *Parsing location information of the selector\n") ;
806         g_print (" ************************************************/\n") ;
807         
808         for (cur_sel = a_selector_list; 
809              cur_sel ;
810              cur_sel = cur_sel->next) {
811                 for (cur_simple_sel = cur_sel->simple_sel ;
812                      cur_simple_sel ;
813                      cur_simple_sel = cur_simple_sel->next) {
814
815                         dump_location_annotated_simple_sel 
816                                 (cur_simple_sel) ;
817                 }
818         }        
819 }
820
821 static void
822 end_selector (CRDocHandler * a_this,
823               CRSelector *a_selector_list)
824 {
825         struct SacContext *context = NULL;
826
827         g_return_if_fail (a_this);
828
829         cr_doc_handler_get_ctxt (a_this, (gpointer *) (gpointer) & context);
830         if (context) {
831                 context->level--;
832         }
833         g_print (" }\n") ;
834 }
835
836 static void
837 property (CRDocHandler *a_this,
838           CRString *a_name,
839           CRTerm *a_expr,
840           gboolean a_is_important)
841 {
842         gchar *str = NULL ;
843         CRTerm *cur_term = NULL ;
844         
845         str = (gchar*) cr_string_peek_raw_str (a_name) ;
846         if (str) {
847                 g_print ("\n\n") ;
848                 g_print ("%s", str) ;
849                 str = NULL ;
850                 if (a_expr) {
851                         str = cr_term_to_string (a_expr) ;
852                         if (str) {
853                                 g_print (" : %s;\n\n", str) ;
854                                 g_free (str) ;
855                                 str = NULL ;
856                         }
857                 } else {
858                         g_print (";\n\n") ;
859                 }
860         }
861
862         /*Now dump each part of the property declaration*/
863
864         g_print ("\n") ;
865         g_print ("/************************************************\n") ;
866         g_print (" *Parsing location information of the property\n") ;
867         g_print (" ************************************************/\n") ;
868
869         str = (gchar*) cr_string_peek_raw_str (a_name) ;
870         if (str) {
871                 g_print ("  /*%s*/\n", str) ;
872                 str = NULL ;
873         }
874         str = cr_parsing_location_to_string (&a_name->location, 0) ;
875         if (str) {
876                 g_print ("  /*%s*/\n", str) ;
877                 g_free (str) ;
878                 str = NULL ;
879         }
880
881         for (cur_term = a_expr ;
882              cur_term;
883              cur_term = cur_term->next) {
884                 str = cr_term_one_to_string (cur_term) ;
885                 if (str) {
886                         g_print ("  /*%s*/\n", str) ;
887                         g_free (str) ;
888                         str = NULL ;
889                 }
890                 str = cr_parsing_location_to_string
891                         (&cur_term->location, 0) ;
892                 if (str) {
893                         g_print ("  /*%s*/\n", str) ;
894                         g_free (str) ;
895                         str = NULL ;
896                 }
897         }
898 }
899
900
901 static enum CRStatus
902 sac_parse_and_display_locations (guchar * a_file_uri)
903 {
904         enum CRStatus status = CR_OK;
905         CRDocHandler *sac_handler = NULL;
906         CRParser *parser = NULL;
907
908         g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR);
909
910         parser = cr_parser_new_from_file (a_file_uri, CR_UTF_8);
911         if (!parser) {
912                 cr_utils_trace_info ("parser instanciation failed");
913                 return CR_ERROR;
914         }
915         sac_handler = cr_doc_handler_new ();
916         if (!sac_handler) {
917                 cr_utils_trace_info ("sac handler instanciation failed");
918                 status = CR_OUT_OF_MEMORY_ERROR;
919                 goto cleanup;
920         }
921         sac_handler->start_document = start_document ;
922         sac_handler->end_document = end_document ;
923         sac_handler->charset = charset ;
924         sac_handler->import_style = import_style ;
925         sac_handler->start_font_face = start_font_face ;
926         sac_handler->end_font_face = end_font_face ;
927         sac_handler->start_media = start_media ;
928         sac_handler->end_media = end_media ;
929         sac_handler->start_page = start_page ;
930         sac_handler->end_page = end_page ;
931         sac_handler->start_selector = start_selector;
932         sac_handler->end_selector = end_selector;
933         sac_handler->property = property ;
934
935         cr_parser_set_sac_handler (parser, sac_handler) ;
936         status = cr_parser_parse (parser) ;
937         
938  cleanup:
939         if (parser) {
940                 cr_parser_destroy (parser);
941                 parser = NULL;
942         }
943         return status;
944 }
945
946 int
947 main (int argc, char **argv)
948 {
949         struct Options options;
950         enum CRStatus status = CR_OK;
951
952         memset (&options, 0, sizeof (struct Options));
953         options.use_cssom = TRUE;
954         parse_cmd_line (argc, argv, &options);
955
956         if (options.show_version == TRUE) {
957                 display_version ();
958                 return 0;
959         }
960
961         if (options.display_help == TRUE) {
962                 display_usage ();
963                 return 0;
964         }
965         if (options.use_cssom == TRUE) {
966                 if (options.evaluate == TRUE) {
967                         status = evaluate_selectors
968                                 (options.xml_path,
969                                  options.author_sheet_path,
970                                  options.user_sheet_path,
971                                  options.ua_sheet_path, options.xpath);
972                 } else if (options.css_files_list != NULL) {
973                         status = cssom_parse (options.css_files_list[0]);
974                 }
975         } else if (options.dump_location == TRUE) {
976                 if (options.css_files_list) {
977                         status = sac_parse_and_display_locations 
978                                 (options.css_files_list[0]) ;
979                 } else {
980                         display_usage () ;
981                         return -1 ;
982                 }
983         }
984
985         return 0;
986 }