rdiscount-dsc 1.6.9
Sign up to get free protection for your applications and to get access to all the features.
- data/BUILDING +34 -0
- data/COPYING +52 -0
- data/README.markdown +71 -0
- data/Rakefile +182 -0
- data/bin/rdiscount +19 -0
- data/ext/Csio.c +61 -0
- data/ext/amalloc.h +29 -0
- data/ext/basename.c +43 -0
- data/ext/config.h +23 -0
- data/ext/css.c +85 -0
- data/ext/cstring.h +77 -0
- data/ext/docheader.c +49 -0
- data/ext/dumptree.c +152 -0
- data/ext/emmatch.c +188 -0
- data/ext/extconf.rb +18 -0
- data/ext/generate.c +1642 -0
- data/ext/html5.c +24 -0
- data/ext/markdown.c +1215 -0
- data/ext/markdown.h +169 -0
- data/ext/mkdio.c +344 -0
- data/ext/mkdio.h +100 -0
- data/ext/rdiscount.c +106 -0
- data/ext/resource.c +157 -0
- data/ext/tags.c +123 -0
- data/ext/tags.h +19 -0
- data/ext/toc.c +101 -0
- data/ext/xml.c +82 -0
- data/lib/markdown.rb +1 -0
- data/lib/rdiscount.rb +87 -0
- data/man/markdown.7 +1020 -0
- data/man/rdiscount.1 +119 -0
- data/man/rdiscount.1.ronn +98 -0
- data/rdiscount-dsc.gemspec +57 -0
- data/test/benchmark.rb +56 -0
- data/test/benchmark.txt +306 -0
- data/test/markdown_test.rb +159 -0
- data/test/rdiscount_test.rb +111 -0
- metadata +88 -0
data/ext/markdown.h
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
#ifndef _MARKDOWN_D
|
2
|
+
#define _MARKDOWN_D
|
3
|
+
|
4
|
+
#include "cstring.h"
|
5
|
+
|
6
|
+
/* reference-style links (and images) are stored in an array
|
7
|
+
* of footnotes.
|
8
|
+
*/
|
9
|
+
typedef struct footnote {
|
10
|
+
Cstring tag; /* the tag for the reference link */
|
11
|
+
Cstring link; /* what this footnote points to */
|
12
|
+
Cstring title; /* what it's called (TITLE= attribute) */
|
13
|
+
int height, width; /* dimensions (for image link) */
|
14
|
+
int dealloc; /* deallocation needed? */
|
15
|
+
} Footnote;
|
16
|
+
|
17
|
+
/* each input line is read into a Line, which contains the line,
|
18
|
+
* the offset of the first non-space character [this assumes
|
19
|
+
* that all tabs will be expanded to spaces!], and a pointer to
|
20
|
+
* the next line.
|
21
|
+
*/
|
22
|
+
typedef struct line {
|
23
|
+
Cstring text;
|
24
|
+
struct line *next;
|
25
|
+
int dle;
|
26
|
+
} Line;
|
27
|
+
|
28
|
+
|
29
|
+
/* a paragraph is a collection of Lines, with links to the next paragraph
|
30
|
+
* and (if it's a QUOTE, UL, or OL) to the reparsed contents of this
|
31
|
+
* paragraph.
|
32
|
+
*/
|
33
|
+
typedef struct paragraph {
|
34
|
+
struct paragraph *next; /* next paragraph */
|
35
|
+
struct paragraph *down; /* recompiled contents of this paragraph */
|
36
|
+
struct line *text; /* all the text in this paragraph */
|
37
|
+
char *ident; /* %id% tag for QUOTE */
|
38
|
+
enum { WHITESPACE=0, CODE, QUOTE, MARKUP,
|
39
|
+
HTML, STYLE, DL, UL, OL, AL, LISTITEM,
|
40
|
+
HDR, HR, TABLE, SOURCE } typ;
|
41
|
+
enum { IMPLICIT=0, PARA, CENTER} align;
|
42
|
+
int hnumber; /* <Hn> for typ == HDR */
|
43
|
+
} Paragraph;
|
44
|
+
|
45
|
+
enum { ETX, SETEXT }; /* header types */
|
46
|
+
|
47
|
+
|
48
|
+
typedef struct block {
|
49
|
+
enum { bTEXT, bSTAR, bUNDER } b_type;
|
50
|
+
int b_count;
|
51
|
+
char b_char;
|
52
|
+
Cstring b_text;
|
53
|
+
Cstring b_post;
|
54
|
+
} block;
|
55
|
+
|
56
|
+
typedef STRING(block) Qblock;
|
57
|
+
|
58
|
+
|
59
|
+
typedef char* (*mkd_callback_t)(const char*, const int, void*);
|
60
|
+
typedef void (*mkd_free_t)(char*, void*);
|
61
|
+
|
62
|
+
typedef struct callback_data {
|
63
|
+
void *e_data; /* private data for callbacks */
|
64
|
+
mkd_callback_t e_url; /* url edit callback */
|
65
|
+
mkd_callback_t e_flags; /* extra href flags callback */
|
66
|
+
mkd_free_t e_free; /* edit/flags callback memory deallocator */
|
67
|
+
} Callback_data;
|
68
|
+
|
69
|
+
|
70
|
+
/* a magic markdown io thing holds all the data structures needed to
|
71
|
+
* do the backend processing of a markdown document
|
72
|
+
*/
|
73
|
+
typedef struct mmiot {
|
74
|
+
Cstring out;
|
75
|
+
Cstring in;
|
76
|
+
Qblock Q;
|
77
|
+
int isp;
|
78
|
+
STRING(Footnote) *footnotes;
|
79
|
+
DWORD flags;
|
80
|
+
#define MKD_NOLINKS 0x00000001
|
81
|
+
#define MKD_NOIMAGE 0x00000002
|
82
|
+
#define MKD_NOPANTS 0x00000004
|
83
|
+
#define MKD_NOHTML 0x00000008
|
84
|
+
#define MKD_STRICT 0x00000010
|
85
|
+
#define MKD_TAGTEXT 0x00000020
|
86
|
+
#define MKD_NO_EXT 0x00000040
|
87
|
+
#define MKD_CDATA 0x00000080
|
88
|
+
#define MKD_NOSUPERSCRIPT 0x00000100
|
89
|
+
#define MKD_NORELAXED 0x00000200
|
90
|
+
#define MKD_NOTABLES 0x00000400
|
91
|
+
#define MKD_NOSTRIKETHROUGH 0x00000800
|
92
|
+
#define MKD_TOC 0x00001000
|
93
|
+
#define MKD_1_COMPAT 0x00002000
|
94
|
+
#define MKD_AUTOLINK 0x00004000
|
95
|
+
#define MKD_SAFELINK 0x00008000
|
96
|
+
#define MKD_NOHEADER 0x00010000
|
97
|
+
#define MKD_TABSTOP 0x00020000
|
98
|
+
#define MKD_NODIVQUOTE 0x00040000
|
99
|
+
#define MKD_NOALPHALIST 0x00080000
|
100
|
+
#define MKD_NODLIST 0x00100000
|
101
|
+
#define IS_LABEL 0x08000000
|
102
|
+
#define USER_FLAGS 0x0FFFFFFF
|
103
|
+
#define INPUT_MASK (MKD_NOHEADER|MKD_TABSTOP)
|
104
|
+
|
105
|
+
Callback_data *cb;
|
106
|
+
} MMIOT;
|
107
|
+
|
108
|
+
|
109
|
+
/*
|
110
|
+
* the mkdio text input functions return a document structure,
|
111
|
+
* which contains a header (retrieved from the document if
|
112
|
+
* markdown was configured * with the * --enable-pandoc-header
|
113
|
+
* and the document begins with a pandoc-style header) and the
|
114
|
+
* root of the linked list of Lines.
|
115
|
+
*/
|
116
|
+
typedef struct document {
|
117
|
+
int magic; /* "I AM VALID" magic number */
|
118
|
+
#define VALID_DOCUMENT 0x19600731
|
119
|
+
Line *title;
|
120
|
+
Line *author;
|
121
|
+
Line *date;
|
122
|
+
ANCHOR(Line) content; /* uncompiled text, not valid after compile() */
|
123
|
+
Paragraph *code; /* intermediate code generated by compile() */
|
124
|
+
int compiled; /* set after mkd_compile() */
|
125
|
+
int html; /* set after (internal) htmlify() */
|
126
|
+
int tabstop; /* for properly expanding tabs (ick) */
|
127
|
+
MMIOT *ctx; /* backend buffers, flags, and structures */
|
128
|
+
Callback_data cb; /* callback functions & private data */
|
129
|
+
} Document;
|
130
|
+
|
131
|
+
|
132
|
+
extern int mkd_firstnonblank(Line *);
|
133
|
+
extern int mkd_compile(Document *, DWORD);
|
134
|
+
extern int mkd_document(Document *, char **);
|
135
|
+
extern int mkd_generatehtml(Document *, FILE *);
|
136
|
+
extern int mkd_css(Document *, char **);
|
137
|
+
extern int mkd_generatecss(Document *, FILE *);
|
138
|
+
#define mkd_style mkd_generatecss
|
139
|
+
extern int mkd_xml(char *, int , char **);
|
140
|
+
extern int mkd_generatexml(char *, int, FILE *);
|
141
|
+
extern void mkd_cleanup(Document *);
|
142
|
+
extern int mkd_line(char *, int, char **, DWORD);
|
143
|
+
extern int mkd_generateline(char *, int, FILE*, DWORD);
|
144
|
+
#define mkd_text mkd_generateline
|
145
|
+
extern void mkd_basename(Document*, char *);
|
146
|
+
extern void mkd_string_to_anchor(char*,int, void(*)(int,void*), void*, int);
|
147
|
+
|
148
|
+
extern Document *mkd_in(FILE *, DWORD);
|
149
|
+
extern Document *mkd_string(char*,int, DWORD);
|
150
|
+
|
151
|
+
extern void mkd_initialize();
|
152
|
+
extern void mkd_shlib_destructor();
|
153
|
+
|
154
|
+
/* internal resource handling functions.
|
155
|
+
*/
|
156
|
+
extern void ___mkd_freeLine(Line *);
|
157
|
+
extern void ___mkd_freeLines(Line *);
|
158
|
+
extern void ___mkd_freeParagraph(Paragraph *);
|
159
|
+
extern void ___mkd_freefootnote(Footnote *);
|
160
|
+
extern void ___mkd_freefootnotes(MMIOT *);
|
161
|
+
extern void ___mkd_initmmiot(MMIOT *, void *);
|
162
|
+
extern void ___mkd_freemmiot(MMIOT *, void *);
|
163
|
+
extern void ___mkd_freeLineRange(Line *, Line *);
|
164
|
+
extern void ___mkd_xml(char *, int, FILE *);
|
165
|
+
extern void ___mkd_reparse(char *, int, int, MMIOT*);
|
166
|
+
extern void ___mkd_emblock(MMIOT*);
|
167
|
+
extern void ___mkd_tidy(Cstring *);
|
168
|
+
|
169
|
+
#endif/*_MARKDOWN_D*/
|
data/ext/mkdio.c
ADDED
@@ -0,0 +1,344 @@
|
|
1
|
+
/*
|
2
|
+
* mkdio -- markdown front end input functions
|
3
|
+
*
|
4
|
+
* Copyright (C) 2007 David L Parsons.
|
5
|
+
* The redistribution terms are provided in the COPYRIGHT file that must
|
6
|
+
* be distributed with this source code.
|
7
|
+
*/
|
8
|
+
#include "config.h"
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <ctype.h>
|
12
|
+
|
13
|
+
#include "cstring.h"
|
14
|
+
#include "markdown.h"
|
15
|
+
#include "amalloc.h"
|
16
|
+
|
17
|
+
typedef ANCHOR(Line) LineAnchor;
|
18
|
+
|
19
|
+
/* create a new blank Document
|
20
|
+
*/
|
21
|
+
static Document*
|
22
|
+
new_Document()
|
23
|
+
{
|
24
|
+
Document *ret = calloc(sizeof(Document), 1);
|
25
|
+
|
26
|
+
if ( ret ) {
|
27
|
+
if (( ret->ctx = calloc(sizeof(MMIOT), 1) )) {
|
28
|
+
ret->magic = VALID_DOCUMENT;
|
29
|
+
return ret;
|
30
|
+
}
|
31
|
+
free(ret);
|
32
|
+
}
|
33
|
+
return 0;
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
/* add a line to the markdown input chain
|
38
|
+
*/
|
39
|
+
static void
|
40
|
+
queue(Document* a, Cstring *line)
|
41
|
+
{
|
42
|
+
Line *p = calloc(sizeof *p, 1);
|
43
|
+
unsigned char c;
|
44
|
+
int xp = 0;
|
45
|
+
int size = S(*line);
|
46
|
+
unsigned char *str = (unsigned char*)T(*line);
|
47
|
+
|
48
|
+
CREATE(p->text);
|
49
|
+
ATTACH(a->content, p);
|
50
|
+
|
51
|
+
while ( size-- ) {
|
52
|
+
if ( (c = *str++) == '\t' ) {
|
53
|
+
/* expand tabs into ->tabstop spaces. We use ->tabstop
|
54
|
+
* because the ENTIRE FREAKING COMPUTER WORLD uses editors
|
55
|
+
* that don't do ^T/^D, but instead use tabs for indentation,
|
56
|
+
* and, of course, set their tabs down to 4 spaces
|
57
|
+
*/
|
58
|
+
do {
|
59
|
+
EXPAND(p->text) = ' ';
|
60
|
+
} while ( ++xp % a->tabstop );
|
61
|
+
}
|
62
|
+
else if ( c >= ' ' ) {
|
63
|
+
EXPAND(p->text) = c;
|
64
|
+
++xp;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
EXPAND(p->text) = 0;
|
68
|
+
S(p->text)--;
|
69
|
+
p->dle = mkd_firstnonblank(p);
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
/* trim leading blanks from a header line
|
74
|
+
*/
|
75
|
+
static void
|
76
|
+
header_dle(Line *p)
|
77
|
+
{
|
78
|
+
CLIP(p->text, 0, 1);
|
79
|
+
p->dle = mkd_firstnonblank(p);
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
/* build a Document from any old input.
|
84
|
+
*/
|
85
|
+
typedef int (*getc_func)(void*);
|
86
|
+
|
87
|
+
Document *
|
88
|
+
populate(getc_func getc, void* ctx, int flags)
|
89
|
+
{
|
90
|
+
Cstring line;
|
91
|
+
Document *a = new_Document();
|
92
|
+
int c;
|
93
|
+
int pandoc = 0;
|
94
|
+
|
95
|
+
if ( !a ) return 0;
|
96
|
+
|
97
|
+
a->tabstop = (flags & MKD_TABSTOP) ? 4 : TABSTOP;
|
98
|
+
|
99
|
+
CREATE(line);
|
100
|
+
|
101
|
+
while ( (c = (*getc)(ctx)) != EOF ) {
|
102
|
+
if ( c == '\n' ) {
|
103
|
+
if ( pandoc != EOF && pandoc < 3 ) {
|
104
|
+
if ( S(line) && (T(line)[0] == '%') )
|
105
|
+
pandoc++;
|
106
|
+
else
|
107
|
+
pandoc = EOF;
|
108
|
+
}
|
109
|
+
queue(a, &line);
|
110
|
+
S(line) = 0;
|
111
|
+
}
|
112
|
+
else if ( isprint(c) || isspace(c) || (c & 0x80) )
|
113
|
+
EXPAND(line) = c;
|
114
|
+
}
|
115
|
+
|
116
|
+
if ( S(line) )
|
117
|
+
queue(a, &line);
|
118
|
+
|
119
|
+
DELETE(line);
|
120
|
+
|
121
|
+
if ( (pandoc == 3) && !(flags & (MKD_NOHEADER|MKD_STRICT)) ) {
|
122
|
+
/* the first three lines started with %, so we have a header.
|
123
|
+
* clip the first three lines out of content and hang them
|
124
|
+
* off header.
|
125
|
+
*/
|
126
|
+
Line *headers = T(a->content);
|
127
|
+
|
128
|
+
a->title = headers; header_dle(a->title);
|
129
|
+
a->author= headers->next; header_dle(a->author);
|
130
|
+
a->date = headers->next->next; header_dle(a->date);
|
131
|
+
|
132
|
+
T(a->content) = headers->next->next->next;
|
133
|
+
}
|
134
|
+
|
135
|
+
return a;
|
136
|
+
}
|
137
|
+
|
138
|
+
|
139
|
+
/* convert a file into a linked list
|
140
|
+
*/
|
141
|
+
Document *
|
142
|
+
mkd_in(FILE *f, DWORD flags)
|
143
|
+
{
|
144
|
+
return populate((getc_func)fgetc, f, flags & INPUT_MASK);
|
145
|
+
}
|
146
|
+
|
147
|
+
|
148
|
+
/* return a single character out of a buffer
|
149
|
+
*/
|
150
|
+
struct string_ctx {
|
151
|
+
char *data; /* the unread data */
|
152
|
+
int size; /* and how much is there? */
|
153
|
+
} ;
|
154
|
+
|
155
|
+
|
156
|
+
static int
|
157
|
+
strget(struct string_ctx *in)
|
158
|
+
{
|
159
|
+
if ( !in->size ) return EOF;
|
160
|
+
|
161
|
+
--(in->size);
|
162
|
+
|
163
|
+
return *(in->data)++;
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
/* convert a block of text into a linked list
|
168
|
+
*/
|
169
|
+
Document *
|
170
|
+
mkd_string(char *buf, int len, DWORD flags)
|
171
|
+
{
|
172
|
+
struct string_ctx about;
|
173
|
+
|
174
|
+
about.data = buf;
|
175
|
+
about.size = len;
|
176
|
+
|
177
|
+
return populate((getc_func)strget, &about, flags & INPUT_MASK);
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
/* write the html to a file (xmlified if necessary)
|
182
|
+
*/
|
183
|
+
int
|
184
|
+
mkd_generatehtml(Document *p, FILE *output)
|
185
|
+
{
|
186
|
+
char *doc;
|
187
|
+
int szdoc;
|
188
|
+
|
189
|
+
if ( (szdoc = mkd_document(p, &doc)) != EOF ) {
|
190
|
+
if ( p->ctx->flags & MKD_CDATA )
|
191
|
+
mkd_generatexml(doc, szdoc, output);
|
192
|
+
else
|
193
|
+
fwrite(doc, szdoc, 1, output);
|
194
|
+
putc('\n', output);
|
195
|
+
return 0;
|
196
|
+
}
|
197
|
+
return -1;
|
198
|
+
}
|
199
|
+
|
200
|
+
|
201
|
+
/* convert some markdown text to html
|
202
|
+
*/
|
203
|
+
int
|
204
|
+
markdown(Document *document, FILE *out, int flags)
|
205
|
+
{
|
206
|
+
if ( mkd_compile(document, flags) ) {
|
207
|
+
mkd_generatehtml(document, out);
|
208
|
+
mkd_cleanup(document);
|
209
|
+
return 0;
|
210
|
+
}
|
211
|
+
return -1;
|
212
|
+
}
|
213
|
+
|
214
|
+
|
215
|
+
/* write out a Cstring, mangled into a form suitable for `<a href=` or `<a id=`
|
216
|
+
*/
|
217
|
+
void
|
218
|
+
mkd_string_to_anchor(char *s, int len, void(*outchar)(int,void*),
|
219
|
+
void *out, int labelformat)
|
220
|
+
{
|
221
|
+
unsigned char c;
|
222
|
+
|
223
|
+
int i, size;
|
224
|
+
char *line;
|
225
|
+
|
226
|
+
size = mkd_line(s, len, &line, IS_LABEL);
|
227
|
+
|
228
|
+
if ( labelformat && size && !isalpha(line[0]) )
|
229
|
+
(*outchar)('L',out);
|
230
|
+
for ( i=0; i < size ; i++ ) {
|
231
|
+
c = line[i];
|
232
|
+
if ( labelformat ) {
|
233
|
+
if ( isalnum(c) || (c == '_') || (c == ':') || (c == '-') || (c == '.' ) )
|
234
|
+
(*outchar)(c, out);
|
235
|
+
else
|
236
|
+
(*outchar)('.',out);
|
237
|
+
}
|
238
|
+
else
|
239
|
+
(*outchar)(c,out);
|
240
|
+
}
|
241
|
+
|
242
|
+
if (line)
|
243
|
+
free(line);
|
244
|
+
}
|
245
|
+
|
246
|
+
|
247
|
+
/* ___mkd_reparse() a line
|
248
|
+
*/
|
249
|
+
static void
|
250
|
+
mkd_parse_line(char *bfr, int size, MMIOT *f, int flags)
|
251
|
+
{
|
252
|
+
___mkd_initmmiot(f, 0);
|
253
|
+
f->flags = flags & USER_FLAGS;
|
254
|
+
___mkd_reparse(bfr, size, 0, f);
|
255
|
+
___mkd_emblock(f);
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
/* ___mkd_reparse() a line, returning it in malloc()ed memory
|
260
|
+
*/
|
261
|
+
int
|
262
|
+
mkd_line(char *bfr, int size, char **res, DWORD flags)
|
263
|
+
{
|
264
|
+
MMIOT f;
|
265
|
+
int len;
|
266
|
+
|
267
|
+
mkd_parse_line(bfr, size, &f, flags);
|
268
|
+
|
269
|
+
if ( len = S(f.out) ) {
|
270
|
+
/* kludge alert; we know that T(f.out) is malloced memory,
|
271
|
+
* so we can just steal it away. This is awful -- there
|
272
|
+
* should be an opaque method that transparently moves
|
273
|
+
* the pointer out of the embedded Cstring.
|
274
|
+
*/
|
275
|
+
EXPAND(f.out) = 0;
|
276
|
+
*res = T(f.out);
|
277
|
+
T(f.out) = 0;
|
278
|
+
S(f.out) = ALLOCATED(f.out) = 0;
|
279
|
+
}
|
280
|
+
else {
|
281
|
+
*res = 0;
|
282
|
+
len = EOF;
|
283
|
+
}
|
284
|
+
___mkd_freemmiot(&f, 0);
|
285
|
+
return len;
|
286
|
+
}
|
287
|
+
|
288
|
+
|
289
|
+
/* ___mkd_reparse() a line, writing it to a FILE
|
290
|
+
*/
|
291
|
+
int
|
292
|
+
mkd_generateline(char *bfr, int size, FILE *output, DWORD flags)
|
293
|
+
{
|
294
|
+
MMIOT f;
|
295
|
+
|
296
|
+
mkd_parse_line(bfr, size, &f, flags);
|
297
|
+
if ( flags & MKD_CDATA )
|
298
|
+
mkd_generatexml(T(f.out), S(f.out), output);
|
299
|
+
else
|
300
|
+
fwrite(T(f.out), S(f.out), 1, output);
|
301
|
+
|
302
|
+
___mkd_freemmiot(&f, 0);
|
303
|
+
return 0;
|
304
|
+
}
|
305
|
+
|
306
|
+
|
307
|
+
/* set the url display callback
|
308
|
+
*/
|
309
|
+
void
|
310
|
+
mkd_e_url(Document *f, mkd_callback_t edit)
|
311
|
+
{
|
312
|
+
if ( f )
|
313
|
+
f->cb.e_url = edit;
|
314
|
+
}
|
315
|
+
|
316
|
+
|
317
|
+
/* set the url options callback
|
318
|
+
*/
|
319
|
+
void
|
320
|
+
mkd_e_flags(Document *f, mkd_callback_t edit)
|
321
|
+
{
|
322
|
+
if ( f )
|
323
|
+
f->cb.e_flags = edit;
|
324
|
+
}
|
325
|
+
|
326
|
+
|
327
|
+
/* set the url display/options deallocator
|
328
|
+
*/
|
329
|
+
void
|
330
|
+
mkd_e_free(Document *f, mkd_free_t dealloc)
|
331
|
+
{
|
332
|
+
if ( f )
|
333
|
+
f->cb.e_free = dealloc;
|
334
|
+
}
|
335
|
+
|
336
|
+
|
337
|
+
/* set the url display/options context data field
|
338
|
+
*/
|
339
|
+
void
|
340
|
+
mkd_e_data(Document *f, void *data)
|
341
|
+
{
|
342
|
+
if ( f )
|
343
|
+
f->cb.e_data = data;
|
344
|
+
}
|