jgm / peg-markdown

An implementation of markdown in C, using a PEG grammar

This URL has Read+Write access

peg-markdown / utility_functions.c
bea5f65c » jgm 2008-06-12 Removed c function definiti... 1 /* utility_functions.c - List manipulation functions, element
2 * constructors, and macro definitions for leg markdown parser. */
3
4 extern int strcasecmp(const char *string1, const char *string2);
5
6 /**********************************************************************
7
8 List manipulation functions
9
10 ***********************************************************************/
11
2a7ef09f » jgm 2008-06-12 Renamed pushelt -> cons again. 12 /* cons - cons an element onto a list, returning pointer to new head */
13 static element * cons(element *new, element *list) {
bea5f65c » jgm 2008-06-12 Removed c function definiti... 14 assert(new != NULL);
15 new->next = list;
16 return new;
17 }
18
19 /* reverse - reverse a list, returning pointer to new list */
20 static element *reverse(element *list) {
21 element *new = NULL;
22 element *next = NULL;
23 while (list != NULL) {
24 next = list->next;
2a7ef09f » jgm 2008-06-12 Renamed pushelt -> cons again. 25 new = cons(list, new);
bea5f65c » jgm 2008-06-12 Removed c function definiti... 26 list = next;
27 }
28 return new;
29 }
30
31 /* concat_string_list - concatenates string contents of list of STR elements.
32 * Frees STR elements as they are added to the concatenation. */
33 static GString *concat_string_list(element *list) {
34 GString *result;
35 element *next;
36 result = g_string_new("");
37 while (list != NULL) {
38 assert(list->key == STR);
39 assert(list->contents.str != NULL);
40 g_string_append(result, list->contents.str);
41 next = list->next;
42 free_element(list);
43 list = next;
44 }
45 return result;
46 }
47
48 /**********************************************************************
49
50 Global variables used in parsing
51
52 ***********************************************************************/
53
54 static char *charbuf = ""; /* Buffer of characters to be parsed. */
55 static element *references = NULL; /* List of link references found. */
56 static element *notes = NULL; /* List of footnotes found. */
57 static element *parse_result; /* Results of parse. */
58 static int syntax_extensions; /* Syntax extensions selected. */
59
60 /**********************************************************************
61
62 Auxiliary functions for parsing actions.
63 These make it easier to build up data structures (including lists)
64 in the parsing actions.
65
66 ***********************************************************************/
67
68 /* mk_element - generic constructor for element */
69 static element * mk_element(int key) {
70 element *result = malloc(sizeof(element));
71 result->key = key;
72 result->children = NULL;
73 result->next = NULL;
74 result->contents.str = NULL;
75 return result;
76 }
77
78 /* mk_str - constructor for STR element */
79 static element * mk_str(char *string) {
80 element *result;
81 assert(string != NULL);
82 result = mk_element(STR);
83 result->contents.str = strdup(string);
84 return result;
85 }
86
87 /* mk_str_from_list - makes STR element by concatenating a
88 * reversed list of strings, adding optional extra newline */
89 static element * mk_str_from_list(element *list, bool extra_newline) {
90 element *result;
91 GString *c = concat_string_list(reverse(list));
92 if (extra_newline)
93 g_string_append(c, "\n");
94 result = mk_element(STR);
95 result->contents.str = c->str;
96 g_string_free(c, false);
97 return result;
98 }
99
100 /* mk_list - makes new list with key 'key' and children the reverse of 'lst'.
2a7ef09f » jgm 2008-06-12 Renamed pushelt -> cons again. 101 * This is designed to be used with cons to build lists in a parser action.
102 * The reversing is necessary because cons adds to the head of a list. */
bea5f65c » jgm 2008-06-12 Removed c function definiti... 103 static element * mk_list(int key, element *lst) {
104 element *result;
105 result = mk_element(key);
106 result->children = reverse(lst);
107 return result;
108 }
109
110 /* mk_link - constructor for LINK element */
111 static element * mk_link(element *label, char *url, char *title) {
112 element *result;
113 result = mk_element(LINK);
114 result->contents.link = malloc(sizeof(link));
115 result->contents.link->label = label;
116 result->contents.link->url = strdup(url);
117 result->contents.link->title = strdup(title);
118 return result;
119 }
120
121 /* extension = returns true if extension is selected */
122 static bool extension(int ext) {
123 return (syntax_extensions & ext);
124 }
125
126 /* match_inlines - returns true if inline lists match (case-insensitive...) */
127 static bool match_inlines(element *l1, element *l2) {
128 while (l1 != NULL && l2 != NULL) {
c1d3ceca » jgm 2008-11-22 Updated match_inlines funct... 129 if (l1->key != l2->key)
bea5f65c » jgm 2008-06-12 Removed c function definiti... 130 return false;
131 switch (l1->key) {
132 case SPACE:
133 case LINEBREAK:
c1d3ceca » jgm 2008-11-22 Updated match_inlines funct... 134 case ELLIPSIS:
135 case EMDASH:
136 case ENDASH:
137 case APOSTROPHE:
bea5f65c » jgm 2008-06-12 Removed c function definiti... 138 break;
139 case CODE:
140 case STR:
141 case HTML:
142 if (strcasecmp(l1->contents.str, l2->contents.str) == 0)
143 break;
144 else
145 return false;
146 case EMPH:
147 case STRONG:
148 case LIST:
c1d3ceca » jgm 2008-11-22 Updated match_inlines funct... 149 case SINGLEQUOTED:
150 case DOUBLEQUOTED:
bea5f65c » jgm 2008-06-12 Removed c function definiti... 151 if (match_inlines(l1->children, l2->children))
152 break;
153 else
154 return false;
155 case LINK:
156 case IMAGE:
157 return false; /* No links or images within links */
158 default:
159 fprintf(stderr, "match_inlines encountered unknown key = %d\n", l1->key);
160 exit(EXIT_FAILURE);
161 break;
162 }
163 l1 = l1->next;
164 l2 = l2->next;
165 }
166 return (l1 == NULL && l2 == NULL); /* return true if both lists exhausted */
167 }
168
169 /* find_reference - return true if link found in references matching label.
170 * 'link' is modified with the matching url and title. */
171 static bool find_reference(link *result, element *label) {
172 element *cur = references; /* pointer to walk up list of references */
173 link *curitem;
174 while (cur != NULL) {
175 curitem = cur->contents.link;
176 if (match_inlines(label, curitem->label)) {
177 *result = *curitem;
178 return true;
179 }
180 else
181 cur = cur->next;
182 }
183 return false;
184 }
185
186 /* find_note - return true if note found in notes matching label.
187 if found, 'result' is set to point to matched note. */
188
189 static bool find_note(element **result, char *label) {
190 element *cur = notes; /* pointer to walk up list of notes */
191 while (cur != NULL) {
192 if (strcmp(label, cur->contents.str) == 0) {
193 *result = cur;
194 return true;
195 }
196 else
197 cur = cur->next;
198 }
199 return false;
200 }
201
202 /**********************************************************************
203
204 Definitions for leg parser generator.
205 YY_INPUT is the function the parser calls to get new input.
206 We take all new input from (static) charbuf.
207
208 ***********************************************************************/
209
210 # define YYSTYPE element *
211 #ifdef __DEBUG__
212 # define YY_DEBUG 1
213 #endif
214
215 #define YY_INPUT(buf, result, max_size) \
216 { \
217 int yyc; \
218 if (charbuf && *charbuf != '\0') { \
219 yyc= *charbuf++; \
220 } else { \
221 yyc= EOF; \
222 } \
223 result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \
224 }
225
226