PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/cssed-0.4.0/libcroco/parser/cr-parser.c

#
C | 4469 lines | 3249 code | 592 blank | 628 comment | 788 complexity | f6f52a8ea2487ef05af5aa9724643aaa MD5 | raw file
Possible License(s): GPL-2.0
  1. /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
  2. /*
  3. * This file is part of The Croco Library
  4. *
  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
  8. * GNU Lesser General Public
  9. * License as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  19. * USA
  20. *
  21. * Author: Dodji Seketeli
  22. * See COPYRIGHTS file for copyrights information.
  23. */
  24. /**
  25. *@file
  26. *The definition of the #CRParser class.
  27. */
  28. #include "string.h"
  29. #include "cr-parser.h"
  30. #include "cr-num.h"
  31. #include "cr-term.h"
  32. #include "cr-simple-sel.h"
  33. #include "cr-attr-sel.h"
  34. /*
  35. *Random notes:
  36. *CSS core syntax vs CSS level 2 syntax
  37. *=====================================
  38. *
  39. *One must keep in mind
  40. *that css UA must comply with two syntax.
  41. *
  42. *1/the specific syntax that defines the css language
  43. *for a given level of specificatin (e.g css2 syntax
  44. *defined in appendix D.1 of the css2 spec)
  45. *
  46. *2/the core (general) syntax that is there to allow
  47. *UAs to parse style sheets written in levels of CSS that
  48. *didn't exist at the time the UAs were created.
  49. *
  50. *the name of parsing functions (or methods) contained in this file
  51. *follows the following scheme: cr_parser_parse_<production_name> (...) ;
  52. *where <production_name> is the name
  53. *of a production of the css2 language.
  54. *When a given production is
  55. *defined by the css2 level grammar *and* by the
  56. *css core syntax, there will be two functions to parse that production:
  57. *one will parse the production defined by the css2 level grammar and the
  58. *other will parse the production defined by the css core grammar.
  59. *The css2 level grammar related parsing function will be called:
  60. *cr_parser_parse_<production_name> (...) ;
  61. *Then css core grammar related parsing function will be called:
  62. *cr_parser_parse_<production_name>_core (...) ;
  63. *
  64. *If a production is defined only by the css core grammar, then
  65. *it will be named:
  66. *cr_parser_parse_<production_name>_core (...) ;
  67. */
  68. /* moved _CRParserError struct to make it public and not opaque
  69. modified by Iago Rubio to cssed */
  70. /**
  71. *An abstraction of an error reported by by the
  72. *parsing routines.
  73. */
  74. enum CRParserState {
  75. READY_STATE = 0,
  76. TRY_PARSE_CHARSET_STATE,
  77. CHARSET_PARSED_STATE,
  78. TRY_PARSE_IMPORT_STATE,
  79. IMPORT_PARSED_STATE,
  80. TRY_PARSE_RULESET_STATE,
  81. RULESET_PARSED_STATE,
  82. TRY_PARSE_MEDIA_STATE,
  83. MEDIA_PARSED_STATE,
  84. TRY_PARSE_PAGE_STATE,
  85. PAGE_PARSED_STATE,
  86. TRY_PARSE_FONT_FACE_STATE,
  87. FONT_FACE_PARSED_STATE
  88. } ;
  89. /**
  90. *The private attributes of
  91. *#CRParser.
  92. */
  93. struct _CRParserPriv {
  94. /**
  95. *The tokenizer
  96. */
  97. CRTknzr *tknzr;
  98. /**
  99. *The sac handlers to call
  100. *to notify the parsing of
  101. *the css2 constructions.
  102. */
  103. CRDocHandler *sac_handler;
  104. /**
  105. *A stack of errors reported
  106. *by the parsing routines.
  107. *Contains instance of #CRParserError.
  108. *This pointer is the top of the stack.
  109. */
  110. GList *err_stack;
  111. enum CRParserState state;
  112. gboolean resolve_import;
  113. gboolean is_case_sensitive;
  114. gboolean use_core_grammar;
  115. };
  116. #define PRIVATE(obj) ((obj)->priv)
  117. #define CHARS_TAB_SIZE 12
  118. /**
  119. *return TRUE if the character is a number ([0-9]), FALSE otherwise
  120. *@param a_char the char to test.
  121. */
  122. #define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
  123. /**
  124. *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
  125. *
  126. *@param status the status (of type enum CRStatus) to test.
  127. *@param is_exception if set to FALSE, the final status returned
  128. *by the current function will be CR_PARSING_ERROR. If set to TRUE, the
  129. *current status will be the current value of the 'status' variable.
  130. *
  131. */
  132. #define CHECK_PARSING_STATUS(status, is_exception) \
  133. if ((status) != CR_OK) \
  134. { \
  135. if (is_exception == FALSE) \
  136. { \
  137. status = CR_PARSING_ERROR ; \
  138. } \
  139. goto error ; \
  140. }
  141. /**
  142. *same as CHECK_PARSING_STATUS() but this one pushes an error
  143. *on the parser error stack when an error arises.
  144. *@param a_this the current instance of #CRParser .
  145. *@param a_status the status to check. Is of type enum #CRStatus.
  146. *@param a_is_exception in case of error, if is TRUE, the status
  147. *is set to CR_PARSING_ERROR before goto error. If is false, the
  148. *real low level status is kept and will be returned by the
  149. *upper level function that called this macro. Usally,this must
  150. *be set to FALSE.
  151. *
  152. */
  153. #define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\
  154. a_err_msg, a_err_status) \
  155. if ((a_status) != CR_OK) \
  156. { \
  157. if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \
  158. cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
  159. goto error ; \
  160. }
  161. /**
  162. *Peeks the next char from the input stream of the current parser
  163. *by invoking cr_tknzr_input_peek_char().
  164. *invokes CHECK_PARSING_STATUS on the status returned by
  165. *cr_tknzr_peek_char().
  166. *
  167. *@param a_this the current instance of #CRParser.
  168. *@param a_to_char a pointer to the char where to store the
  169. *char peeked.
  170. */
  171. #define PEEK_NEXT_CHAR(a_this, a_to_char) \
  172. {\
  173. enum CRStatus status ; \
  174. status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
  175. CHECK_PARSING_STATUS (status, TRUE) \
  176. }
  177. /**
  178. *Reads the next char from the input stream of the current parser.
  179. *In case of error, jumps to the "error:" label located in the
  180. *function where this macro is called.
  181. *@param a_this the curent instance of #CRParser
  182. *@param to_char a pointer to the guint32 char where to store
  183. *the character read.
  184. */
  185. #define READ_NEXT_CHAR(a_this, a_to_char) \
  186. status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
  187. CHECK_PARSING_STATUS (status, TRUE)
  188. /**
  189. *Gets information about the current position in
  190. *the input of the parser.
  191. *In case of failure, this macro returns from the
  192. *calling function and
  193. *returns a status code of type enum #CRStatus.
  194. *@param a_this the current instance of #CRParser.
  195. *@param a_pos out parameter. A pointer to the position
  196. *inside the current parser input. Must
  197. */
  198. #define RECORD_INITIAL_POS(a_this, a_pos) \
  199. status = cr_tknzr_get_cur_pos (PRIVATE \
  200. (a_this)->tknzr, a_pos) ; \
  201. g_return_val_if_fail (status == CR_OK, status)
  202. /**
  203. *Gets the address of the current byte inside the
  204. *parser input.
  205. *@param parser the current instance of #CRParser.
  206. *@param addr out parameter a pointer (guchar*)
  207. *to where the address must be put.
  208. */
  209. #define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \
  210. status = cr_tknzr_get_cur_byte_addr \
  211. (PRIVATE (a_this)->tknzr, a_addr) ; \
  212. CHECK_PARSING_STATUS (status, TRUE)
  213. /**
  214. *Peeks a byte from the topmost parser input at
  215. *a given offset from the current position.
  216. *If it fails, goto the "error:" label.
  217. *
  218. *@param a_parser the current instance of #CRParser.
  219. *@param a_offset the offset of the byte to peek, the
  220. *current byte having the offset '0'.
  221. *@param a_byte_ptr out parameter a pointer (guchar*) to
  222. *where the peeked char is to be stored.
  223. */
  224. #define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \
  225. status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \
  226. a_offset, \
  227. a_byte_ptr) ; \
  228. CHECK_PARSING_STATUS (status, TRUE) ;
  229. #define BYTE(a_parser, a_offset, a_eof) \
  230. cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof)
  231. /**
  232. *Reads a byte from the topmost parser input
  233. *steam.
  234. *If it fails, goto the "error" label.
  235. *@param a_this the current instance of #CRParser.
  236. *@param a_byte_ptr the guchar * where to put the read char.
  237. */
  238. #define READ_NEXT_BYTE(a_this, a_byte_ptr) \
  239. status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \
  240. CHECK_PARSING_STATUS (status, TRUE) ;
  241. /**
  242. *Skips a given number of byte in the topmost
  243. *parser input. Don't update line and column number.
  244. *In case of error, jumps to the "error:" label
  245. *of the surrounding function.
  246. *@param a_parser the current instance of #CRParser.
  247. *@param a_nb_bytes the number of bytes to skip.
  248. */
  249. #define SKIP_BYTES(a_this, a_nb_bytes) \
  250. status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \
  251. CR_SEEK_CUR, a_nb_bytes) ; \
  252. CHECK_PARSING_STATUS (status, TRUE) ;
  253. /**
  254. *Skip utf8 encoded characters.
  255. *Updates line and column numbers.
  256. *@param a_parser the current instance of #CRParser.
  257. *@param a_nb_chars the number of chars to skip. Must be of
  258. *type glong.
  259. */
  260. #define SKIP_CHARS(a_parser, a_nb_chars) \
  261. { \
  262. glong nb_chars = a_nb_chars ; \
  263. status = cr_tknzr_consume_chars \
  264. (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \
  265. CHECK_PARSING_STATUS (status, TRUE) ; \
  266. }
  267. /**
  268. *Tests the condition and if it is false, sets
  269. *status to "CR_PARSING_ERROR" and goto the 'error'
  270. *label.
  271. *@param condition the condition to test.
  272. */
  273. #define ENSURE_PARSING_COND(condition) \
  274. if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
  275. #define ENSURE_PARSING_COND_ERR(a_this, a_condition, \
  276. a_err_msg, a_err_status) \
  277. if (! (a_condition)) \
  278. { \
  279. status = CR_PARSING_ERROR; \
  280. cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
  281. goto error ; \
  282. }
  283. #define GET_NEXT_TOKEN(a_this, a_token_ptr) \
  284. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \
  285. a_token_ptr) ; \
  286. ENSURE_PARSING_COND (status == CR_OK) ;
  287. #ifdef WITH_UNICODE_ESCAPE_AND_RANGE
  288. static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this,
  289. guint32 * a_unicode);
  290. static enum CRStatus cr_parser_parse_escape (CRParser * a_this,
  291. guint32 * a_esc_code);
  292. static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this,
  293. CRString ** a_inf,
  294. CRString ** a_sup);
  295. #endif
  296. static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this);
  297. static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this);
  298. static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this);
  299. static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this);
  300. static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this);
  301. static enum CRStatus cr_parser_parse_any_core (CRParser * a_this);
  302. static enum CRStatus cr_parser_parse_block_core (CRParser * a_this);
  303. static enum CRStatus cr_parser_parse_value_core (CRParser * a_this);
  304. static enum CRStatus cr_parser_parse_string (CRParser * a_this,
  305. CRString ** a_str);
  306. static enum CRStatus cr_parser_parse_ident (CRParser * a_this,
  307. CRString ** a_str);
  308. static enum CRStatus cr_parser_parse_uri (CRParser * a_this,
  309. CRString ** a_str);
  310. static enum CRStatus cr_parser_parse_function (CRParser * a_this,
  311. CRString ** a_func_name,
  312. CRTerm ** a_expr);
  313. static enum CRStatus cr_parser_parse_property (CRParser * a_this,
  314. CRString ** a_property);
  315. static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this,
  316. CRAttrSel ** a_sel);
  317. static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this,
  318. CRSimpleSel ** a_sel);
  319. static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this,
  320. CRSimpleSel ** a_sel);
  321. static CRParserError *cr_parser_error_new (const guchar * a_msg,
  322. enum CRStatus);
  323. static void cr_parser_error_set_msg (CRParserError * a_this,
  324. const guchar * a_msg);
  325. static void cr_parser_error_dump (CRParserError * a_this);
  326. static void cr_parser_error_set_status (CRParserError * a_this,
  327. enum CRStatus a_status);
  328. static void cr_parser_error_set_pos (CRParserError * a_this,
  329. glong a_line,
  330. glong a_column, glong a_byte_num);
  331. static void
  332. cr_parser_error_destroy (CRParserError * a_this);
  333. static enum CRStatus cr_parser_push_error (CRParser * a_this,
  334. const guchar * a_msg,
  335. enum CRStatus a_status);
  336. static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this,
  337. gboolean a_clear_errs);
  338. static enum CRStatus
  339. cr_parser_clear_errors (CRParser * a_this);
  340. /* **********************************************************
  341. Added by Iago Rubio to use it in cssed as syntax validator
  342. ********************************************************** */
  343. GList*
  344. cr_parser_get_error_stack(CRParser *a_this)
  345. {
  346. GList *stack ;
  347. stack = g_list_copy(PRIVATE(a_this)->err_stack);
  348. return stack;
  349. }
  350. gulong
  351. cr_parser_get_pos(CRParser *a_this)
  352. {
  353. return cr_tknzr_get_cur_line(PRIVATE(a_this)->tknzr);
  354. }
  355. /*****************************
  356. * end iago's changes
  357. *****************************/
  358. /*****************************
  359. *error managemet methods
  360. *****************************/
  361. /**
  362. *Constructor of #CRParserError class.
  363. *@param a_msg the brute error message.
  364. *@param a_status the error status.
  365. *@return the newly built instance of #CRParserError.
  366. */
  367. static CRParserError *
  368. cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status)
  369. {
  370. CRParserError *result = NULL;
  371. result = g_try_malloc (sizeof (CRParserError));
  372. if (result == NULL) {
  373. cr_utils_trace_info ("Out of memory");
  374. return NULL;
  375. }
  376. memset (result, 0, sizeof (CRParserError));
  377. cr_parser_error_set_msg (result, a_msg);
  378. cr_parser_error_set_status (result, a_status);
  379. return result;
  380. }
  381. /**
  382. *Sets the message associated to this instance of #CRError.
  383. *@param a_this the current instance of #CRParserError.
  384. *@param a_msg the new message.
  385. */
  386. static void
  387. cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg)
  388. {
  389. g_return_if_fail (a_this);
  390. if (a_this->msg) {
  391. g_free (a_this->msg);
  392. }
  393. a_this->msg = g_strdup (a_msg);
  394. }
  395. /**
  396. *Sets the error status.
  397. *@param a_this the current instance of #CRParserError.
  398. *@param a_status the new error status.
  399. *
  400. */
  401. static void
  402. cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status)
  403. {
  404. g_return_if_fail (a_this);
  405. a_this->status = a_status;
  406. }
  407. /**
  408. *Sets the position of the parser error.
  409. *@param a_this the current instance of #CRParserError.
  410. *@param a_line the line number.
  411. *@param a_column the column number.
  412. *@param a_byte_num the byte number.
  413. */
  414. static void
  415. cr_parser_error_set_pos (CRParserError * a_this,
  416. glong a_line, glong a_column, glong a_byte_num)
  417. {
  418. g_return_if_fail (a_this);
  419. a_this->line = a_line;
  420. a_this->column = a_column;
  421. a_this->byte_num = a_byte_num;
  422. }
  423. static void
  424. cr_parser_error_dump (CRParserError * a_this)
  425. {
  426. g_return_if_fail (a_this);
  427. g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column);
  428. g_printerr ("%s\n", a_this->msg);
  429. }
  430. /**
  431. *The destructor of #CRParserError.
  432. *@param a_this the current instance of #CRParserError.
  433. */
  434. static void
  435. cr_parser_error_destroy (CRParserError * a_this)
  436. {
  437. g_return_if_fail (a_this);
  438. if (a_this->msg) {
  439. g_free (a_this->msg);
  440. a_this->msg = NULL;
  441. }
  442. g_free (a_this);
  443. }
  444. /**
  445. *Pushes an error on the parser error stack.
  446. *@param a_this the current instance of #CRParser.
  447. *@param a_msg the error message.
  448. *@param a_status the error status.
  449. *@return CR_OK upon successfull completion, an error code otherwise.
  450. */
  451. static enum CRStatus
  452. cr_parser_push_error (CRParser * a_this,
  453. const guchar * a_msg, enum CRStatus a_status)
  454. {
  455. enum CRStatus status = CR_OK;
  456. CRParserError *error = NULL;
  457. CRInputPos pos;
  458. g_return_val_if_fail (a_this && PRIVATE (a_this)
  459. && a_msg, CR_BAD_PARAM_ERROR);
  460. error = cr_parser_error_new (a_msg, a_status);
  461. g_return_val_if_fail (error, CR_ERROR);
  462. RECORD_INITIAL_POS (a_this, &pos);
  463. cr_parser_error_set_pos
  464. (error, pos.line, pos.col, pos.next_byte_index - 1);
  465. PRIVATE (a_this)->err_stack =
  466. g_list_prepend (PRIVATE (a_this)->err_stack, error);
  467. if (PRIVATE (a_this)->err_stack == NULL)
  468. goto error;
  469. return CR_OK;
  470. error:
  471. if (error) {
  472. cr_parser_error_destroy (error);
  473. error = NULL;
  474. }
  475. return status;
  476. }
  477. /**
  478. *Dumps the error stack on stdout.
  479. *@param a_this the current instance of #CRParser.
  480. *@param a_clear_errs whether to clear the error stack
  481. *after the dump or not.
  482. *@return CR_OK upon successfull completion, an error code
  483. *otherwise.
  484. */
  485. static enum CRStatus
  486. cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs)
  487. {
  488. GList *cur = NULL;
  489. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  490. if (PRIVATE (a_this)->err_stack == NULL)
  491. return CR_OK;
  492. for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
  493. cr_parser_error_dump ((CRParserError *) cur->data);
  494. }
  495. if (a_clear_errs == TRUE) {
  496. cr_parser_clear_errors (a_this);
  497. }
  498. return CR_OK;
  499. }
  500. /**
  501. *Clears all the errors contained in the parser error stack.
  502. *Frees all the errors, and the stack that contains'em.
  503. *@param a_this the current instance of #CRParser.
  504. */
  505. static enum CRStatus
  506. cr_parser_clear_errors (CRParser * a_this)
  507. {
  508. GList *cur = NULL;
  509. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  510. for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
  511. if (cur->data) {
  512. cr_parser_error_destroy ((CRParserError *)
  513. cur->data);
  514. }
  515. }
  516. if (PRIVATE (a_this)->err_stack) {
  517. g_list_free (PRIVATE (a_this)->err_stack);
  518. PRIVATE (a_this)->err_stack = NULL;
  519. }
  520. return CR_OK;
  521. }
  522. /**
  523. *Same as cr_parser_try_to_skip_spaces() but this one skips
  524. *spaces and comments.
  525. *
  526. *@param a_this the current instance of #CRParser.
  527. *@return CR_OK upon successfull completion, an error code otherwise.
  528. */
  529. enum CRStatus
  530. cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this)
  531. {
  532. enum CRStatus status = CR_ERROR;
  533. CRToken *token = NULL;
  534. g_return_val_if_fail (a_this && PRIVATE (a_this)
  535. && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
  536. do {
  537. if (token) {
  538. cr_token_destroy (token);
  539. token = NULL;
  540. }
  541. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  542. &token);
  543. if (status != CR_OK)
  544. goto error;
  545. }
  546. while ((token != NULL)
  547. && (token->type == COMMENT_TK || token->type == S_TK));
  548. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  549. return status;
  550. error:
  551. if (token) {
  552. cr_token_destroy (token);
  553. token = NULL;
  554. }
  555. return status;
  556. }
  557. /***************************************
  558. *End of Parser input handling routines
  559. ***************************************/
  560. /*************************************
  561. *Non trivial terminal productions
  562. *parsing routines
  563. *************************************/
  564. /**
  565. *Parses a css stylesheet following the core css grammar.
  566. *This is mainly done for test purposes.
  567. *During the parsing, no callback is called. This is just
  568. *to validate that the stylesheet is well formed according to the
  569. *css core syntax.
  570. *stylesheet : [ CDO | CDC | S | statement ]*;
  571. *@param a_this the current instance of #CRParser.
  572. *@return CR_OK upon successfull completion, an error code otherwise.
  573. */
  574. static enum CRStatus
  575. cr_parser_parse_stylesheet_core (CRParser * a_this)
  576. {
  577. CRToken *token = NULL;
  578. CRInputPos init_pos;
  579. enum CRStatus status = CR_ERROR;
  580. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  581. RECORD_INITIAL_POS (a_this, &init_pos);
  582. continue_parsing:
  583. if (token) {
  584. cr_token_destroy (token);
  585. token = NULL;
  586. }
  587. cr_parser_try_to_skip_spaces_and_comments (a_this);
  588. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  589. if (status == CR_END_OF_INPUT_ERROR) {
  590. status = CR_OK;
  591. goto done;
  592. } else if (status != CR_OK) {
  593. goto error;
  594. }
  595. switch (token->type) {
  596. case CDO_TK:
  597. case CDC_TK:
  598. goto continue_parsing;
  599. break;
  600. default:
  601. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  602. token);
  603. CHECK_PARSING_STATUS (status, TRUE);
  604. token = NULL;
  605. status = cr_parser_parse_statement_core (a_this);
  606. cr_parser_clear_errors (a_this);
  607. if (status == CR_OK) {
  608. goto continue_parsing;
  609. } else if (status == CR_END_OF_INPUT_ERROR) {
  610. goto done;
  611. } else {
  612. goto error;
  613. }
  614. }
  615. done:
  616. if (token) {
  617. cr_token_destroy (token);
  618. token = NULL;
  619. }
  620. cr_parser_clear_errors (a_this);
  621. return CR_OK;
  622. error:
  623. cr_parser_push_error
  624. (a_this, "could not recognize next production", CR_ERROR);
  625. //cr_parser_dump_err_stack (a_this, TRUE);
  626. if (token) {
  627. cr_token_destroy (token);
  628. token = NULL;
  629. }
  630. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  631. return status;
  632. }
  633. /**
  634. *Parses an at-rule as defined by the css core grammar
  635. *in chapter 4.1 in the css2 spec.
  636. *at-rule : ATKEYWORD S* any* [ block | ';' S* ];
  637. *@param a_this the current instance of #CRParser.
  638. *@return CR_OK upon successfull completion, an error code
  639. *otherwise.
  640. */
  641. static enum CRStatus
  642. cr_parser_parse_atrule_core (CRParser * a_this)
  643. {
  644. CRToken *token = NULL;
  645. CRInputPos init_pos;
  646. enum CRStatus status = CR_ERROR;
  647. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  648. RECORD_INITIAL_POS (a_this, &init_pos);
  649. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  650. &token);
  651. ENSURE_PARSING_COND (status == CR_OK
  652. && token
  653. &&
  654. (token->type == ATKEYWORD_TK
  655. || token->type == IMPORT_SYM_TK
  656. || token->type == PAGE_SYM_TK
  657. || token->type == MEDIA_SYM_TK
  658. || token->type == FONT_FACE_SYM_TK
  659. || token->type == CHARSET_SYM_TK));
  660. cr_token_destroy (token);
  661. token = NULL;
  662. cr_parser_try_to_skip_spaces_and_comments (a_this);
  663. do {
  664. status = cr_parser_parse_any_core (a_this);
  665. } while (status == CR_OK);
  666. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  667. &token);
  668. ENSURE_PARSING_COND (status == CR_OK && token);
  669. if (token->type == CBO_TK) {
  670. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  671. token);
  672. token = NULL;
  673. status = cr_parser_parse_block_core (a_this);
  674. CHECK_PARSING_STATUS (status,
  675. FALSE);
  676. goto done;
  677. } else if (token->type == SEMICOLON_TK) {
  678. goto done;
  679. } else {
  680. status = CR_PARSING_ERROR ;
  681. goto error;
  682. }
  683. done:
  684. if (token) {
  685. cr_token_destroy (token);
  686. token = NULL;
  687. }
  688. return CR_OK;
  689. error:
  690. if (token) {
  691. cr_token_destroy (token);
  692. token = NULL;
  693. }
  694. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
  695. &init_pos);
  696. return status;
  697. }
  698. /**
  699. *Parses a ruleset as defined by the css core grammar in chapter
  700. *4.1 of the css2 spec.
  701. *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
  702. *@param a_this the current instance of #CRParser.
  703. *@return CR_OK upon successfull completion, an error code otherwise.
  704. */
  705. static enum CRStatus
  706. cr_parser_parse_ruleset_core (CRParser * a_this)
  707. {
  708. CRToken *token = NULL;
  709. CRInputPos init_pos;
  710. enum CRStatus status = CR_ERROR;
  711. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  712. RECORD_INITIAL_POS (a_this, &init_pos);
  713. status = cr_parser_parse_selector_core (a_this);
  714. ENSURE_PARSING_COND (status == CR_OK
  715. || status == CR_PARSING_ERROR
  716. || status == CR_END_OF_INPUT_ERROR);
  717. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  718. ENSURE_PARSING_COND (status == CR_OK && token
  719. && token->type == CBO_TK);
  720. cr_token_destroy (token);
  721. token = NULL;
  722. cr_parser_try_to_skip_spaces_and_comments (a_this);
  723. status = cr_parser_parse_declaration_core (a_this);
  724. parse_declaration_list:
  725. if (token) {
  726. cr_token_destroy (token);
  727. token = NULL;
  728. }
  729. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  730. ENSURE_PARSING_COND (status == CR_OK && token);
  731. if (token->type == CBC_TK) {
  732. goto done;
  733. }
  734. ENSURE_PARSING_COND (status == CR_OK
  735. && token && token->type == SEMICOLON_TK);
  736. cr_token_destroy (token);
  737. token = NULL;
  738. cr_parser_try_to_skip_spaces_and_comments (a_this);
  739. status = cr_parser_parse_declaration_core (a_this);
  740. cr_parser_clear_errors (a_this);
  741. ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR);
  742. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  743. ENSURE_PARSING_COND (status == CR_OK && token);
  744. if (token->type == CBC_TK) {
  745. cr_token_destroy (token);
  746. token = NULL;
  747. cr_parser_try_to_skip_spaces_and_comments (a_this);
  748. goto done;
  749. } else {
  750. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  751. token);
  752. token = NULL;
  753. goto parse_declaration_list;
  754. }
  755. done:
  756. if (token) {
  757. cr_token_destroy (token);
  758. token = NULL;
  759. }
  760. if (status == CR_OK) {
  761. return CR_OK;
  762. }
  763. error:
  764. if (token) {
  765. cr_token_destroy (token);
  766. token = NULL;
  767. }
  768. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  769. return status;
  770. }
  771. /**
  772. *Parses a "selector" as specified by the css core
  773. *grammar.
  774. *selector : any+;
  775. *@param a_this the current instance of #CRParser.
  776. *@return CR_OK upon successfull completion, an error code
  777. *otherwise.
  778. */
  779. static enum CRStatus
  780. cr_parser_parse_selector_core (CRParser * a_this)
  781. {
  782. CRToken *token = NULL;
  783. CRInputPos init_pos;
  784. enum CRStatus status = CR_ERROR;
  785. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  786. RECORD_INITIAL_POS (a_this, &init_pos);
  787. status = cr_parser_parse_any_core (a_this);
  788. CHECK_PARSING_STATUS (status, FALSE);
  789. do {
  790. status = cr_parser_parse_any_core (a_this);
  791. } while (status == CR_OK);
  792. return CR_OK;
  793. error:
  794. if (token) {
  795. cr_token_destroy (token);
  796. token = NULL;
  797. }
  798. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  799. return status;
  800. }
  801. /**
  802. *Parses a "block" as defined in the css core grammar
  803. *in chapter 4.1 of the css2 spec.
  804. *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
  805. *@param a_this the current instance of #CRParser.
  806. *FIXME: code this function.
  807. */
  808. static enum CRStatus
  809. cr_parser_parse_block_core (CRParser * a_this)
  810. {
  811. CRToken *token = NULL;
  812. CRInputPos init_pos;
  813. enum CRStatus status = CR_ERROR;
  814. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  815. RECORD_INITIAL_POS (a_this, &init_pos);
  816. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  817. ENSURE_PARSING_COND (status == CR_OK && token
  818. && token->type == CBO_TK);
  819. parse_block_content:
  820. if (token) {
  821. cr_token_destroy (token);
  822. token = NULL;
  823. }
  824. cr_parser_try_to_skip_spaces_and_comments (a_this);
  825. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  826. ENSURE_PARSING_COND (status == CR_OK && token);
  827. if (token->type == CBC_TK) {
  828. cr_parser_try_to_skip_spaces_and_comments (a_this);
  829. goto done;
  830. } else if (token->type == SEMICOLON_TK) {
  831. goto parse_block_content;
  832. } else if (token->type == ATKEYWORD_TK) {
  833. cr_parser_try_to_skip_spaces_and_comments (a_this);
  834. goto parse_block_content;
  835. } else if (token->type == CBO_TK) {
  836. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  837. token = NULL;
  838. status = cr_parser_parse_block_core (a_this);
  839. CHECK_PARSING_STATUS (status, FALSE);
  840. goto parse_block_content;
  841. } else {
  842. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  843. token = NULL;
  844. status = cr_parser_parse_any_core (a_this);
  845. CHECK_PARSING_STATUS (status, FALSE);
  846. goto parse_block_content;
  847. }
  848. done:
  849. if (token) {
  850. cr_token_destroy (token);
  851. token = NULL;
  852. }
  853. if (status == CR_OK)
  854. return CR_OK;
  855. error:
  856. if (token) {
  857. cr_token_destroy (token);
  858. token = NULL;
  859. }
  860. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  861. return status;
  862. }
  863. static enum CRStatus
  864. cr_parser_parse_declaration_core (CRParser * a_this)
  865. {
  866. CRToken *token = NULL;
  867. CRInputPos init_pos;
  868. enum CRStatus status = CR_ERROR;
  869. CRString *prop = NULL;
  870. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  871. RECORD_INITIAL_POS (a_this, &init_pos);
  872. status = cr_parser_parse_property (a_this, &prop);
  873. CHECK_PARSING_STATUS (status, FALSE);
  874. cr_parser_clear_errors (a_this);
  875. ENSURE_PARSING_COND (status == CR_OK && prop);
  876. cr_string_destroy (prop);
  877. prop = NULL;
  878. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  879. ENSURE_PARSING_COND (status == CR_OK
  880. && token
  881. && token->type == DELIM_TK
  882. && token->u.unichar == ':');
  883. cr_token_destroy (token);
  884. token = NULL;
  885. cr_parser_try_to_skip_spaces_and_comments (a_this);
  886. status = cr_parser_parse_value_core (a_this);
  887. CHECK_PARSING_STATUS (status, FALSE);
  888. return CR_OK;
  889. error:
  890. if (prop) {
  891. cr_string_destroy (prop);
  892. prop = NULL;
  893. }
  894. if (token) {
  895. cr_token_destroy (token);
  896. token = NULL;
  897. }
  898. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  899. return status;
  900. }
  901. /**
  902. *Parses a "value" production as defined by the css core grammar
  903. *in chapter 4.1.
  904. *value ::= [ any | block | ATKEYWORD S* ]+;
  905. *@param a_this the current instance of #CRParser.
  906. *@return CR_OK upon successfull completion, an error code otherwise.
  907. */
  908. static enum CRStatus
  909. cr_parser_parse_value_core (CRParser * a_this)
  910. {
  911. CRToken *token = NULL;
  912. CRInputPos init_pos;
  913. enum CRStatus status = CR_ERROR;
  914. glong ref = 0;
  915. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  916. RECORD_INITIAL_POS (a_this, &init_pos);
  917. continue_parsing:
  918. if (token) {
  919. cr_token_destroy (token);
  920. token = NULL;
  921. }
  922. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  923. ENSURE_PARSING_COND (status == CR_OK && token);
  924. switch (token->type) {
  925. case CBO_TK:
  926. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  927. token);
  928. token = NULL;
  929. status = cr_parser_parse_block_core (a_this);
  930. CHECK_PARSING_STATUS (status, FALSE);
  931. ref++;
  932. goto continue_parsing;
  933. case ATKEYWORD_TK:
  934. cr_parser_try_to_skip_spaces_and_comments (a_this);
  935. ref++;
  936. goto continue_parsing;
  937. default:
  938. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  939. token);
  940. token = NULL;
  941. status = cr_parser_parse_any_core (a_this);
  942. if (status == CR_OK) {
  943. ref++;
  944. goto continue_parsing;
  945. } else if (status == CR_PARSING_ERROR) {
  946. status = CR_OK;
  947. goto done;
  948. } else {
  949. goto error;
  950. }
  951. }
  952. done:
  953. if (token) {
  954. cr_token_destroy (token);
  955. token = NULL;
  956. }
  957. if (status == CR_OK && ref)
  958. return CR_OK;
  959. error:
  960. if (token) {
  961. cr_token_destroy (token);
  962. token = NULL;
  963. }
  964. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  965. return status;
  966. }
  967. /**
  968. *Parses an "any" as defined by the css core grammar in the
  969. *css2 spec in chapter 4.1.
  970. *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
  971. * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
  972. * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
  973. *
  974. *@param a_this the current instance of #CRParser.
  975. *@return CR_OK upon successfull completion, an error code otherwise.
  976. */
  977. static enum CRStatus
  978. cr_parser_parse_any_core (CRParser * a_this)
  979. {
  980. CRToken *token1 = NULL,
  981. *token2 = NULL;
  982. CRInputPos init_pos;
  983. enum CRStatus status = CR_ERROR;
  984. g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
  985. RECORD_INITIAL_POS (a_this, &init_pos);
  986. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1);
  987. ENSURE_PARSING_COND (status == CR_OK && token1);
  988. switch (token1->type) {
  989. case IDENT_TK:
  990. case NUMBER_TK:
  991. case RGB_TK:
  992. case PERCENTAGE_TK:
  993. case DIMEN_TK:
  994. case EMS_TK:
  995. case EXS_TK:
  996. case LENGTH_TK:
  997. case ANGLE_TK:
  998. case FREQ_TK:
  999. case TIME_TK:
  1000. case STRING_TK:
  1001. case DELIM_TK:
  1002. case URI_TK:
  1003. case HASH_TK:
  1004. case UNICODERANGE_TK:
  1005. case INCLUDES_TK:
  1006. case DASHMATCH_TK:
  1007. case S_TK:
  1008. case COMMENT_TK:
  1009. case IMPORTANT_SYM_TK:
  1010. status = CR_OK;
  1011. break;
  1012. case FUNCTION_TK:
  1013. /*
  1014. *this case isn't specified by the spec but it
  1015. *does happen. So we have to handle it.
  1016. *We must consider function with parameters.
  1017. *We consider parameter as being an "any*" production.
  1018. */
  1019. do {
  1020. status = cr_parser_parse_any_core (a_this);
  1021. } while (status == CR_OK);
  1022. ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
  1023. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1024. &token2);
  1025. ENSURE_PARSING_COND (status == CR_OK
  1026. && token2 && token2->type == PC_TK);
  1027. break;
  1028. case PO_TK:
  1029. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1030. &token2);
  1031. ENSURE_PARSING_COND (status == CR_OK && token2);
  1032. if (token2->type == PC_TK) {
  1033. cr_token_destroy (token2);
  1034. token2 = NULL;
  1035. goto done;
  1036. } else {
  1037. status = cr_tknzr_unget_token
  1038. (PRIVATE (a_this)->tknzr, token2);
  1039. token2 = NULL;
  1040. }
  1041. do {
  1042. status = cr_parser_parse_any_core (a_this);
  1043. } while (status == CR_OK);
  1044. ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
  1045. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1046. &token2);
  1047. ENSURE_PARSING_COND (status == CR_OK
  1048. && token2 && token2->type == PC_TK);
  1049. status = CR_OK;
  1050. break;
  1051. case BO_TK:
  1052. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1053. &token2);
  1054. ENSURE_PARSING_COND (status == CR_OK && token2);
  1055. if (token2->type == BC_TK) {
  1056. cr_token_destroy (token2);
  1057. token2 = NULL;
  1058. goto done;
  1059. } else {
  1060. status = cr_tknzr_unget_token
  1061. (PRIVATE (a_this)->tknzr, token2);
  1062. token2 = NULL;
  1063. }
  1064. do {
  1065. status = cr_parser_parse_any_core (a_this);
  1066. } while (status == CR_OK);
  1067. ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
  1068. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1069. &token2);
  1070. ENSURE_PARSING_COND (status == CR_OK
  1071. && token2 && token2->type == BC_TK);
  1072. status = CR_OK;
  1073. break;
  1074. default:
  1075. status = CR_PARSING_ERROR;
  1076. goto error;
  1077. }
  1078. done:
  1079. if (token1) {
  1080. cr_token_destroy (token1);
  1081. token1 = NULL;
  1082. }
  1083. if (token2) {
  1084. cr_token_destroy (token2);
  1085. token2 = NULL;
  1086. }
  1087. return CR_OK;
  1088. error:
  1089. if (token1) {
  1090. cr_token_destroy (token1);
  1091. token1 = NULL;
  1092. }
  1093. if (token2) {
  1094. cr_token_destroy (token2);
  1095. token2 = NULL;
  1096. }
  1097. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1098. return status;
  1099. }
  1100. /**
  1101. *Parses an attribute selector as defined in the css2 spec in
  1102. *appendix D.1:
  1103. *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
  1104. * [ IDENT | STRING ] S* ]? ']'
  1105. *
  1106. *@param a_this the "this pointer" of the current instance of
  1107. *#CRParser .
  1108. *@param a_sel out parameter. The successfully parsed attribute selector.
  1109. *@return CR_OK upon successfull completion, an error code otherwise.
  1110. */
  1111. static enum CRStatus
  1112. cr_parser_parse_attribute_selector (CRParser * a_this,
  1113. CRAttrSel ** a_sel)
  1114. {
  1115. enum CRStatus status = CR_OK;
  1116. CRInputPos init_pos;
  1117. CRToken *token = NULL;
  1118. CRAttrSel *result = NULL;
  1119. CRParsingLocation location = {0} ;
  1120. g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
  1121. RECORD_INITIAL_POS (a_this, &init_pos);
  1122. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1123. ENSURE_PARSING_COND (status == CR_OK && token
  1124. && token->type == BO_TK);
  1125. cr_parsing_location_copy
  1126. (&location, &token->location) ;
  1127. cr_token_destroy (token);
  1128. token = NULL;
  1129. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1130. result = cr_attr_sel_new ();
  1131. if (!result) {
  1132. cr_utils_trace_info ("result failed") ;
  1133. status = CR_OUT_OF_MEMORY_ERROR ;
  1134. goto error ;
  1135. }
  1136. cr_parsing_location_copy (&result->location,
  1137. &location) ;
  1138. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1139. ENSURE_PARSING_COND (status == CR_OK
  1140. && token && token->type == IDENT_TK);
  1141. result->name = token->u.str;
  1142. token->u.str = NULL;
  1143. cr_token_destroy (token);
  1144. token = NULL;
  1145. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1146. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1147. ENSURE_PARSING_COND (status == CR_OK && token);
  1148. if (token->type == INCLUDES_TK) {
  1149. result->match_way = INCLUDES;
  1150. goto parse_right_part;
  1151. } else if (token->type == DASHMATCH_TK) {
  1152. result->match_way = DASHMATCH;
  1153. goto parse_right_part;
  1154. } else if (token->type == DELIM_TK && token->u.unichar == '=') {
  1155. result->match_way = EQUALS;
  1156. goto parse_right_part;
  1157. } else if (token->type == BC_TK) {
  1158. result->match_way = SET;
  1159. goto done;
  1160. }
  1161. parse_right_part:
  1162. if (token) {
  1163. cr_token_destroy (token);
  1164. token = NULL;
  1165. }
  1166. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1167. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1168. ENSURE_PARSING_COND (status == CR_OK && token);
  1169. if (token->type == IDENT_TK) {
  1170. result->value = token->u.str;
  1171. token->u.str = NULL;
  1172. } else if (token->type == STRING_TK) {
  1173. result->value = token->u.str;
  1174. token->u.str = NULL;
  1175. } else {
  1176. status = CR_PARSING_ERROR;
  1177. goto error;
  1178. }
  1179. if (token) {
  1180. cr_token_destroy (token);
  1181. token = NULL;
  1182. }
  1183. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1184. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1185. ENSURE_PARSING_COND (status == CR_OK && token
  1186. && token->type == BC_TK);
  1187. done:
  1188. if (token) {
  1189. cr_token_destroy (token);
  1190. token = NULL;
  1191. }
  1192. if (*a_sel) {
  1193. status = cr_attr_sel_append_attr_sel (*a_sel, result);
  1194. CHECK_PARSING_STATUS (status, FALSE);
  1195. } else {
  1196. *a_sel = result;
  1197. }
  1198. cr_parser_clear_errors (a_this);
  1199. return CR_OK;
  1200. error:
  1201. if (result) {
  1202. cr_attr_sel_destroy (result);
  1203. result = NULL;
  1204. }
  1205. if (token) {
  1206. cr_token_destroy (token);
  1207. token = NULL;
  1208. }
  1209. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1210. return status;
  1211. }
  1212. /**
  1213. *Parses a "property" as specified by the css2 spec at [4.1.1]:
  1214. *property : IDENT S*;
  1215. *
  1216. *@param a_this the "this pointer" of the current instance of #CRParser.
  1217. *@param GString a_property out parameter. The parsed property without the
  1218. *trailing spaces. If *a_property is NULL, this function allocates a
  1219. *new instance of GString and set it content to the parsed property.
  1220. *If not, the property is just appended to a_property's previous content.
  1221. *In both cases, it is up to the caller to free a_property.
  1222. *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the
  1223. *next construction was not a "property", or an error code.
  1224. */
  1225. static enum CRStatus
  1226. cr_parser_parse_property (CRParser * a_this,
  1227. CRString ** a_property)
  1228. {
  1229. enum CRStatus status = CR_OK;
  1230. CRInputPos init_pos;
  1231. g_return_val_if_fail (a_this && PRIVATE (a_this)
  1232. && PRIVATE (a_this)->tknzr
  1233. && a_property,
  1234. CR_BAD_PARAM_ERROR);
  1235. RECORD_INITIAL_POS (a_this, &init_pos);
  1236. status = cr_parser_parse_ident (a_this, a_property);
  1237. CHECK_PARSING_STATUS (status, TRUE);
  1238. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1239. cr_parser_clear_errors (a_this);
  1240. return CR_OK;
  1241. error:
  1242. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1243. return status;
  1244. }
  1245. /**
  1246. *Parses a "term" as defined in the css2 spec, appendix D.1:
  1247. *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* |
  1248. *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] |
  1249. *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
  1250. *
  1251. *TODO: handle parsing of 'RGB'
  1252. *
  1253. *@param a_term out parameter. The successfully parsed term.
  1254. *@return CR_OK upon successfull completion, an error code otherwise.
  1255. */
  1256. enum CRStatus
  1257. cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term)
  1258. {
  1259. enum CRStatus status = CR_PARSING_ERROR;
  1260. CRInputPos init_pos;
  1261. CRTerm *result = NULL;
  1262. CRTerm *param = NULL;
  1263. CRToken *token = NULL;
  1264. CRString *func_name = NULL;
  1265. CRParsingLocation location = {0} ;
  1266. g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR);
  1267. RECORD_INITIAL_POS (a_this, &init_pos);
  1268. result = cr_term_new ();
  1269. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1270. &token);
  1271. if (status != CR_OK || !token)
  1272. goto error;
  1273. cr_parsing_location_copy (&location, &token->location) ;
  1274. if (token->type == DELIM_TK && token->u.unichar == '+') {
  1275. result->unary_op = PLUS_UOP;
  1276. cr_token_destroy (token) ;
  1277. token = NULL ;
  1278. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1279. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1280. &token);
  1281. if (status != CR_OK || !token)
  1282. goto error;
  1283. } else if (token->type == DELIM_TK && token->u.unichar == '-') {
  1284. result->unary_op = MINUS_UOP;
  1285. cr_token_destroy (token) ;
  1286. token = NULL ;
  1287. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1288. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  1289. &token);
  1290. if (status != CR_OK || !token)
  1291. goto error;
  1292. }
  1293. if (token->type == EMS_TK
  1294. || token->type == EXS_TK
  1295. || token->type == LENGTH_TK
  1296. || token->type == ANGLE_TK
  1297. || token->type == TIME_TK
  1298. || token->type == FREQ_TK
  1299. || token->type == PERCENTAGE_TK
  1300. || token->type == NUMBER_TK) {
  1301. status = cr_term_set_number (result, token->u.num);
  1302. CHECK_PARSING_STATUS (status, TRUE);
  1303. token->u.num = NULL;
  1304. status = CR_OK;
  1305. } else if (token && token->type == FUNCTION_TK) {
  1306. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  1307. token);
  1308. token = NULL;
  1309. status = cr_parser_parse_function (a_this, &func_name,
  1310. &param);
  1311. if (status == CR_OK) {
  1312. status = cr_term_set_function (result,
  1313. func_name,
  1314. param);
  1315. CHECK_PARSING_STATUS (status, TRUE);
  1316. }
  1317. } else if (token && token->type == STRING_TK) {
  1318. status = cr_term_set_string (result,
  1319. token->u.str);
  1320. CHECK_PARSING_STATUS (status, TRUE);
  1321. token->u.str = NULL;
  1322. } else if (token && token->type == IDENT_TK) {
  1323. status = cr_term_set_ident (result, token->u.str);
  1324. CHECK_PARSING_STATUS (status, TRUE);
  1325. token->u.str = NULL;
  1326. } else if (token && token->type == URI_TK) {
  1327. status = cr_term_set_uri (result, token->u.str);
  1328. CHECK_PARSING_STATUS (status, TRUE);
  1329. token->u.str = NULL;
  1330. } else if (token && token->type == RGB_TK) {
  1331. status = cr_term_set_rgb (result, token->u.rgb);
  1332. CHECK_PARSING_STATUS (status, TRUE);
  1333. token->u.rgb = NULL;
  1334. } else if (token && token->type == UNICODERANGE_TK) {
  1335. result->type = TERM_UNICODERANGE;
  1336. status = CR_PARSING_ERROR;
  1337. } else if (token && token->type == HASH_TK) {
  1338. status = cr_term_set_hash (result, token->u.str);
  1339. CHECK_PARSING_STATUS (status, TRUE);
  1340. token->u.str = NULL;
  1341. } else {
  1342. status = CR_PARSING_ERROR;
  1343. }
  1344. if (status != CR_OK) {
  1345. goto error;
  1346. }
  1347. cr_parsing_location_copy (&result->location,
  1348. &location) ;
  1349. *a_term = cr_term_append_term (*a_term, result);
  1350. result = NULL;
  1351. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1352. if (token) {
  1353. cr_token_destroy (token);
  1354. token = NULL;
  1355. }
  1356. cr_parser_clear_errors (a_this);
  1357. return CR_OK;
  1358. error:
  1359. if (result) {
  1360. cr_term_destroy (result);
  1361. result = NULL;
  1362. }
  1363. if (token) {
  1364. cr_token_destroy (token);
  1365. token = NULL;
  1366. }
  1367. if (param) {
  1368. cr_term_destroy (param);
  1369. param = NULL;
  1370. }
  1371. if (func_name) {
  1372. cr_string_destroy (func_name);
  1373. func_name = NULL;
  1374. }
  1375. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1376. return status;
  1377. }
  1378. /**
  1379. *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 :
  1380. *element_name? [ HASH | class | attrib | pseudo ]* S*
  1381. *and where pseudo is:
  1382. *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ]
  1383. *
  1384. *@Param a_this the "this pointer" of the current instance of #CRParser.
  1385. *@param a_sel out parameter. Is set to the successfully parsed simple
  1386. *selector.
  1387. *@return CR_OK upon successfull completion, an error code otherwise.
  1388. */
  1389. static enum CRStatus
  1390. cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel)
  1391. {
  1392. enum CRStatus status = CR_ERROR;
  1393. CRInputPos init_pos;
  1394. CRToken *token = NULL;
  1395. CRSimpleSel *sel = NULL;
  1396. CRAdditionalSel *add_sel_list = NULL;
  1397. gboolean found_sel = FALSE;
  1398. guint32 cur_char = 0;
  1399. g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
  1400. RECORD_INITIAL_POS (a_this, &init_pos);
  1401. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1402. if (status != CR_OK)
  1403. goto error;
  1404. sel = cr_simple_sel_new ();
  1405. ENSURE_PARSING_COND (sel);
  1406. cr_parsing_location_copy
  1407. (&sel->location,
  1408. &token->location) ;
  1409. if (token && token->type == DELIM_TK
  1410. && token->u.unichar == '*') {
  1411. sel->type_mask |= UNIVERSAL_SELECTOR;
  1412. sel->name = cr_string_new_from_string ("*");
  1413. found_sel = TRUE;
  1414. } else if (token && token->type == IDENT_TK) {
  1415. sel->name = token->u.str;
  1416. sel->type_mask |= TYPE_SELECTOR;
  1417. token->u.str = NULL;
  1418. found_sel = TRUE;
  1419. } else {
  1420. status = cr_tknzr_unget_token
  1421. (PRIVATE (a_this)->tknzr,
  1422. token);
  1423. token = NULL;
  1424. }
  1425. if (token) {
  1426. cr_token_destroy (token);
  1427. token = NULL;
  1428. }
  1429. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1430. for (;;) {
  1431. if (token) {
  1432. cr_token_destroy (token);
  1433. token = NULL;
  1434. }
  1435. status = cr_tknzr_get_next_token
  1436. (PRIVATE (a_this)->tknzr,
  1437. &token);
  1438. if (status != CR_OK)
  1439. goto error;
  1440. if (token && token->type == HASH_TK) {
  1441. /*we parsed an attribute id */
  1442. CRAdditionalSel *add_sel = NULL;
  1443. add_sel = cr_additional_sel_new_with_type
  1444. (ID_ADD_SELECTOR);
  1445. add_sel->content.id_name = token->u.str;
  1446. token->u.str = NULL;
  1447. cr_parsing_location_copy
  1448. (&add_sel->location,
  1449. &token->location) ;
  1450. add_sel_list =
  1451. cr_additional_sel_append
  1452. (add_sel_list, add_sel);
  1453. found_sel = TRUE;
  1454. } else if (token && (token->type == DELIM_TK)
  1455. && (token->u.unichar == '.')) {
  1456. cr_token_destroy (token);
  1457. token = NULL;
  1458. status = cr_tknzr_get_next_token
  1459. (PRIVATE (a_this)->tknzr, &token);
  1460. if (status != CR_OK)
  1461. goto error;
  1462. if (token && token->type == IDENT_TK) {
  1463. CRAdditionalSel *add_sel = NULL;
  1464. add_sel = cr_additional_sel_new_with_type
  1465. (CLASS_ADD_SELECTOR);
  1466. add_sel->content.class_name = token->u.str;
  1467. token->u.str = NULL;
  1468. add_sel_list =
  1469. cr_additional_sel_append
  1470. (add_sel_list, add_sel);
  1471. found_sel = TRUE;
  1472. cr_parsing_location_copy
  1473. (&add_sel->location,
  1474. & token->location) ;
  1475. } else {
  1476. status = CR_PARSING_ERROR;
  1477. goto error;
  1478. }
  1479. } else if (token && token->type == BO_TK) {
  1480. CRAttrSel *attr_sel = NULL;
  1481. CRAdditionalSel *add_sel = NULL;
  1482. status = cr_tknzr_unget_token
  1483. (PRIVATE (a_this)->tknzr, token);
  1484. if (status != CR_OK)
  1485. goto error;
  1486. token = NULL;
  1487. status = cr_parser_parse_attribute_selector
  1488. (a_this, &attr_sel);
  1489. CHECK_PARSING_STATUS (status, FALSE);
  1490. add_sel = cr_additional_sel_new_with_type
  1491. (ATTRIBUTE_ADD_SELECTOR);
  1492. ENSURE_PARSING_COND (add_sel != NULL);
  1493. add_sel->content.attr_sel = attr_sel;
  1494. add_sel_list =
  1495. cr_additional_sel_append
  1496. (add_sel_list, add_sel);
  1497. found_sel = TRUE;
  1498. cr_parsing_location_copy
  1499. (&add_sel->location,
  1500. &attr_sel->location) ;
  1501. } else if (token && (token->type == DELIM_TK)
  1502. && (token->u.unichar == ':')) {
  1503. CRPseudo *pseudo = NULL;
  1504. /*try to parse a pseudo */
  1505. if (token) {
  1506. cr_token_destroy (token);
  1507. token = NULL;
  1508. }
  1509. pseudo = cr_pseudo_new ();
  1510. status = cr_tknzr_get_next_token
  1511. (PRIVATE (a_this)->tknzr, &token);
  1512. ENSURE_PARSING_COND (status == CR_OK && token);
  1513. cr_parsing_location_copy
  1514. (&pseudo->location,
  1515. &token->location) ;
  1516. if (token->type == IDENT_TK) {
  1517. pseudo->type = IDENT_PSEUDO;
  1518. pseudo->name = token->u.str;
  1519. token->u.str = NULL;
  1520. found_sel = TRUE;
  1521. } else if (token->type == FUNCTION_TK) {
  1522. pseudo->name = token->u.str;
  1523. token->u.str = NULL;
  1524. cr_parser_try_to_skip_spaces_and_comments
  1525. (a_this);
  1526. status = cr_parser_parse_ident
  1527. (a_this, &pseudo->extra);
  1528. ENSURE_PARSING_COND (status == CR_OK);
  1529. READ_NEXT_CHAR (a_this, &cur_char);
  1530. ENSURE_PARSING_COND (cur_char == ')');
  1531. pseudo->type = FUNCTION_PSEUDO;
  1532. found_sel = TRUE;
  1533. } else {
  1534. status = CR_PARSING_ERROR;
  1535. goto error;
  1536. }
  1537. if (status == CR_OK) {
  1538. CRAdditionalSel *add_sel = NULL;
  1539. add_sel = cr_additional_sel_new_with_type
  1540. (PSEUDO_CLASS_ADD_SELECTOR);
  1541. add_sel->content.pseudo = pseudo;
  1542. cr_parsing_location_copy
  1543. (&add_sel->location,
  1544. &pseudo->location) ;
  1545. add_sel_list =
  1546. cr_additional_sel_append
  1547. (add_sel_list, add_sel);
  1548. status = CR_OK;
  1549. }
  1550. } else {
  1551. status = cr_tknzr_unget_token
  1552. (PRIVATE (a_this)->tknzr, token);
  1553. token = NULL;
  1554. break;
  1555. }
  1556. }
  1557. if (status == CR_OK && found_sel == TRUE) {
  1558. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1559. sel->add_sel = add_sel_list;
  1560. add_sel_list = NULL;
  1561. if (*a_sel == NULL) {
  1562. *a_sel = sel;
  1563. } else {
  1564. cr_simple_sel_append_simple_sel (*a_sel, sel);
  1565. }
  1566. sel = NULL;
  1567. if (token) {
  1568. cr_token_destroy (token);
  1569. token = NULL;
  1570. }
  1571. cr_parser_clear_errors (a_this);
  1572. return CR_OK;
  1573. } else {
  1574. status = CR_PARSING_ERROR;
  1575. }
  1576. error:
  1577. if (token) {
  1578. cr_token_destroy (token);
  1579. token = NULL;
  1580. }
  1581. if (add_sel_list) {
  1582. cr_additional_sel_destroy (add_sel_list);
  1583. add_sel_list = NULL;
  1584. }
  1585. if (sel) {
  1586. cr_simple_sel_destroy (sel);
  1587. sel = NULL;
  1588. }
  1589. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1590. return status;
  1591. }
  1592. /**
  1593. *Parses a "selector" as defined by the css2 spec in appendix D.1:
  1594. *selector ::= simple_selector [ combinator simple_selector ]*
  1595. *
  1596. *@param a_this the this pointer of the current instance of #CRParser.
  1597. *@param a_start a pointer to the
  1598. *first chararcter of the successfully parsed
  1599. *string.
  1600. *@param a_end a pointer to the last character of the successfully parsed
  1601. *string.
  1602. *@return CR_OK upon successfull completion, an error code otherwise.
  1603. */
  1604. static enum CRStatus
  1605. cr_parser_parse_simple_sels (CRParser * a_this,
  1606. CRSimpleSel ** a_sel)
  1607. {
  1608. enum CRStatus status = CR_ERROR;
  1609. CRInputPos init_pos;
  1610. CRSimpleSel *sel = NULL;
  1611. guint32 cur_char = 0;
  1612. g_return_val_if_fail (a_this
  1613. && PRIVATE (a_this)
  1614. && a_sel,
  1615. CR_BAD_PARAM_ERROR);
  1616. RECORD_INITIAL_POS (a_this, &init_pos);
  1617. status = cr_parser_parse_simple_selector (a_this, &sel);
  1618. CHECK_PARSING_STATUS (status, FALSE);
  1619. *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel);
  1620. for (;;) {
  1621. guint32 next_char = 0;
  1622. enum Combinator comb = 0;
  1623. sel = NULL;
  1624. PEEK_NEXT_CHAR (a_this, &next_char);
  1625. if (next_char == '+') {
  1626. READ_NEXT_CHAR (a_this, &cur_char);
  1627. comb = COMB_PLUS;
  1628. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1629. } else if (next_char == '>') {
  1630. READ_NEXT_CHAR (a_this, &cur_char);
  1631. comb = COMB_GT;
  1632. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1633. } else {
  1634. comb = COMB_WS;
  1635. }
  1636. status = cr_parser_parse_simple_selector (a_this, &sel);
  1637. if (status != CR_OK)
  1638. break;
  1639. if (comb && sel) {
  1640. sel->combinator = comb;
  1641. comb = 0;
  1642. }
  1643. if (sel) {
  1644. *a_sel = cr_simple_sel_append_simple_sel (*a_sel,
  1645. sel) ;
  1646. }
  1647. }
  1648. cr_parser_clear_errors (a_this);
  1649. return CR_OK;
  1650. error:
  1651. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1652. return status;
  1653. }
  1654. /**
  1655. *Parses a comma separated list of selectors.
  1656. *@param a_this the current instance of #CRParser.
  1657. *@param a_selector the parsed list of comma separated
  1658. *selectors.
  1659. *@return CR_OK upon successful completion, an error
  1660. *code otherwise.
  1661. */
  1662. static enum CRStatus
  1663. cr_parser_parse_selector (CRParser * a_this,
  1664. CRSelector ** a_selector)
  1665. {
  1666. enum CRStatus status = CR_OK;
  1667. CRInputPos init_pos;
  1668. guint32 cur_char = 0,
  1669. next_char = 0;
  1670. CRSimpleSel *simple_sels = NULL;
  1671. CRSelector *selector = NULL;
  1672. g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR);
  1673. RECORD_INITIAL_POS (a_this, &init_pos);
  1674. status = cr_parser_parse_simple_sels (a_this, &simple_sels);
  1675. CHECK_PARSING_STATUS (status, FALSE);
  1676. if (simple_sels) {
  1677. selector = cr_selector_append_simple_sel
  1678. (selector, simple_sels);
  1679. if (selector) {
  1680. cr_parsing_location_copy
  1681. (&selector->location,
  1682. &simple_sels->location) ;
  1683. }
  1684. simple_sels = NULL;
  1685. } else {
  1686. status = CR_PARSING_ERROR ;
  1687. goto error ;
  1688. }
  1689. status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
  1690. &next_char);
  1691. if (status != CR_OK) {
  1692. if (status == CR_END_OF_INPUT_ERROR) {
  1693. status = CR_OK;
  1694. goto okay;
  1695. } else {
  1696. goto error;
  1697. }
  1698. }
  1699. if (next_char == ',') {
  1700. for (;;) {
  1701. simple_sels = NULL;
  1702. status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
  1703. &next_char);
  1704. if (status != CR_OK) {
  1705. if (status == CR_END_OF_INPUT_ERROR) {
  1706. status = CR_OK;
  1707. break;
  1708. } else {
  1709. goto error;
  1710. }
  1711. }
  1712. if (next_char != ',')
  1713. break;
  1714. /*consume the ',' char */
  1715. READ_NEXT_CHAR (a_this, &cur_char);
  1716. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1717. status = cr_parser_parse_simple_sels
  1718. (a_this, &simple_sels);
  1719. CHECK_PARSING_STATUS (status, FALSE);
  1720. if (simple_sels) {
  1721. selector =
  1722. cr_selector_append_simple_sel
  1723. (selector, simple_sels);
  1724. simple_sels = NULL;
  1725. }
  1726. }
  1727. }
  1728. okay:
  1729. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1730. if (!*a_selector) {
  1731. *a_selector = selector;
  1732. } else {
  1733. *a_selector = cr_selector_append (*a_selector, selector);
  1734. }
  1735. selector = NULL;
  1736. return CR_OK;
  1737. error:
  1738. if (simple_sels) {
  1739. cr_simple_sel_destroy (simple_sels);
  1740. simple_sels = NULL;
  1741. }
  1742. if (selector) {
  1743. cr_selector_unref (selector);
  1744. selector = NULL;
  1745. }
  1746. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1747. return status;
  1748. }
  1749. /**
  1750. *Parses a "function" as defined in css spec at appendix D.1:
  1751. *function ::= FUNCTION S* expr ')' S*
  1752. *FUNCTION ::= ident'('
  1753. *
  1754. *@param a_this the "this pointer" of the current instance of
  1755. *#CRParser.
  1756. *
  1757. *@param a_func_name out parameter. The parsed function name
  1758. *@param a_expr out parameter. The successfully parsed term.
  1759. *@return CR_OK upon successfull completion, an error code otherwise.
  1760. */
  1761. static enum CRStatus
  1762. cr_parser_parse_function (CRParser * a_this,
  1763. CRString ** a_func_name,
  1764. CRTerm ** a_expr)
  1765. {
  1766. CRInputPos init_pos;
  1767. enum CRStatus status = CR_OK;
  1768. CRToken *token = NULL;
  1769. CRTerm *expr = NULL;
  1770. g_return_val_if_fail (a_this && PRIVATE (a_this)
  1771. && a_func_name,
  1772. CR_BAD_PARAM_ERROR);
  1773. RECORD_INITIAL_POS (a_this, &init_pos);
  1774. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1775. if (status != CR_OK)
  1776. goto error;
  1777. if (token && token->type == FUNCTION_TK) {
  1778. *a_func_name = token->u.str;
  1779. token->u.str = NULL;
  1780. } else {
  1781. status = CR_PARSING_ERROR;
  1782. goto error;
  1783. }
  1784. cr_token_destroy (token);
  1785. token = NULL;
  1786. cr_parser_try_to_skip_spaces_and_comments (a_this) ;
  1787. status = cr_parser_parse_expr (a_this, &expr);
  1788. CHECK_PARSING_STATUS (status, FALSE);
  1789. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1790. if (status != CR_OK)
  1791. goto error;
  1792. ENSURE_PARSING_COND (token && token->type == PC_TK);
  1793. cr_token_destroy (token);
  1794. token = NULL;
  1795. if (expr) {
  1796. *a_expr = cr_term_append_term (*a_expr, expr);
  1797. expr = NULL;
  1798. }
  1799. cr_parser_clear_errors (a_this);
  1800. return CR_OK;
  1801. error:
  1802. if (*a_func_name) {
  1803. cr_string_destroy (*a_func_name);
  1804. *a_func_name = NULL;
  1805. }
  1806. if (expr) {
  1807. cr_term_destroy (expr);
  1808. expr = NULL;
  1809. }
  1810. if (token) {
  1811. cr_token_destroy (token);
  1812. }
  1813. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  1814. return status;
  1815. }
  1816. /**
  1817. *Parses an uri as defined by the css spec [4.1.1]:
  1818. * URI ::= url\({w}{string}{w}\)
  1819. * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
  1820. *
  1821. *@param a_this the current instance of #CRParser.
  1822. *@param a_str the successfully parsed url.
  1823. *@return CR_OK upon successfull completion, an error code otherwise.
  1824. */
  1825. static enum CRStatus
  1826. cr_parser_parse_uri (CRParser * a_this, CRString ** a_str)
  1827. {
  1828. enum CRStatus status = CR_PARSING_ERROR;
  1829. g_return_val_if_fail (a_this && PRIVATE (a_this)
  1830. && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
  1831. status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
  1832. URI_TK, NO_ET, a_str, NULL);
  1833. return status;
  1834. }
  1835. /**
  1836. *Parses a string type as defined in css spec [4.1.1]:
  1837. *
  1838. *string ::= {string1}|{string2}
  1839. *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
  1840. *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
  1841. *
  1842. *@param a_this the current instance of #CRParser.
  1843. *@param a_start out parameter. Upon successfull completion,
  1844. *points to the beginning of the string, points to an undefined value
  1845. *otherwise.
  1846. *@param a_end out parameter. Upon successfull completion, points to
  1847. *the beginning of the string, points to an undefined value otherwise.
  1848. *@return CR_OK upon successfull completion, an error code otherwise.
  1849. */
  1850. static enum CRStatus
  1851. cr_parser_parse_string (CRParser * a_this, CRString ** a_str)
  1852. {
  1853. enum CRStatus status = CR_OK;
  1854. g_return_val_if_fail (a_this && PRIVATE (a_this)
  1855. && PRIVATE (a_this)->tknzr
  1856. && a_str, CR_BAD_PARAM_ERROR);
  1857. status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
  1858. STRING_TK, NO_ET, a_str, NULL);
  1859. return status;
  1860. }
  1861. /**
  1862. *Parses an "ident" as defined in css spec [4.1.1]:
  1863. *ident ::= {nmstart}{nmchar}*
  1864. *
  1865. *@param a_this the currens instance of #CRParser.
  1866. *
  1867. *@param a_str a pointer to parsed ident. If *a_str is NULL,
  1868. *this function allocates a new instance of #CRString. If not,
  1869. *the function just appends the parsed string to the one passed.
  1870. *In both cases it is up to the caller to free *a_str.
  1871. *
  1872. *@return CR_OK upon successfull completion, an error code
  1873. *otherwise.
  1874. */
  1875. static enum CRStatus
  1876. cr_parser_parse_ident (CRParser * a_this, CRString ** a_str)
  1877. {
  1878. enum CRStatus status = CR_OK;
  1879. g_return_val_if_fail (a_this && PRIVATE (a_this)
  1880. && PRIVATE (a_this)->tknzr
  1881. && a_str, CR_BAD_PARAM_ERROR);
  1882. status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
  1883. IDENT_TK, NO_ET, a_str, NULL);
  1884. return status;
  1885. }
  1886. /**
  1887. *the next rule is ignored as well. This seems to be a bug
  1888. *Parses a stylesheet as defined in the css2 spec in appendix D.1:
  1889. *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]?
  1890. * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
  1891. * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]*
  1892. *
  1893. *TODO: Finish the code of this function. Think about splitting it into
  1894. *smaller functions.
  1895. *
  1896. *@param a_this the "this pointer" of the current instance of #CRParser.
  1897. *@param a_start out parameter. A pointer to the first character of
  1898. *the successfully parsed string.
  1899. *@param a_end out parameter. A pointer to the first character of
  1900. *the successfully parsed string.
  1901. *
  1902. *@return CR_OK upon successfull completion, an error code otherwise.
  1903. */
  1904. static enum CRStatus
  1905. cr_parser_parse_stylesheet (CRParser * a_this)
  1906. {
  1907. enum CRStatus status = CR_OK;
  1908. CRInputPos init_pos;
  1909. CRToken *token = NULL;
  1910. CRString *charset = NULL;
  1911. g_return_val_if_fail (a_this && PRIVATE (a_this)
  1912. && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
  1913. RECORD_INITIAL_POS (a_this, &init_pos);
  1914. PRIVATE (a_this)->state = READY_STATE;
  1915. if (PRIVATE (a_this)->sac_handler
  1916. && PRIVATE (a_this)->sac_handler->start_document) {
  1917. PRIVATE (a_this)->sac_handler->start_document
  1918. (PRIVATE (a_this)->sac_handler);
  1919. }
  1920. parse_charset:
  1921. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  1922. if (status == CR_END_OF_INPUT_ERROR)
  1923. goto done;
  1924. CHECK_PARSING_STATUS (status, TRUE);
  1925. if (token && token->type == CHARSET_SYM_TK) {
  1926. CRParsingLocation location = {0} ;
  1927. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  1928. token);
  1929. CHECK_PARSING_STATUS (status, TRUE);
  1930. token = NULL;
  1931. status = cr_parser_parse_charset (a_this,
  1932. &charset,
  1933. &location);
  1934. if (status == CR_OK && charset) {
  1935. if (PRIVATE (a_this)->sac_handler
  1936. && PRIVATE (a_this)->sac_handler->charset) {
  1937. PRIVATE (a_this)->sac_handler->charset
  1938. (PRIVATE (a_this)->sac_handler,
  1939. charset, &location);
  1940. }
  1941. } else if (status != CR_END_OF_INPUT_ERROR) {
  1942. status = cr_parser_parse_atrule_core (a_this);
  1943. CHECK_PARSING_STATUS (status, FALSE);
  1944. }
  1945. if (charset) {
  1946. cr_string_destroy (charset);
  1947. charset = NULL;
  1948. }
  1949. } else if (token
  1950. && (token->type == S_TK
  1951. || token->type == COMMENT_TK)) {
  1952. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  1953. token);
  1954. token = NULL;
  1955. CHECK_PARSING_STATUS (status, TRUE);
  1956. cr_parser_try_to_skip_spaces_and_comments (a_this);
  1957. goto parse_charset ;
  1958. } else if (token) {
  1959. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  1960. token);
  1961. token = NULL;
  1962. CHECK_PARSING_STATUS (status, TRUE);
  1963. }
  1964. /* parse_imports:*/
  1965. do {
  1966. if (token) {
  1967. cr_token_destroy (token);
  1968. token = NULL;
  1969. }
  1970. cr_parser_try_to_skip_spaces_and_comments (a_this) ;
  1971. status = cr_tknzr_get_next_token
  1972. (PRIVATE (a_this)->tknzr, &token);
  1973. if (status == CR_END_OF_INPUT_ERROR)
  1974. goto done;
  1975. CHECK_PARSING_STATUS (status, TRUE);
  1976. } while (token
  1977. && (token->type == S_TK
  1978. || token->type == CDO_TK || token->type == CDC_TK));
  1979. if (token) {
  1980. status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
  1981. token);
  1982. token = NULL;
  1983. }
  1984. for (;;) {
  1985. status = cr_tknzr_get_next_token
  1986. (PRIVATE (a_this)->tknzr, &token);
  1987. if (status == CR_END_OF_INPUT_ERROR)
  1988. goto done;
  1989. CHECK_PARSING_STATUS (status, TRUE);
  1990. if (token && token->type == IMPORT_SYM_TK) {
  1991. GList *media_list = NULL;
  1992. CRString *import_string = NULL;
  1993. CRParsingLocation location = {0} ;
  1994. status = cr_tknzr_unget_token
  1995. (PRIVATE (a_this)->tknzr, token);
  1996. token = NULL;
  1997. CHECK_PARSING_STATUS (status, TRUE);
  1998. status = cr_parser_parse_import (a_this,
  1999. &media_list,
  2000. &import_string,
  2001. &location);
  2002. if (status == CR_OK) {
  2003. if (import_string
  2004. && PRIVATE (a_this)->sac_handler
  2005. && PRIVATE (a_this)->sac_handler->import_style) {
  2006. PRIVATE (a_this)->sac_handler->import_style
  2007. (PRIVATE(a_this)->sac_handler,
  2008. media_list,
  2009. import_string,
  2010. NULL, &location) ;
  2011. if ((PRIVATE (a_this)->sac_handler->resolve_import == TRUE)) {
  2012. /*
  2013. *TODO: resolve the
  2014. *import rule.
  2015. */
  2016. }
  2017. if ((PRIVATE (a_this)->sac_handler->import_style_result)) {
  2018. PRIVATE (a_this)->sac_handler->import_style_result
  2019. (PRIVATE (a_this)->sac_handler,
  2020. media_list, import_string,
  2021. NULL, NULL);
  2022. }
  2023. }
  2024. } else if (status != CR_END_OF_INPUT_ERROR) {
  2025. if (PRIVATE (a_this)->sac_handler
  2026. && PRIVATE (a_this)->sac_handler->error) {
  2027. /* changed by iago rubio to track line error numbers */
  2028. CRParserError* err;
  2029. if( PRIVATE (a_this)->err_stack == NULL ){
  2030. cr_parser_push_error (a_this,
  2031. "syntax error",
  2032. status) ;
  2033. }
  2034. err = (CRParserError*) PRIVATE (a_this)->err_stack->data;
  2035. PRIVATE (a_this)->sac_handler->
  2036. error(PRIVATE(a_this)->sac_handler, err->line ) ;
  2037. /* end */
  2038. }
  2039. status = cr_parser_parse_atrule_core (a_this);
  2040. CHECK_PARSING_STATUS (status, TRUE) ;
  2041. } else {
  2042. goto error ;
  2043. }
  2044. /*
  2045. *then, after calling the appropriate
  2046. *SAC handler, free
  2047. *the media_list and import_string.
  2048. */
  2049. if (media_list) {
  2050. GList *cur = NULL;
  2051. /*free the medium list */
  2052. for (cur = media_list; cur; cur = cur->next) {
  2053. if (cur->data) {
  2054. cr_string_destroy (cur->data);
  2055. }
  2056. }
  2057. g_list_free (media_list);
  2058. media_list = NULL;
  2059. }
  2060. if (import_string) {
  2061. cr_string_destroy (import_string);
  2062. import_string = NULL;
  2063. }
  2064. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2065. } else if (token
  2066. && (token->type == S_TK
  2067. || token->type == CDO_TK
  2068. || token->type == CDC_TK)) {
  2069. status = cr_tknzr_unget_token
  2070. (PRIVATE (a_this)->tknzr, token);
  2071. token = NULL;
  2072. do {
  2073. if (token) {
  2074. cr_token_destroy (token);
  2075. token = NULL;
  2076. }
  2077. status = cr_tknzr_get_next_token
  2078. (PRIVATE (a_this)->tknzr, &token);
  2079. if (status == CR_END_OF_INPUT_ERROR)
  2080. goto done;
  2081. CHECK_PARSING_STATUS (status, TRUE);
  2082. } while (token
  2083. && (token->type == S_TK
  2084. || token->type == CDO_TK
  2085. || token->type == CDC_TK));
  2086. } else {
  2087. if (token) {
  2088. status = cr_tknzr_unget_token
  2089. (PRIVATE (a_this)->tknzr, token);
  2090. token = NULL;
  2091. }
  2092. goto parse_ruleset_and_others;
  2093. }
  2094. }
  2095. parse_ruleset_and_others:
  2096. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2097. for (;;) {
  2098. status = cr_tknzr_get_next_token
  2099. (PRIVATE (a_this)->tknzr, &token);
  2100. if (status == CR_END_OF_INPUT_ERROR)
  2101. goto done;
  2102. CHECK_PARSING_STATUS (status, TRUE);
  2103. if (token
  2104. && (token->type == S_TK
  2105. || token->type == CDO_TK || token->type == CDC_TK)) {
  2106. status = cr_tknzr_unget_token
  2107. (PRIVATE (a_this)->tknzr, token);
  2108. token = NULL;
  2109. do {
  2110. if (token) {
  2111. cr_token_destroy (token);
  2112. token = NULL;
  2113. }
  2114. cr_parser_try_to_skip_spaces_and_comments
  2115. (a_this);
  2116. status = cr_tknzr_get_next_token
  2117. (PRIVATE (a_this)->tknzr, &token);
  2118. } while (token
  2119. && (token->type == S_TK
  2120. || token->type == COMMENT_TK
  2121. || token->type == CDO_TK
  2122. || token->type == CDC_TK));
  2123. if (token) {
  2124. cr_tknzr_unget_token
  2125. (PRIVATE (a_this)->tknzr, token);
  2126. token = NULL;
  2127. }
  2128. } else if (token
  2129. && (token->type == HASH_TK
  2130. || (token->type == DELIM_TK
  2131. && token->u.unichar == '.')
  2132. || (token->type == DELIM_TK
  2133. && token->u.unichar == ':')
  2134. || (token->type == DELIM_TK
  2135. && token->u.unichar == '*')
  2136. || (token->type == BO_TK)
  2137. || token->type == IDENT_TK)) {
  2138. /*
  2139. *Try to parse a CSS2 ruleset.
  2140. *if the parsing fails, try to parse
  2141. *a css core ruleset.
  2142. */
  2143. status = cr_tknzr_unget_token
  2144. (PRIVATE (a_this)->tknzr, token);
  2145. CHECK_PARSING_STATUS (status, TRUE);
  2146. token = NULL;
  2147. status = cr_parser_parse_ruleset (a_this);
  2148. if (status == CR_OK) {
  2149. continue;
  2150. } else {
  2151. if (PRIVATE (a_this)->sac_handler
  2152. && PRIVATE (a_this)->sac_handler->error) {
  2153. /* changed by iago rubio to track line error numbers */
  2154. CRParserError* err;
  2155. if( PRIVATE (a_this)->err_stack == NULL ){
  2156. cr_parser_push_error (a_this,
  2157. "syntax error",
  2158. status) ;
  2159. }
  2160. err = (CRParserError*) PRIVATE (a_this)->err_stack->data;
  2161. PRIVATE (a_this)->sac_handler->
  2162. error(PRIVATE(a_this)->sac_handler, err->line ) ;
  2163. /* end */
  2164. }
  2165. status = cr_parser_parse_ruleset_core
  2166. (a_this);
  2167. if (status == CR_OK) {
  2168. continue;
  2169. } else {
  2170. break;
  2171. }
  2172. }
  2173. } else if (token && token->type == MEDIA_SYM_TK) {
  2174. status = cr_tknzr_unget_token
  2175. (PRIVATE (a_this)->tknzr, token);
  2176. CHECK_PARSING_STATUS (status, TRUE);
  2177. token = NULL;
  2178. status = cr_parser_parse_media (a_this);
  2179. if (status == CR_OK) {
  2180. continue;
  2181. } else {
  2182. if (PRIVATE (a_this)->sac_handler
  2183. && PRIVATE (a_this)->sac_handler->error) {
  2184. /* changed by iago rubio to track line error numbers */
  2185. CRParserError* err;
  2186. if( PRIVATE (a_this)->err_stack == NULL ){
  2187. cr_parser_push_error (a_this,
  2188. "syntax error",
  2189. status) ;
  2190. }
  2191. err = (CRParserError*) PRIVATE (a_this)->err_stack->data;
  2192. PRIVATE (a_this)->sac_handler->
  2193. error(PRIVATE(a_this)->sac_handler, err->line ) ;
  2194. /* end */
  2195. }
  2196. status = cr_parser_parse_atrule_core (a_this);
  2197. if (status == CR_OK) {
  2198. continue;
  2199. } else {
  2200. break;
  2201. }
  2202. }
  2203. } else if (token && token->type == PAGE_SYM_TK) {
  2204. status = cr_tknzr_unget_token
  2205. (PRIVATE (a_this)->tknzr, token);
  2206. CHECK_PARSING_STATUS (status, TRUE);
  2207. token = NULL;
  2208. status = cr_parser_parse_page (a_this);
  2209. if (status == CR_OK) {
  2210. continue;
  2211. } else {
  2212. if (PRIVATE (a_this)->sac_handler
  2213. && PRIVATE (a_this)->sac_handler->error) {
  2214. /* changed by iago rubio to track line error numbers */
  2215. CRParserError* err;
  2216. if( PRIVATE (a_this)->err_stack == NULL ){
  2217. cr_parser_push_error (a_this,
  2218. "syntax error",
  2219. status) ;
  2220. }
  2221. err = (CRParserError*) PRIVATE (a_this)->err_stack->data;
  2222. PRIVATE (a_this)->sac_handler->
  2223. error(PRIVATE(a_this)->sac_handler, err->line ) ;
  2224. /* end */
  2225. }
  2226. status = cr_parser_parse_atrule_core (a_this);
  2227. if (status == CR_OK) {
  2228. continue;
  2229. } else {
  2230. break;
  2231. }
  2232. }
  2233. } else if (token && token->type == FONT_FACE_SYM_TK) {
  2234. status = cr_tknzr_unget_token
  2235. (PRIVATE (a_this)->tknzr, token);
  2236. CHECK_PARSING_STATUS (status, TRUE);
  2237. token = NULL;
  2238. status = cr_parser_parse_font_face (a_this);
  2239. if (status == CR_OK) {
  2240. continue;
  2241. } else {
  2242. if (PRIVATE (a_this)->sac_handler
  2243. && PRIVATE (a_this)->sac_handler->error) {
  2244. /* changed by iago rubio to track line error numbers */
  2245. CRParserError* err;
  2246. if( PRIVATE (a_this)->err_stack == NULL ){
  2247. cr_parser_push_error (a_this,
  2248. "syntax error",
  2249. status) ;
  2250. }
  2251. err = (CRParserError*) PRIVATE (a_this)->err_stack->data;
  2252. PRIVATE (a_this)->sac_handler->
  2253. error(PRIVATE(a_this)->sac_handler, err->line ) ;
  2254. /* end */
  2255. }
  2256. status = cr_parser_parse_atrule_core (a_this);
  2257. if (status == CR_OK) {
  2258. continue;
  2259. } else {
  2260. break;
  2261. }
  2262. }
  2263. } else {
  2264. status = cr_tknzr_unget_token
  2265. (PRIVATE (a_this)->tknzr, token);
  2266. CHECK_PARSING_STATUS (status, TRUE);
  2267. token = NULL;
  2268. status = cr_parser_parse_statement_core (a_this);
  2269. if (status == CR_OK) {
  2270. continue;
  2271. } else {
  2272. break;
  2273. }
  2274. }
  2275. }
  2276. done:
  2277. if (token) {
  2278. cr_token_destroy (token);
  2279. token = NULL;
  2280. }
  2281. if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) {
  2282. if (PRIVATE (a_this)->sac_handler
  2283. && PRIVATE (a_this)->sac_handler->end_document) {
  2284. PRIVATE (a_this)->sac_handler->end_document
  2285. (PRIVATE (a_this)->sac_handler);
  2286. }
  2287. return CR_OK;
  2288. }
  2289. cr_parser_push_error
  2290. (a_this, "could not recognize next production", CR_ERROR);
  2291. if (PRIVATE (a_this)->sac_handler
  2292. && PRIVATE (a_this)->sac_handler->unrecoverable_error) {
  2293. PRIVATE (a_this)->sac_handler->
  2294. unrecoverable_error (PRIVATE (a_this)->sac_handler);
  2295. }
  2296. //cr_parser_dump_err_stack (a_this, TRUE);
  2297. return status;
  2298. error:
  2299. if (token) {
  2300. cr_token_destroy (token);
  2301. token = NULL;
  2302. }
  2303. if (PRIVATE (a_this)->sac_handler
  2304. && PRIVATE (a_this)->sac_handler->unrecoverable_error) {
  2305. PRIVATE (a_this)->sac_handler->
  2306. unrecoverable_error (PRIVATE (a_this)->sac_handler);
  2307. }
  2308. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  2309. return status;
  2310. }
  2311. /****************************************
  2312. *Public CRParser Methods
  2313. ****************************************/
  2314. /**
  2315. *Creates a new parser to parse data
  2316. *coming the input stream given in parameter.
  2317. *@param a_input the input stream of the parser.
  2318. *Note that the newly created parser will ref
  2319. *a_input and unref it when parsing reaches the
  2320. *end of the input stream.
  2321. *@return the newly created instance of #CRParser,
  2322. *or NULL if an error occured.
  2323. */
  2324. CRParser *
  2325. cr_parser_new (CRTknzr * a_tknzr)
  2326. {
  2327. CRParser *result = NULL;
  2328. enum CRStatus status = CR_OK;
  2329. result = g_malloc0 (sizeof (CRParser));
  2330. PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv));
  2331. if (a_tknzr) {
  2332. status = cr_parser_set_tknzr (result, a_tknzr);
  2333. }
  2334. g_return_val_if_fail (status == CR_OK, NULL);
  2335. return result;
  2336. }
  2337. /**
  2338. *Instanciates a new parser from a memory buffer.
  2339. *@param a_buf the buffer to parse.
  2340. *@param a_len the length of the data in the buffer.
  2341. *@param a_enc the encoding of the input buffer a_buf.
  2342. *@param a_free_buf if set to TRUE, a_buf will be freed
  2343. *during the destruction of the newly built instance
  2344. *of #CRParser. If set to FALSE, it is up to the caller to
  2345. *eventually free it.
  2346. *@return the newly built parser, or NULL if an error arises.
  2347. */
  2348. CRParser *
  2349. cr_parser_new_from_buf (guchar * a_buf,
  2350. gulong a_len,
  2351. enum CREncoding a_enc,
  2352. gboolean a_free_buf)
  2353. {
  2354. CRParser *result = NULL;
  2355. CRInput *input = NULL;
  2356. g_return_val_if_fail (a_buf && a_len, NULL);
  2357. input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf);
  2358. g_return_val_if_fail (input, NULL);
  2359. result = cr_parser_new_from_input (input);
  2360. if (!result) {
  2361. cr_input_destroy (input);
  2362. input = NULL;
  2363. return NULL;
  2364. }
  2365. return result;
  2366. }
  2367. CRParser *
  2368. cr_parser_new_from_input (CRInput * a_input)
  2369. {
  2370. CRParser *result = NULL;
  2371. CRTknzr *tokenizer = NULL;
  2372. if (a_input) {
  2373. tokenizer = cr_tknzr_new (a_input);
  2374. g_return_val_if_fail (tokenizer, NULL);
  2375. }
  2376. result = cr_parser_new (tokenizer);
  2377. g_return_val_if_fail (result, NULL);
  2378. return result;
  2379. }
  2380. CRParser *
  2381. cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc)
  2382. {
  2383. CRParser *result = NULL;
  2384. CRTknzr *tokenizer = NULL;
  2385. tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc);
  2386. if (!tokenizer) {
  2387. cr_utils_trace_info ("Could not open input file");
  2388. return NULL;
  2389. }
  2390. result = cr_parser_new (tokenizer);
  2391. g_return_val_if_fail (result, NULL);
  2392. return result;
  2393. }
  2394. /**
  2395. *Sets a SAC document handler to the parser.
  2396. *@param a_this the "this pointer" of the current instance of #CRParser.
  2397. *@param a_handler the handler to set.
  2398. *@return CR_OK upon successfull completion, an error code otherwise.
  2399. */
  2400. enum CRStatus
  2401. cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler)
  2402. {
  2403. g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
  2404. if (PRIVATE (a_this)->sac_handler) {
  2405. cr_doc_handler_unref (PRIVATE (a_this)->sac_handler);
  2406. }
  2407. PRIVATE (a_this)->sac_handler = a_handler;
  2408. cr_doc_handler_ref (a_handler);
  2409. return CR_OK;
  2410. }
  2411. /**
  2412. *Gets the SAC document handler.
  2413. *@param a_this the "this pointer" of the current instance of
  2414. *#CRParser.
  2415. *@param a_handler out parameter. The returned handler.
  2416. *@return CR_OK upon successfull completion, an error code
  2417. *otherwise.
  2418. */
  2419. enum CRStatus
  2420. cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler)
  2421. {
  2422. g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
  2423. *a_handler = PRIVATE (a_this)->sac_handler;
  2424. return CR_OK;
  2425. }
  2426. /**
  2427. *Sets the SAC handler associated to the current instance
  2428. *of #CRParser to the default SAC handler.
  2429. *@param a_this a pointer to the current instance of #CRParser.
  2430. *@return CR_OK upon successfull completion, an error code otherwise.
  2431. */
  2432. enum CRStatus
  2433. cr_parser_set_default_sac_handler (CRParser * a_this)
  2434. {
  2435. CRDocHandler *default_sac_handler = NULL;
  2436. enum CRStatus status = CR_ERROR;
  2437. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  2438. default_sac_handler = cr_doc_handler_new ();
  2439. cr_doc_handler_set_default_sac_handler (default_sac_handler);
  2440. status = cr_parser_set_sac_handler (a_this, default_sac_handler);
  2441. if (status != CR_OK) {
  2442. cr_doc_handler_destroy (default_sac_handler);
  2443. default_sac_handler = NULL;
  2444. }
  2445. return status;
  2446. }
  2447. enum CRStatus
  2448. cr_parser_set_use_core_grammar (CRParser * a_this,
  2449. gboolean a_use_core_grammar)
  2450. {
  2451. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  2452. PRIVATE (a_this)->use_core_grammar = a_use_core_grammar;
  2453. return CR_OK;
  2454. }
  2455. enum CRStatus
  2456. cr_parser_get_use_core_grammar (CRParser * a_this,
  2457. gboolean * a_use_core_grammar)
  2458. {
  2459. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  2460. *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar;
  2461. return CR_OK;
  2462. }
  2463. /**
  2464. *Parses a the given in parameter.
  2465. *@param a_this a pointer to the current instance of #CRParser.
  2466. *@param a_file_uri the uri to the file to load. For the time being,
  2467. *only local files are supported.
  2468. *@return CR_OK upon successfull completion, an error code otherwise.
  2469. */
  2470. enum CRStatus
  2471. cr_parser_parse_file (CRParser * a_this,
  2472. const guchar * a_file_uri, enum CREncoding a_enc)
  2473. {
  2474. enum CRStatus status = CR_ERROR;
  2475. CRTknzr *tknzr = NULL;
  2476. g_return_val_if_fail (a_this && PRIVATE (a_this)
  2477. && a_file_uri, CR_BAD_PARAM_ERROR);
  2478. tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc);
  2479. g_return_val_if_fail (tknzr != NULL, CR_ERROR);
  2480. status = cr_parser_set_tknzr (a_this, tknzr);
  2481. g_return_val_if_fail (status == CR_OK, CR_ERROR);
  2482. status = cr_parser_parse (a_this);
  2483. return status;
  2484. }
  2485. /**
  2486. *Parses an expression as defined by the css2 spec in appendix
  2487. *D.1:
  2488. *expr: term [ operator term ]*
  2489. */
  2490. enum CRStatus
  2491. cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr)
  2492. {
  2493. enum CRStatus status = CR_ERROR;
  2494. CRInputPos init_pos;
  2495. CRTerm *expr = NULL,
  2496. *expr2 = NULL;
  2497. guchar next_byte = 0;
  2498. gulong nb_terms = 0;
  2499. g_return_val_if_fail (a_this && PRIVATE (a_this)
  2500. && a_expr, CR_BAD_PARAM_ERROR);
  2501. RECORD_INITIAL_POS (a_this, &init_pos);
  2502. status = cr_parser_parse_term (a_this, &expr);
  2503. CHECK_PARSING_STATUS (status, FALSE);
  2504. for (;;) {
  2505. guchar operator = 0;
  2506. status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr,
  2507. 1, &next_byte);
  2508. if (status != CR_OK) {
  2509. if (status == CR_END_OF_INPUT_ERROR) {
  2510. /*
  2511. if (!nb_terms)
  2512. {
  2513. goto error ;
  2514. }
  2515. */
  2516. status = CR_OK;
  2517. break;
  2518. } else {
  2519. goto error;
  2520. }
  2521. }
  2522. if (next_byte == '/' || next_byte == ',') {
  2523. READ_NEXT_BYTE (a_this, &operator);
  2524. }
  2525. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2526. status = cr_parser_parse_term (a_this, &expr2);
  2527. if (status != CR_OK || expr2 == NULL) {
  2528. status = CR_OK;
  2529. break;
  2530. }
  2531. switch (operator) {
  2532. case '/':
  2533. expr2->the_operator = DIVIDE;
  2534. break;
  2535. case ',':
  2536. expr2->the_operator = COMMA;
  2537. default:
  2538. break;
  2539. }
  2540. expr = cr_term_append_term (expr, expr2);
  2541. expr2 = NULL;
  2542. operator = 0;
  2543. nb_terms++;
  2544. }
  2545. if (status == CR_OK) {
  2546. *a_expr = cr_term_append_term (*a_expr, expr);
  2547. expr = NULL;
  2548. cr_parser_clear_errors (a_this);
  2549. return CR_OK;
  2550. }
  2551. error:
  2552. if (expr) {
  2553. cr_term_destroy (expr);
  2554. expr = NULL;
  2555. }
  2556. if (expr2) {
  2557. cr_term_destroy (expr2);
  2558. expr2 = NULL;
  2559. }
  2560. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  2561. return status;
  2562. }
  2563. /**
  2564. *Parses a declaration priority as defined by
  2565. *the css2 grammar in appendix C:
  2566. *prio: IMPORTANT_SYM S*
  2567. *@param a_this the current instance of #CRParser.
  2568. *@param a_prio a string representing the priority.
  2569. *Today, only "!important" is returned as only this
  2570. *priority is defined by css2.
  2571. */
  2572. enum CRStatus
  2573. cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio)
  2574. {
  2575. enum CRStatus status = CR_ERROR;
  2576. CRInputPos init_pos;
  2577. CRToken *token = NULL;
  2578. g_return_val_if_fail (a_this && PRIVATE (a_this)
  2579. && a_prio
  2580. && *a_prio == NULL, CR_BAD_PARAM_ERROR);
  2581. RECORD_INITIAL_POS (a_this, &init_pos);
  2582. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  2583. if (status == CR_END_OF_INPUT_ERROR) {
  2584. goto error;
  2585. }
  2586. ENSURE_PARSING_COND (status == CR_OK
  2587. && token && token->type == IMPORTANT_SYM_TK);
  2588. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2589. *a_prio = cr_string_new_from_string ("!important");
  2590. cr_token_destroy (token);
  2591. token = NULL;
  2592. return CR_OK;
  2593. error:
  2594. if (token) {
  2595. cr_token_destroy (token);
  2596. token = NULL;
  2597. }
  2598. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  2599. return status;
  2600. }
  2601. /**
  2602. *TODO: return the parsed priority, so that
  2603. *upper layers can take benefit from it.
  2604. *Parses a "declaration" as defined by the css2 spec in appendix D.1:
  2605. *declaration ::= [property ':' S* expr prio?]?
  2606. *
  2607. *@param a_this the "this pointer" of the current instance of #CRParser.
  2608. *@param a_property the successfully parsed property. The caller
  2609. * *must* free the returned pointer.
  2610. *@param a_expr the expression that represents the attribute value.
  2611. *The caller *must* free the returned pointer.
  2612. *@return CR_OK upon successfull completion, an error code otherwise.
  2613. */
  2614. enum CRStatus
  2615. cr_parser_parse_declaration (CRParser * a_this,
  2616. CRString ** a_property,
  2617. CRTerm ** a_expr, gboolean * a_important)
  2618. {
  2619. enum CRStatus status = CR_ERROR;
  2620. CRInputPos init_pos;
  2621. guint32 cur_char = 0;
  2622. CRTerm *expr = NULL;
  2623. CRString *prio = NULL;
  2624. g_return_val_if_fail (a_this && PRIVATE (a_this)
  2625. && a_property && a_expr
  2626. && a_important, CR_BAD_PARAM_ERROR);
  2627. RECORD_INITIAL_POS (a_this, &init_pos);
  2628. status = cr_parser_parse_property (a_this, a_property);
  2629. if (status == CR_END_OF_INPUT_ERROR)
  2630. goto error;
  2631. CHECK_PARSING_STATUS_ERR
  2632. (a_this, status, FALSE,
  2633. "while parsing declaration: next property is malformed",
  2634. CR_SYNTAX_ERROR);
  2635. READ_NEXT_CHAR (a_this, &cur_char);
  2636. if (cur_char != ':') {
  2637. status = CR_PARSING_ERROR;
  2638. cr_parser_push_error
  2639. (a_this,
  2640. "while parsing declaration: this char must be ':'",
  2641. CR_SYNTAX_ERROR);
  2642. goto error;
  2643. }
  2644. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2645. status = cr_parser_parse_expr (a_this, &expr);
  2646. CHECK_PARSING_STATUS_ERR
  2647. (a_this, status, FALSE,
  2648. "while parsing declaration: next expression is malformed",
  2649. CR_SYNTAX_ERROR);
  2650. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2651. status = cr_parser_parse_prio (a_this, &prio);
  2652. if (prio) {
  2653. cr_string_destroy (prio);
  2654. prio = NULL;
  2655. *a_important = TRUE;
  2656. } else {
  2657. *a_important = FALSE;
  2658. }
  2659. if (*a_expr) {
  2660. cr_term_append_term (*a_expr, expr);
  2661. expr = NULL;
  2662. } else {
  2663. *a_expr = expr;
  2664. expr = NULL;
  2665. }
  2666. cr_parser_clear_errors (a_this);
  2667. return CR_OK;
  2668. error:
  2669. if (expr) {
  2670. cr_term_destroy (expr);
  2671. expr = NULL;
  2672. }
  2673. if (*a_property) {
  2674. cr_string_destroy (*a_property);
  2675. *a_property = NULL;
  2676. }
  2677. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  2678. return status;
  2679. }
  2680. /**
  2681. *Parses a statement as defined by the css core grammar in
  2682. *chapter 4.1 of the css2 spec.
  2683. *statement : ruleset | at-rule;
  2684. *@param a_this the current instance of #CRParser.
  2685. *@return CR_OK upon successfull completion, an error code otherwise.
  2686. */
  2687. enum CRStatus
  2688. cr_parser_parse_statement_core (CRParser * a_this)
  2689. {
  2690. CRToken *token = NULL;
  2691. CRInputPos init_pos;
  2692. enum CRStatus status = CR_ERROR;
  2693. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  2694. RECORD_INITIAL_POS (a_this, &init_pos);
  2695. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  2696. ENSURE_PARSING_COND (status == CR_OK && token);
  2697. switch (token->type) {
  2698. case ATKEYWORD_TK:
  2699. case IMPORT_SYM_TK:
  2700. case PAGE_SYM_TK:
  2701. case MEDIA_SYM_TK:
  2702. case FONT_FACE_SYM_TK:
  2703. case CHARSET_SYM_TK:
  2704. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  2705. token = NULL;
  2706. status = cr_parser_parse_atrule_core (a_this);
  2707. CHECK_PARSING_STATUS (status, TRUE);
  2708. break;
  2709. default:
  2710. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  2711. token = NULL;
  2712. status = cr_parser_parse_ruleset_core (a_this);
  2713. cr_parser_clear_errors (a_this);
  2714. CHECK_PARSING_STATUS (status, TRUE);
  2715. }
  2716. return CR_OK;
  2717. error:
  2718. if (token) {
  2719. cr_token_destroy (token);
  2720. token = NULL;
  2721. }
  2722. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  2723. return status;
  2724. }
  2725. /**
  2726. *Parses a "ruleset" as defined in the css2 spec at appendix D.1.
  2727. *ruleset ::= selector [ ',' S* selector ]*
  2728. *'{' S* declaration? [ ';' S* declaration? ]* '}' S*;
  2729. *
  2730. *This methods calls the the SAC handler on the relevant SAC handler
  2731. *callbacks whenever it encounters some specific constructions.
  2732. *See the documentation of #CRDocHandler (the SAC handler) to know
  2733. *when which SAC handler is called.
  2734. *@param a_this the "this pointer" of the current instance of #CRParser.
  2735. *@return CR_OK upon successfull completion, an error code otherwise.
  2736. */
  2737. enum CRStatus
  2738. cr_parser_parse_ruleset (CRParser * a_this)
  2739. {
  2740. enum CRStatus status = CR_OK;
  2741. CRInputPos init_pos;
  2742. guint32 cur_char = 0,
  2743. next_char = 0;
  2744. CRString *property = NULL;
  2745. CRTerm *expr = NULL;
  2746. CRSimpleSel *simple_sels = NULL;
  2747. CRSelector *selector = NULL;
  2748. gboolean start_selector = FALSE,
  2749. is_important = FALSE;
  2750. g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
  2751. RECORD_INITIAL_POS (a_this, &init_pos);
  2752. status = cr_parser_parse_selector (a_this, &selector);
  2753. CHECK_PARSING_STATUS (status, FALSE);
  2754. READ_NEXT_CHAR (a_this, &cur_char);
  2755. ENSURE_PARSING_COND_ERR
  2756. (a_this, cur_char == '{',
  2757. "while parsing rulset: current char should be '{'",
  2758. CR_SYNTAX_ERROR);
  2759. if (PRIVATE (a_this)->sac_handler
  2760. && PRIVATE (a_this)->sac_handler->start_selector) {
  2761. /*
  2762. *the selector is ref counted so that the parser's user
  2763. *can choose to keep it.
  2764. */
  2765. if (selector) {
  2766. cr_selector_ref (selector);
  2767. }
  2768. PRIVATE (a_this)->sac_handler->start_selector
  2769. (PRIVATE (a_this)->sac_handler, selector);
  2770. start_selector = TRUE;
  2771. }
  2772. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2773. PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE;
  2774. status = cr_parser_parse_declaration (a_this, &property,
  2775. &expr,
  2776. &is_important);
  2777. if (expr) {
  2778. cr_term_ref (expr);
  2779. }
  2780. if (status == CR_OK
  2781. && PRIVATE (a_this)->sac_handler
  2782. && PRIVATE (a_this)->sac_handler->property) {
  2783. PRIVATE (a_this)->sac_handler->property
  2784. (PRIVATE (a_this)->sac_handler, property, expr,
  2785. is_important);
  2786. }
  2787. if (status == CR_OK) {
  2788. /*
  2789. *free the allocated
  2790. *'property' and 'term' before parsing
  2791. *next declarations.
  2792. */
  2793. if (property) {
  2794. cr_string_destroy (property);
  2795. property = NULL;
  2796. }
  2797. if (expr) {
  2798. cr_term_unref (expr);
  2799. expr = NULL;
  2800. }
  2801. } else {/*status != CR_OK*/
  2802. guint32 c = 0 ;
  2803. /*
  2804. *test if we have reached '}', which
  2805. *would mean that we are parsing an empty ruleset (eg. x{ })
  2806. *In that case, goto end_of_ruleset.
  2807. */
  2808. status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ;
  2809. if (status == CR_OK && c == '}') {
  2810. status = CR_OK ;
  2811. goto end_of_ruleset ;
  2812. }
  2813. }
  2814. CHECK_PARSING_STATUS_ERR
  2815. (a_this, status, FALSE,
  2816. "while parsing ruleset: next construction should be a declaration",
  2817. CR_SYNTAX_ERROR);
  2818. for (;;) {
  2819. PEEK_NEXT_CHAR (a_this, &next_char);
  2820. if (next_char != ';')
  2821. break;
  2822. /*consume the ';' char */
  2823. READ_NEXT_CHAR (a_this, &cur_char);
  2824. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2825. status = cr_parser_parse_declaration (a_this, &property,
  2826. &expr, &is_important);
  2827. if (expr) {
  2828. cr_term_ref (expr);
  2829. }
  2830. if (status == CR_OK
  2831. && PRIVATE (a_this)->sac_handler
  2832. && PRIVATE (a_this)->sac_handler->property) {
  2833. PRIVATE (a_this)->sac_handler->property
  2834. (PRIVATE (a_this)->sac_handler,
  2835. property, expr, is_important);
  2836. }
  2837. if (property) {
  2838. cr_string_destroy (property);
  2839. property = NULL;
  2840. }
  2841. if (expr) {
  2842. cr_term_unref (expr);
  2843. expr = NULL;
  2844. }
  2845. }
  2846. end_of_ruleset:
  2847. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2848. READ_NEXT_CHAR (a_this, &cur_char);
  2849. ENSURE_PARSING_COND_ERR
  2850. (a_this, cur_char == '}',
  2851. "while parsing rulset: current char must be a '}'",
  2852. CR_SYNTAX_ERROR);
  2853. if (PRIVATE (a_this)->sac_handler
  2854. && PRIVATE (a_this)->sac_handler->end_selector) {
  2855. PRIVATE (a_this)->sac_handler->end_selector
  2856. (PRIVATE (a_this)->sac_handler, selector);
  2857. start_selector = FALSE;
  2858. }
  2859. if (expr) {
  2860. cr_term_unref (expr);
  2861. expr = NULL;
  2862. }
  2863. if (simple_sels) {
  2864. cr_simple_sel_destroy (simple_sels);
  2865. simple_sels = NULL;
  2866. }
  2867. if (selector) {
  2868. cr_selector_unref (selector);
  2869. selector = NULL;
  2870. }
  2871. cr_parser_clear_errors (a_this);
  2872. PRIVATE (a_this)->state = RULESET_PARSED_STATE;
  2873. return CR_OK;
  2874. error:
  2875. if (start_selector == TRUE
  2876. && PRIVATE (a_this)->sac_handler
  2877. && PRIVATE (a_this)->sac_handler->error) {
  2878. /* changed by iago rubio to track line error numbers */
  2879. CRParserError* err;
  2880. if( PRIVATE (a_this)->err_stack == NULL ){
  2881. cr_parser_push_error (a_this,
  2882. "syntax error",
  2883. status) ;
  2884. }
  2885. err = (CRParserError*) PRIVATE (a_this)->err_stack->data;
  2886. PRIVATE (a_this)->sac_handler->
  2887. error(PRIVATE(a_this)->sac_handler, err->line ) ;
  2888. /* end */
  2889. }
  2890. if (expr) {
  2891. cr_term_unref (expr);
  2892. expr = NULL;
  2893. }
  2894. if (simple_sels) {
  2895. cr_simple_sel_destroy (simple_sels);
  2896. simple_sels = NULL;
  2897. }
  2898. if (property) {
  2899. cr_string_destroy (property);
  2900. }
  2901. if (selector) {
  2902. cr_selector_unref (selector);
  2903. selector = NULL;
  2904. }
  2905. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  2906. return status;
  2907. }
  2908. /**
  2909. *Parses an 'import' declaration as defined in the css2 spec
  2910. *in appendix D.1:
  2911. *
  2912. *import ::=
  2913. *@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S*
  2914. *
  2915. *@param a_this the "this pointer" of the current instance
  2916. *of #CRParser.
  2917. *
  2918. *@param a_medium_list out parameter. A linked list of
  2919. *#CRString
  2920. *Each CRString is a string that contains
  2921. *a 'medium' declaration part of the successfully
  2922. *parsed 'import' declaration.
  2923. *
  2924. *@param a_import_string out parameter.
  2925. *A string that contains the 'import
  2926. *string". The import string can be either an uri (if it starts with
  2927. *the substring "uri(") or a any other css2 string. Note that
  2928. * *a_import_string must be initially set to NULL or else, this function
  2929. *will return CR_BAD_PARAM_ERROR.
  2930. *
  2931. *@return CR_OK upon sucessfull completion, an error code otherwise.
  2932. */
  2933. enum CRStatus
  2934. cr_parser_parse_import (CRParser * a_this,
  2935. GList ** a_media_list,
  2936. CRString ** a_import_string,
  2937. CRParsingLocation *a_location)
  2938. {
  2939. enum CRStatus status = CR_OK;
  2940. CRInputPos init_pos;
  2941. guint32 cur_char = 0,
  2942. next_char = 0;
  2943. CRString *medium = NULL;
  2944. g_return_val_if_fail (a_this
  2945. && a_import_string
  2946. && (*a_import_string == NULL),
  2947. CR_BAD_PARAM_ERROR);
  2948. RECORD_INITIAL_POS (a_this, &init_pos);
  2949. if (BYTE (a_this, 1, NULL) == '@'
  2950. && BYTE (a_this, 2, NULL) == 'i'
  2951. && BYTE (a_this, 3, NULL) == 'm'
  2952. && BYTE (a_this, 4, NULL) == 'p'
  2953. && BYTE (a_this, 5, NULL) == 'o'
  2954. && BYTE (a_this, 6, NULL) == 'r'
  2955. && BYTE (a_this, 7, NULL) == 't') {
  2956. SKIP_CHARS (a_this, 1);
  2957. if (a_location) {
  2958. cr_parser_get_parsing_location
  2959. (a_this, a_location) ;
  2960. }
  2961. SKIP_CHARS (a_this, 6);
  2962. status = CR_OK;
  2963. } else {
  2964. status = CR_PARSING_ERROR;
  2965. goto error;
  2966. }
  2967. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2968. PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE;
  2969. PEEK_NEXT_CHAR (a_this, &next_char);
  2970. if (next_char == '"' || next_char == '\'') {
  2971. status = cr_parser_parse_string (a_this, a_import_string);
  2972. CHECK_PARSING_STATUS (status, FALSE);
  2973. } else {
  2974. status = cr_parser_parse_uri (a_this, a_import_string);
  2975. CHECK_PARSING_STATUS (status, FALSE);
  2976. }
  2977. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2978. status = cr_parser_parse_ident (a_this, &medium);
  2979. if (status == CR_OK && medium) {
  2980. *a_media_list = g_list_append (*a_media_list, medium);
  2981. medium = NULL;
  2982. }
  2983. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2984. for (; status == CR_OK;) {
  2985. if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
  2986. &next_char)) != CR_OK) {
  2987. if (status == CR_END_OF_INPUT_ERROR) {
  2988. status = CR_OK;
  2989. goto okay;
  2990. }
  2991. goto error;
  2992. }
  2993. if (next_char == ',') {
  2994. READ_NEXT_CHAR (a_this, &cur_char);
  2995. } else {
  2996. break;
  2997. }
  2998. cr_parser_try_to_skip_spaces_and_comments (a_this);
  2999. status = cr_parser_parse_ident (a_this, &medium);
  3000. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3001. if ((status == CR_OK) && medium) {
  3002. *a_media_list = g_list_append (*a_media_list, medium);
  3003. medium = NULL;
  3004. }
  3005. CHECK_PARSING_STATUS (status, FALSE);
  3006. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3007. }
  3008. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3009. READ_NEXT_CHAR (a_this, &cur_char);
  3010. ENSURE_PARSING_COND (cur_char == ';');
  3011. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3012. okay:
  3013. cr_parser_clear_errors (a_this);
  3014. PRIVATE (a_this)->state = IMPORT_PARSED_STATE;
  3015. return CR_OK;
  3016. error:
  3017. if (*a_media_list) {
  3018. GList *cur = NULL;
  3019. /*
  3020. *free each element of *a_media_list.
  3021. *Note that each element of *a_medium list *must*
  3022. *be a GString* or else, the code that is coming next
  3023. *will corrupt the memory and lead to hard to debug
  3024. *random crashes.
  3025. *This is where C++ and its compile time
  3026. *type checking mecanism (through STL containers) would
  3027. *have prevented us to go through this hassle.
  3028. */
  3029. for (cur = *a_media_list; cur; cur = cur->next) {
  3030. if (cur->data) {
  3031. cr_string_destroy (cur->data);
  3032. }
  3033. }
  3034. g_list_free (*a_media_list);
  3035. *a_media_list = NULL;
  3036. }
  3037. if (*a_import_string) {
  3038. cr_string_destroy (*a_import_string);
  3039. *a_import_string = NULL;
  3040. }
  3041. if (medium) {
  3042. cr_string_destroy (medium);
  3043. medium = NULL;
  3044. }
  3045. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  3046. return status;
  3047. }
  3048. /**
  3049. *Parses a 'media' declaration as specified in the css2 spec at
  3050. *appendix D.1:
  3051. *
  3052. *media ::= @media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S*
  3053. *
  3054. *Note that this function calls the required sac handlers during the parsing
  3055. *to notify media productions. See #CRDocHandler to know the callback called
  3056. *during @media parsing.
  3057. *@param a_this the "this pointer" of the current instance of #CRParser.
  3058. *@return CR_OK upon successfull completion, an error code otherwise.
  3059. */
  3060. enum CRStatus
  3061. cr_parser_parse_media (CRParser * a_this)
  3062. {
  3063. enum CRStatus status = CR_OK;
  3064. CRInputPos init_pos;
  3065. CRToken *token = NULL;
  3066. guint32 next_char = 0,
  3067. cur_char = 0;
  3068. CRString *medium = NULL;
  3069. GList *media_list = NULL;
  3070. CRParsingLocation location = {0} ;
  3071. g_return_val_if_fail (a_this
  3072. && PRIVATE (a_this),
  3073. CR_BAD_PARAM_ERROR);
  3074. RECORD_INITIAL_POS (a_this, &init_pos);
  3075. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  3076. &token);
  3077. ENSURE_PARSING_COND (status == CR_OK
  3078. && token
  3079. && token->type == MEDIA_SYM_TK);
  3080. cr_parsing_location_copy (&location, &token->location) ;
  3081. cr_token_destroy (token);
  3082. token = NULL;
  3083. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3084. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3085. ENSURE_PARSING_COND (status == CR_OK
  3086. && token && token->type == IDENT_TK);
  3087. medium = token->u.str;
  3088. token->u.str = NULL;
  3089. cr_token_destroy (token);
  3090. token = NULL;
  3091. if (medium) {
  3092. media_list = g_list_append (media_list, medium);
  3093. medium = NULL;
  3094. }
  3095. for (; status == CR_OK;) {
  3096. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3097. PEEK_NEXT_CHAR (a_this, &next_char);
  3098. if (next_char == ',') {
  3099. READ_NEXT_CHAR (a_this, &cur_char);
  3100. } else {
  3101. break;
  3102. }
  3103. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3104. status = cr_parser_parse_ident (a_this, &medium);
  3105. CHECK_PARSING_STATUS (status, FALSE);
  3106. if (medium) {
  3107. media_list = g_list_append (media_list, medium);
  3108. medium = NULL;
  3109. }
  3110. }
  3111. READ_NEXT_CHAR (a_this, &cur_char);
  3112. ENSURE_PARSING_COND (cur_char == '{');
  3113. /*
  3114. *call the SAC handler api here.
  3115. */
  3116. if (PRIVATE (a_this)->sac_handler
  3117. && PRIVATE (a_this)->sac_handler->start_media) {
  3118. PRIVATE (a_this)->sac_handler->start_media
  3119. (PRIVATE (a_this)->sac_handler, media_list,
  3120. &location);
  3121. }
  3122. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3123. PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE;
  3124. for (; status == CR_OK;) {
  3125. status = cr_parser_parse_ruleset (a_this);
  3126. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3127. }
  3128. READ_NEXT_CHAR (a_this, &cur_char);
  3129. ENSURE_PARSING_COND (cur_char == '}');
  3130. /*
  3131. *call the right SAC handler api here.
  3132. */
  3133. if (PRIVATE (a_this)->sac_handler
  3134. && PRIVATE (a_this)->sac_handler->end_media) {
  3135. PRIVATE (a_this)->sac_handler->end_media
  3136. (PRIVATE (a_this)->sac_handler, media_list);
  3137. }
  3138. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3139. /*
  3140. *Then, free the data structures passed to
  3141. *the last call to the SAC handler.
  3142. */
  3143. if (medium) {
  3144. cr_string_destroy (medium);
  3145. medium = NULL;
  3146. }
  3147. if (media_list) {
  3148. GList *cur = NULL;
  3149. for (cur = media_list; cur; cur = cur->next) {
  3150. cr_string_destroy (cur->data);
  3151. }
  3152. g_list_free (media_list);
  3153. media_list = NULL;
  3154. }
  3155. cr_parser_clear_errors (a_this);
  3156. PRIVATE (a_this)->state = MEDIA_PARSED_STATE;
  3157. return CR_OK;
  3158. error:
  3159. if (token) {
  3160. cr_token_destroy (token);
  3161. token = NULL;
  3162. }
  3163. if (medium) {
  3164. cr_string_destroy (medium);
  3165. medium = NULL;
  3166. }
  3167. if (media_list) {
  3168. GList *cur = NULL;
  3169. for (cur = media_list; cur; cur = cur->next) {
  3170. cr_string_destroy (cur->data);
  3171. }
  3172. g_list_free (media_list);
  3173. media_list = NULL;
  3174. }
  3175. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  3176. return status;
  3177. }
  3178. /**
  3179. *Parses '@page' rule as specified in the css2 spec in appendix D.1:
  3180. *page ::= PAGE_SYM S* IDENT? pseudo_page? S*
  3181. *'{' S* declaration [ ';' S* declaration ]* '}' S*
  3182. *
  3183. *This function also calls the relevant SAC handlers whenever it
  3184. *encounters a construction that must
  3185. *be reported to the calling application.
  3186. *@param a_this the "this pointer" of the current instance of #CRParser.
  3187. *@return CR_OK upon successfull completion, an error code otherwise.
  3188. */
  3189. enum CRStatus
  3190. cr_parser_parse_page (CRParser * a_this)
  3191. {
  3192. enum CRStatus status = CR_OK;
  3193. CRInputPos init_pos;
  3194. CRToken *token = NULL;
  3195. CRTerm *css_expression = NULL;
  3196. CRString *page_selector = NULL,
  3197. *page_pseudo_class = NULL,
  3198. *property = NULL;
  3199. gboolean important = TRUE;
  3200. CRParsingLocation location = {0} ;
  3201. g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
  3202. RECORD_INITIAL_POS (a_this, &init_pos);
  3203. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  3204. &token) ;
  3205. ENSURE_PARSING_COND (status == CR_OK
  3206. && token
  3207. && token->type == PAGE_SYM_TK);
  3208. cr_parsing_location_copy (&location, &token->location) ;
  3209. cr_token_destroy (token);
  3210. token = NULL;
  3211. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3212. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3213. ENSURE_PARSING_COND (status == CR_OK && token);
  3214. if (token->type == IDENT_TK) {
  3215. page_selector = token->u.str;
  3216. token->u.str = NULL;
  3217. cr_token_destroy (token);
  3218. token = NULL;
  3219. } else {
  3220. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  3221. token = NULL;
  3222. }
  3223. /*
  3224. *try to parse pseudo_page
  3225. */
  3226. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3227. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3228. ENSURE_PARSING_COND (status == CR_OK && token);
  3229. if (token->type == DELIM_TK && token->u.unichar == ':') {
  3230. cr_token_destroy (token);
  3231. token = NULL;
  3232. status = cr_parser_parse_ident (a_this, &page_pseudo_class);
  3233. CHECK_PARSING_STATUS (status, FALSE);
  3234. } else {
  3235. cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
  3236. token = NULL;
  3237. }
  3238. /*
  3239. *parse_block
  3240. *
  3241. */
  3242. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3243. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3244. ENSURE_PARSING_COND (status == CR_OK && token
  3245. && token->type == CBO_TK);
  3246. cr_token_destroy (token);
  3247. token = NULL;
  3248. /*
  3249. *Call the appropriate SAC handler here.
  3250. */
  3251. if (PRIVATE (a_this)->sac_handler
  3252. && PRIVATE (a_this)->sac_handler->start_page) {
  3253. PRIVATE (a_this)->sac_handler->start_page
  3254. (PRIVATE (a_this)->sac_handler,
  3255. page_selector, page_pseudo_class,
  3256. &location);
  3257. }
  3258. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3259. PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE;
  3260. status = cr_parser_parse_declaration (a_this, &property,
  3261. &css_expression,
  3262. &important);
  3263. ENSURE_PARSING_COND (status == CR_OK);
  3264. /*
  3265. *call the relevant SAC handler here...
  3266. */
  3267. if (PRIVATE (a_this)->sac_handler
  3268. && PRIVATE (a_this)->sac_handler->property) {
  3269. if (css_expression)
  3270. cr_term_ref (css_expression);
  3271. PRIVATE (a_this)->sac_handler->property
  3272. (PRIVATE (a_this)->sac_handler,
  3273. property, css_expression, important);
  3274. }
  3275. /*
  3276. *... and free the data structure passed to that last
  3277. *SAC handler.
  3278. */
  3279. if (property) {
  3280. cr_string_destroy (property);
  3281. property = NULL;
  3282. }
  3283. if (css_expression) {
  3284. cr_term_unref (css_expression);
  3285. css_expression = NULL;
  3286. }
  3287. for (;;) {
  3288. /*parse the other ';' separated declarations */
  3289. if (token) {
  3290. cr_token_destroy (token);
  3291. token = NULL;
  3292. }
  3293. status = cr_tknzr_get_next_token
  3294. (PRIVATE (a_this)->tknzr, &token);
  3295. ENSURE_PARSING_COND (status == CR_OK && token);
  3296. if (token->type != SEMICOLON_TK) {
  3297. cr_tknzr_unget_token
  3298. (PRIVATE (a_this)->tknzr,
  3299. token);
  3300. token = NULL ;
  3301. break;
  3302. }
  3303. cr_token_destroy (token);
  3304. token = NULL;
  3305. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3306. status = cr_parser_parse_declaration (a_this, &property,
  3307. &css_expression,
  3308. &important);
  3309. if (status != CR_OK)
  3310. break ;
  3311. /*
  3312. *call the relevant SAC handler here...
  3313. */
  3314. if (PRIVATE (a_this)->sac_handler
  3315. && PRIVATE (a_this)->sac_handler->property) {
  3316. cr_term_ref (css_expression);
  3317. PRIVATE (a_this)->sac_handler->property
  3318. (PRIVATE (a_this)->sac_handler,
  3319. property, css_expression, important);
  3320. }
  3321. /*
  3322. *... and free the data structure passed to that last
  3323. *SAC handler.
  3324. */
  3325. if (property) {
  3326. cr_string_destroy (property);
  3327. property = NULL;
  3328. }
  3329. if (css_expression) {
  3330. cr_term_unref (css_expression);
  3331. css_expression = NULL;
  3332. }
  3333. }
  3334. cr_parser_try_to_skip_spaces_and_comments
  3335. (a_this) ;
  3336. if (token) {
  3337. cr_token_destroy (token) ;
  3338. token = NULL ;
  3339. }
  3340. status = cr_tknzr_get_next_token
  3341. (PRIVATE (a_this)->tknzr, &token);
  3342. ENSURE_PARSING_COND (status == CR_OK
  3343. && token
  3344. && token->type == CBC_TK) ;
  3345. cr_token_destroy (token) ;
  3346. token = NULL ;
  3347. /*
  3348. *call the relevant SAC handler here.
  3349. */
  3350. if (PRIVATE (a_this)->sac_handler
  3351. && PRIVATE (a_this)->sac_handler->end_page) {
  3352. PRIVATE (a_this)->sac_handler->end_page
  3353. (PRIVATE (a_this)->sac_handler,
  3354. page_selector, page_pseudo_class);
  3355. }
  3356. if (page_selector) {
  3357. cr_string_destroy (page_selector);
  3358. page_selector = NULL;
  3359. }
  3360. if (page_pseudo_class) {
  3361. cr_string_destroy (page_pseudo_class);
  3362. page_pseudo_class = NULL;
  3363. }
  3364. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3365. /*here goes the former implem of this function ... */
  3366. cr_parser_clear_errors (a_this);
  3367. PRIVATE (a_this)->state = PAGE_PARSED_STATE;
  3368. return CR_OK;
  3369. error:
  3370. if (token) {
  3371. cr_token_destroy (token);
  3372. token = NULL;
  3373. }
  3374. if (page_selector) {
  3375. cr_string_destroy (page_selector);
  3376. page_selector = NULL;
  3377. }
  3378. if (page_pseudo_class) {
  3379. cr_string_destroy (page_pseudo_class);
  3380. page_pseudo_class = NULL;
  3381. }
  3382. if (property) {
  3383. cr_string_destroy (property);
  3384. property = NULL;
  3385. }
  3386. if (css_expression) {
  3387. cr_term_destroy (css_expression);
  3388. css_expression = NULL;
  3389. }
  3390. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  3391. return status;
  3392. }
  3393. /**
  3394. *Parses a charset declaration as defined implictly by the css2 spec in
  3395. *appendix D.1:
  3396. *charset ::= CHARSET_SYM S* STRING S* ';'
  3397. *
  3398. *@param a_this the "this pointer" of the current instance of #CRParser.
  3399. *@param a_value out parameter. The actual parsed value of the charset
  3400. *declararation. Note that for safety check reasons, *a_value must be
  3401. *set to NULL.
  3402. *@param a_charset_sym_location the parsing location of
  3403. *@return CR_OK upon successfull completion, an error code otherwise.
  3404. */
  3405. enum CRStatus
  3406. cr_parser_parse_charset (CRParser * a_this, CRString ** a_value,
  3407. CRParsingLocation *a_charset_sym_location)
  3408. {
  3409. enum CRStatus status = CR_OK;
  3410. CRInputPos init_pos;
  3411. CRToken *token = NULL;
  3412. CRString *charset_str = NULL;
  3413. g_return_val_if_fail (a_this && a_value
  3414. && (*a_value == NULL),
  3415. CR_BAD_PARAM_ERROR);
  3416. RECORD_INITIAL_POS (a_this, &init_pos);
  3417. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3418. ENSURE_PARSING_COND (status == CR_OK
  3419. && token && token->type == CHARSET_SYM_TK);
  3420. if (a_charset_sym_location) {
  3421. cr_parsing_location_copy (a_charset_sym_location,
  3422. &token->location) ;
  3423. }
  3424. cr_token_destroy (token);
  3425. token = NULL;
  3426. PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE;
  3427. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3428. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3429. ENSURE_PARSING_COND (status == CR_OK
  3430. && token && token->type == STRING_TK);
  3431. charset_str = token->u.str;
  3432. token->u.str = NULL;
  3433. cr_token_destroy (token);
  3434. token = NULL;
  3435. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3436. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3437. ENSURE_PARSING_COND (status == CR_OK
  3438. && token && token->type == SEMICOLON_TK);
  3439. cr_token_destroy (token);
  3440. token = NULL;
  3441. if (charset_str) {
  3442. *a_value = charset_str;
  3443. charset_str = NULL;
  3444. }
  3445. PRIVATE (a_this)->state = CHARSET_PARSED_STATE;
  3446. return CR_OK;
  3447. error:
  3448. if (token) {
  3449. cr_token_destroy (token);
  3450. token = NULL;
  3451. }
  3452. if (*a_value) {
  3453. cr_string_destroy (*a_value);
  3454. *a_value = NULL;
  3455. }
  3456. if (charset_str) {
  3457. cr_string_destroy (charset_str);
  3458. charset_str = NULL;
  3459. }
  3460. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  3461. return status;
  3462. }
  3463. /**
  3464. *Parses the "@font-face" rule specified in the css1 spec in
  3465. *appendix D.1:
  3466. *
  3467. *font_face ::= FONT_FACE_SYM S*
  3468. *'{' S* declaration [ ';' S* declaration ]* '}' S*
  3469. *
  3470. *This function will call SAC handlers whenever it is necessary.
  3471. *@return CR_OK upon successfull completion, an error code otherwise.
  3472. */
  3473. enum CRStatus
  3474. cr_parser_parse_font_face (CRParser * a_this)
  3475. {
  3476. enum CRStatus status = CR_ERROR;
  3477. CRInputPos init_pos;
  3478. CRString *property = NULL;
  3479. CRTerm *css_expression = NULL;
  3480. CRToken *token = NULL;
  3481. gboolean important = FALSE;
  3482. guint32 next_char = 0,
  3483. cur_char = 0;
  3484. CRParsingLocation location = {0} ;
  3485. g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
  3486. RECORD_INITIAL_POS (a_this, &init_pos);
  3487. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
  3488. ENSURE_PARSING_COND (status == CR_OK
  3489. && token
  3490. && token->type == FONT_FACE_SYM_TK);
  3491. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3492. if (token) {
  3493. cr_parsing_location_copy (&location,
  3494. &token->location) ;
  3495. cr_token_destroy (token);
  3496. token = NULL;
  3497. }
  3498. status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
  3499. &token);
  3500. ENSURE_PARSING_COND (status == CR_OK && token
  3501. && token->type == CBO_TK);
  3502. if (token) {
  3503. cr_token_destroy (token);
  3504. token = NULL;
  3505. }
  3506. /*
  3507. *here, call the relevant SAC handler.
  3508. */
  3509. if (PRIVATE (a_this)->sac_handler
  3510. && PRIVATE (a_this)->sac_handler->start_font_face) {
  3511. PRIVATE (a_this)->sac_handler->start_font_face
  3512. (PRIVATE (a_this)->sac_handler, &location);
  3513. }
  3514. PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE;
  3515. /*
  3516. *and resume the parsing.
  3517. */
  3518. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3519. status = cr_parser_parse_declaration (a_this, &property,
  3520. &css_expression, &important);
  3521. if (status == CR_OK) {
  3522. /*
  3523. *here, call the relevant SAC handler.
  3524. */
  3525. cr_term_ref (css_expression);
  3526. if (PRIVATE (a_this)->sac_handler &&
  3527. PRIVATE (a_this)->sac_handler->property) {
  3528. PRIVATE (a_this)->sac_handler->property
  3529. (PRIVATE (a_this)->sac_handler,
  3530. property, css_expression, important);
  3531. }
  3532. ENSURE_PARSING_COND (css_expression && property);
  3533. }
  3534. /*free the data structures allocated during last parsing. */
  3535. if (property) {
  3536. cr_string_destroy (property);
  3537. property = NULL;
  3538. }
  3539. if (css_expression) {
  3540. cr_term_unref (css_expression);
  3541. css_expression = NULL;
  3542. }
  3543. for (;;) {
  3544. PEEK_NEXT_CHAR (a_this, &next_char);
  3545. if (next_char == ';') {
  3546. READ_NEXT_CHAR (a_this, &cur_char);
  3547. } else {
  3548. break;
  3549. }
  3550. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3551. status = cr_parser_parse_declaration (a_this,
  3552. &property,
  3553. &css_expression,
  3554. &important);
  3555. if (status != CR_OK)
  3556. break;
  3557. /*
  3558. *here, call the relevant SAC handler.
  3559. */
  3560. cr_term_ref (css_expression);
  3561. if (PRIVATE (a_this)->sac_handler->property) {
  3562. PRIVATE (a_this)->sac_handler->property
  3563. (PRIVATE (a_this)->sac_handler,
  3564. property, css_expression, important);
  3565. }
  3566. /*
  3567. *Then, free the data structures allocated during
  3568. *last parsing.
  3569. */
  3570. if (property) {
  3571. cr_string_destroy (property);
  3572. property = NULL;
  3573. }
  3574. if (css_expression) {
  3575. cr_term_unref (css_expression);
  3576. css_expression = NULL;
  3577. }
  3578. }
  3579. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3580. READ_NEXT_CHAR (a_this, &cur_char);
  3581. ENSURE_PARSING_COND (cur_char == '}');
  3582. /*
  3583. *here, call the relevant SAC handler.
  3584. */
  3585. if (PRIVATE (a_this)->sac_handler->end_font_face) {
  3586. PRIVATE (a_this)->sac_handler->end_font_face
  3587. (PRIVATE (a_this)->sac_handler);
  3588. }
  3589. cr_parser_try_to_skip_spaces_and_comments (a_this);
  3590. if (token) {
  3591. cr_token_destroy (token);
  3592. token = NULL;
  3593. }
  3594. cr_parser_clear_errors (a_this);
  3595. PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE;
  3596. return CR_OK;
  3597. error:
  3598. if (token) {
  3599. cr_token_destroy (token);
  3600. token = NULL;
  3601. }
  3602. if (property) {
  3603. cr_string_destroy (property);
  3604. property = NULL;
  3605. }
  3606. if (css_expression) {
  3607. cr_term_destroy (css_expression);
  3608. css_expression = NULL;
  3609. }
  3610. cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
  3611. return status;
  3612. }
  3613. /**
  3614. *Parses the data that comes from the
  3615. *input previously associated to the current instance of
  3616. *#CRParser.
  3617. *@param a_this the current instance of #CRParser.
  3618. *@return CR_OK ;
  3619. */
  3620. enum CRStatus
  3621. cr_parser_parse (CRParser * a_this)
  3622. {
  3623. enum CRStatus status = CR_ERROR;
  3624. g_return_val_if_fail (a_this && PRIVATE (a_this)
  3625. && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
  3626. if (PRIVATE (a_this)->use_core_grammar == FALSE) {
  3627. status = cr_parser_parse_stylesheet (a_this);
  3628. } else {
  3629. status = cr_parser_parse_stylesheet_core (a_this);
  3630. }
  3631. return status;
  3632. }
  3633. enum CRStatus
  3634. cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr)
  3635. {
  3636. g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
  3637. if (PRIVATE (a_this)->tknzr) {
  3638. cr_tknzr_unref (PRIVATE (a_this)->tknzr);
  3639. }
  3640. PRIVATE (a_this)->tknzr = a_tknzr;
  3641. if (a_tknzr)
  3642. cr_tknzr_ref (a_tknzr);
  3643. return CR_OK;
  3644. }
  3645. /**
  3646. *Getter of the parser's underlying tokenizer
  3647. *@param a_this the current instance of #CRParser
  3648. *@param a_tknzr out parameter. The returned tokenizer
  3649. *@return CR_OK upon succesful completion, an error code
  3650. *otherwise
  3651. */
  3652. enum CRStatus
  3653. cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr)
  3654. {
  3655. g_return_val_if_fail (a_this && PRIVATE (a_this)
  3656. && a_tknzr, CR_BAD_PARAM_ERROR);
  3657. *a_tknzr = PRIVATE (a_this)->tknzr;
  3658. return CR_OK;
  3659. }
  3660. /**
  3661. *Gets the current parsing location.
  3662. *@param a_this the current instance of #CRParser
  3663. *@param a_loc the parsing location to get.
  3664. *@return CR_OK upon succesful completion, an error code
  3665. *otherwise.
  3666. */
  3667. enum CRStatus
  3668. cr_parser_get_parsing_location (CRParser *a_this,
  3669. CRParsingLocation *a_loc)
  3670. {
  3671. g_return_val_if_fail (a_this
  3672. && PRIVATE (a_this)
  3673. && a_loc, CR_BAD_PARAM_ERROR) ;
  3674. return cr_tknzr_get_parsing_location
  3675. (PRIVATE (a_this)->tknzr, a_loc) ;
  3676. }
  3677. /**
  3678. *Parses a stylesheet from a buffer
  3679. *@param a_this the current instance of #CRparser
  3680. *@param a_buf the input buffer
  3681. *@param a_len the length of the input buffer
  3682. *@param a_enc the encoding of the buffer
  3683. *@return CR_OK upon successful completion, an error code otherwise.
  3684. */
  3685. enum CRStatus
  3686. cr_parser_parse_buf (CRParser * a_this,
  3687. const guchar * a_buf,
  3688. gulong a_len, enum CREncoding a_enc)
  3689. {
  3690. enum CRStatus status = CR_ERROR;
  3691. CRTknzr *tknzr = NULL;
  3692. g_return_val_if_fail (a_this && PRIVATE (a_this)
  3693. && a_buf, CR_BAD_PARAM_ERROR);
  3694. tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE);
  3695. g_return_val_if_fail (tknzr != NULL, CR_ERROR);
  3696. status = cr_parser_set_tknzr (a_this, tknzr);
  3697. g_return_val_if_fail (status == CR_OK, CR_ERROR);
  3698. status = cr_parser_parse (a_this);
  3699. return status;
  3700. }
  3701. /**
  3702. *Destroys the current instance
  3703. *of #CRParser.
  3704. *@param a_this the current instance of #CRParser to
  3705. *destroy.
  3706. */
  3707. void
  3708. cr_parser_destroy (CRParser * a_this)
  3709. {
  3710. g_return_if_fail (a_this && PRIVATE (a_this));
  3711. if (PRIVATE (a_this)->tknzr) {
  3712. if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE)
  3713. PRIVATE (a_this)->tknzr = NULL;
  3714. }
  3715. if (PRIVATE (a_this)->sac_handler) {
  3716. cr_doc_handler_unref (PRIVATE (a_this)->sac_handler);
  3717. PRIVATE (a_this)->sac_handler = NULL;
  3718. }
  3719. if (PRIVATE (a_this)->err_stack) {
  3720. cr_parser_clear_errors (a_this);
  3721. PRIVATE (a_this)->err_stack = NULL;
  3722. }
  3723. if (PRIVATE (a_this)) {
  3724. g_free (PRIVATE (a_this));
  3725. PRIVATE (a_this) = NULL;
  3726. }
  3727. if (a_this) {
  3728. g_free (a_this);
  3729. a_this = NULL; /*useless. Just for the sake of coherence */
  3730. }
  3731. }