| GirToBac 0.0 Create FB Headers from GObject Introspection *.gir files

- Main Page
- Tutorial
- Data Structures
- Files

- File List
- Globals

All Data Structures Files Functions Variables Enumerations Macros Pages
GirToBac.bas
Go to the documentation of this file.
1 /'* \file GirToBac.bas
2 \brief Main source code file
3
4 This file contains the main source code. Compile this file with the
5 FreeBasic compiler \em fbc to create an executable GirToBac tool.
6
7 The main content of this file are different parsers used by the <A
8 HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html">
9 GMarkupParser </A>. Each parser is declared as a UDT containing five
10 function adresses. Only two are used here (\em start_element and \em
11 end_element). For better readability macros are used for the
12 relapsing part of the function declarations and the UDT
13 declarations of each parser. Additionally, labels are placed in
14 front of each parser to get a mark in the IDE labels list for easy
15 jumping between the parser definitions. (The labels aren't used in
16 the source code.)
17
18 '/
19
20 /'* \mainpage GirToBac
21
22 GirToBac is a tool to generate FreeBasic (FB) header files for
23 libraries based on GObject. For these libraries a <A
24 HREF="https://wiki.gnome.org/GObjectIntrospection/">GOject-Introspection</A>
25 file (suffix \em *.gir) can get generated containing all information
26 to create language bindings for high-level languages like
27 JavaScript, Vala and others. The aim is to support polyglot
28 application development.
29
30 GirToBac is the first approach to connect the FreeBasic programming
31 language to this tool-chain for easy creating and up-dating
32 FreeBasic header files of GObject based libraries (ie like GTK, GDA,
33 GooCanvas, ...).
34
35 Find more information in the \subpage tutorial.
36
37 (This documentation is generated from source code by <A
38 HREF="http://www.freebasic-portal.de/downloads/ressourcencompiler/fb-doc-229.html"
39 >fb-doc</A>.)
40
41
42 \section licence GirToBac licence (GPLv3)
43
44 Copyright &copy; 2013 by Thomas{ DoT ]Freiherr{ at }gmx[ dOt }net
45
46 This program is free software; you can redistribute it and/or modify
47 it under the terms of the GNU General Public License as published by
48 the Free Software Foundation; either version 3 of the License, or (at
49 your option) any later version.
50
51 This program is distributed in the hope that it will be useful, but
52 WITHOUT ANY WARRANTY; without even the implied warranty of
53 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
54 General Public License for more details.
55
56 To get the licence text refer to
57 http://www.gnu.org/licenses/gpl-3.0.html or write to the Free
58 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
59 MA 02110- 1301, USA.
60
61 '/
62
63 /'
64 GLib provides a simple XML parser, used to read the context of the
65 input files (*.gir) and the control files (*.GirToBac).
66 '/
67 #INCLUDE ONCE "glib.bi"
68
69 CONST OOP = 0 '*< a flag to generate classic (C-like) headers or OOP style (currently only classic style is supported)
70
71
72 /'* \brief ENUM used to specify a type
73
74 These enums are used to specify a type. This may be an return value
75 from a function, a parameter in a parameter list or a member field
76 in a TYPE or UNION.
77
78 '/
79 ENUM TypeFlags
80 TYPE_VAR '<* a variable
81 TYPE_SUB '<* a SUB (function of type 'void')
82 TYPE_FUN '<* a FUNCTION
83 TYPE_VARARG '<* a variadic parameter (in a parameter list)
84 TYPE_ARRAY '<* an Array (C-like)
85 TYPE_LIST '<* a list (GLib type)
86 END ENUM
87
88 /'* \brief TYPE struct used the parsers
89
90 The fields of this TYPE are used in the different parsers to exchain
91 the parsed context.
92
93 '/
94 TYPE UserUDT
95 AS STRING _
96 FunNam, _ '*< The FB name of a SUB/FUNCTION/callback
97 FunTyp, _ '*< The type of a FUNCTION/callback ("" = SUB)
98 FunDll, _ '*< The function name in the dll
99 FieldNam, _ '*< The FB name of a field
100 FieldVal, _ '*< The vale of a field
101 OopDll, _ '*< The FB variable for OOP ???
102 NamSpace, _ '*< The namespace of the library
103 NamDll, _ '*< The name of the library to include
104 NextElm, _ '*< The name of the next element in the ordered list
105 ArrayTyp, _ '*< The type of an array
106 Typ, _ '*< The type of a field
107 TypC, _ '*< The type of a field in C-style
108 ParaStr '*< A parameter list
109 AS INTEGER _
110 ParaBy, _ '*< The parameter passing (BYVAL/BYREF)
111 ParaCnt, _ '*< The number of parameters in a list
112 BlockCnt, _ '*< The number of entries in a block (ENUM/UNION/TYPE)
113 type_flg, _ '*< The tye of a variable (see #TypeFlags)
114 ArrayLen, _ '*< The length or size of an array
115 FieldBits, _ '*< The number of bits (in a bitfield)
116 PropRW, _ '*< The PROPERTY style (read/write)
117 FnrBi, _ '*< The file number for output
118 SkipElem '*< Wether to skip the current element (in ordered parsing process)
119 AS CONST gchar PTR _
120 FuncSkip, _ '*< Used as flag to skip a function
121 GErrr '*< Used as flag to add a GError PTR PTR in parameter lists
122
123 AS STRING _
124 Raus(15), _ '*< Strings for output (0-level, current level and 14 levels of nested blocks)
125 Nams(15) '*< Names of the current block on each level (0 to 15)
126 AS INTEGER _
127 Level = 1, _ '*< A counter for the current level
128 RausMax = 1 '*< The highest level of output (nested blocks)
129 END TYPE
130
131
132 /'* \brief Find an attribute by its name
133 \param Nam The attribute name
134 \param AttNams The GLib array of attribute names (zero terminated)
135 \param AttVals The GLib array of attribute values
136 \returns A pointer to the attribute value (or zero)
137
138 The GLib XML parser lists all attributes found in a tag and their
139 values in the arrays AttNams and AttVals. This function finds an
140 attribute by its name and returns its value. Otherwise it returns
141 zero if the specified attribute isn't present.
142
143 '/
144 FUNCTION find_value( _
145 BYVAL Nam AS CONST gchar PTR, _
146 BYVAL AttNams AS CONST gchar PTR PTR, _
147 BYVAL AttVals AS CONST gchar PTR PTR) AS CONST gchar PTR
148
149 VAR i = 0
150 WHILE AttNams[i]
151 IF *AttNams[i] = *Nam THEN RETURN AttVals[i]
152 i += 1
153 WEND : RETURN NULL
154 END FUNCTION
155
156
157 '* New line character macro (for better readability)
158 #DEFINE NL !"\n" &
159
160
161 /'* \brief Macro to start a parser
162
163 Each parser uses the same parameter list for the start function.
164 This macro generates the code for such a procedure (SUB) and opens a
165 WITH block to support access to the #UserUDT data.
166
167 It's designed to be used in combination with the _END_PARSER() macro.
168
169 '/
170 #MACRO _START_PARSER(_N_)
171 SUB start_##_N_ CDECL( _
172 BYVAL ctx AS GMarkupParseContext PTR, _
173 BYVAL element_name AS CONST gchar PTR, _
174 BYVAL AttNams AS CONST gchar PTR PTR, _
175 BYVAL AttVals AS CONST gchar PTR PTR, _
176 BYVAL UserData AS gpointer, _
177 BYVAL error_ AS GError PTR PTR)
178 WITH PEEK(UserUDT, UserData)
179 #ENDMACRO
180
181 /'* \brief Macro to complete a start parser and open an end parser
182
183 Each parser uses the same code for ending a start function and the
184 same parameter list for the end function. This macro generates the
185 code to finish the start procedure (END WITH/END SUB), open an end
186 procedure (SUB with constant parameter list) and opens a WITH block
187 to support access to the #UserUDT data.
188
189 It's designed to be used after the _START_PARSER() macro and in combination
190 with the _NEW_PARSER() macro.
191
192 '/
193 #MACRO _END_PARSER(_N_)
194 CASE ELSE
195 'PRINT #.FnrBi, NL " ' " & __FB_FUNCTION__ & " Skipping " & *element_name _
196 ' & " """ & *find_value("name", AttNams, AttVals) & """";
197 g_markup_parse_context_push(ctx, @skip_parser, UserData)
198 END SELECT
199 END WITH
200 END SUB
201 SUB end_##_N_ CDECL( _
202 BYVAL ctx AS GMarkupParseContext PTR, _
203 BYVAL element_name AS CONST gchar PTR, _
204 BYVAL UserData AS gpointer, _
205 BYVAL error_ AS GError PTR PTR)
206 WITH PEEK(UserUDT, UserData)
207 #ENDMACRO
208
209
210 /'* \brief Macro to complete an end parser and initialize the <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> UDT
211
212 Each parser uses the same code for ending an end procedure. This
213 macro generates the code to finish the end procedure and generates a
214 structure (TYPE) to use the parser. This TYPE contains two
215 functions (procedures for start and end of a XML tag).
216
217 It's designed to be used after the _END_PARSER() macro.
218
219 '/
220 #MACRO _NEW_PARSER(_N_)
221 CASE ELSE
222 g_markup_parse_context_pop(ctx)
223 END SELECT
224 END WITH
225 END SUB
226 STATIC SHARED AS GMarkupParser _N_##_parser = TYPE(@start_##_N_, @end_##_N_, NULL, NULL, NULL)
227 #ENDMACRO
228
229
230 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for skipping XML-tags
231 STATIC SHARED AS GMarkupParser skip_parser = TYPE(NULL, NULL, NULL, NULL, NULL)
232
233 #INCLUDE ONCE "GirToBac_RepData.bas"
234
235 START_FUNC:
236 /'* \brief Generate code to start parsing a function
237
238 This macro is used to start the function parser. The snipped is used
239 several times, so this macro makes it unique (single source).
240
241 '/
242 #MACRO _START_FUNC()
243 .ParaCnt = 0 : .ParaStr = "(" : .FunTyp = ""
244 IF OOP THEN
245 .FunNam = *FB_NAM.rep(find_value("name", AttNams, AttVals))
246 .FunDll = *find_value("c:identifier", AttNams, AttVals)
247 ELSE
248 .FunNam = *FB_NAM.rep(find_value("c:identifier", AttNams, AttVals))
249 END IF
250 g_markup_parse_context_push(ctx, @func_parser, UserData)
251 #ENDMACRO
252
253 /'* \brief Generate code to end parsing a function
254
255 This macro is used to end the function parser. The snipped is used
256 several times, so this macro makes it unique (single source).
257
258 '/
259 #MACRO _END_FUNC()
260 g_markup_parse_context_pop(ctx)
261 .type_flg = IIF(LEN(.FunTyp), TYPE_FUN, TYPE_SUB)
262 .ParaStr &= ")"
263 #ENDMACRO
264
265
266 /'* \brief Generate an FB type
267 \param Ud The data in the #UserUDT
268 \returns An FB type string
269
270 Type declarations may need adaptions. We have to follow the rules
271 defined in the *.GirToBac file to change some types. Also they may
272 contain '*' characters to be translated to 'PTR' strings for FB.
273
274 In seldom cases a <em>*.gir</em> declaration doesn't contain an
275 entry for a C type. Then we try repairing it by using the type used
276 in the namespace instead.
277
278 '/
279 FUNCTION fb_type(BYVAL Ud AS ANY PTR) AS STRING
280 WITH PEEK(UserUDT, Ud)
281 IF 0 = LEN(.TypC) THEN ' try to fix it (may be faulty)
282 SELECT CASE .Typ
283 CASE "utf8", "filename" : RETURN "/'!'/gchar PTR"
284 CASE ELSE
285 IF 0 = LEN(.Typ) THEN RETURN "/'!'/ any PTR"
286 .TypC = .Typ
287 END SELECT
288 ELSE
289 IF LEFT(.Typc, 9) = "volatile " THEN .TypC = MID(.TypC, 10)
290 IF .Typc = "gchar" THEN .TypC = "gint8"
291 END IF
292
293 VAR ptrs = 0, i = LEN(.TypC) - 1
294 FOR i = i TO 0 STEP -1
295 IF .TypC[i] = ASC("*") THEN ptrs += 1 ELSE EXIT FOR
296 .TypC[i] = 0
297 NEXT
298
299 IF OOP THEN .Typ = *FB_TYP.rep(.Typ) _
300 ELSE .Typ = *FB_TYP.rep(.TypC)
301
302 FOR p AS INTEGER = 1 TO ptrs
303 .Typ &= " PTR"
304 NEXT : RETURN .Typ
305 END WITH
306 END FUNCTION
307
308 '* Forward declaration (due to circular references)
309 DECLARE SUB start_type CDECL( _
310 BYVAL AS GMarkupParseContext PTR, _
311 BYVAL AS CONST gchar PTR, _
312 BYVAL AS CONST gchar PTR PTR, _
313 BYVAL AS CONST gchar PTR PTR, _
314 BYVAL AS gpointer, _
315 BYVAL AS GError PTR PTR)
316
317 '* Forward declaration (due to circular references)
318 DECLARE SUB end_type CDECL( _
319 BYVAL AS GMarkupParseContext PTR, _
320 BYVAL AS CONST gchar PTR, _
321 BYVAL AS gpointer, _
322 BYVAL AS GError PTR PTR)
323
324 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for the type XML-tags
325 STATIC SHARED AS GMarkupParser _
326 type_parser = TYPE(@start_type, @end_type, NULL, NULL, NULL)
327
328
329 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for parameter lists
330 '& SUB_CDECL Para_parser(){};
331 Para_parser:
332 _START_PARSER(Para)
333
334 SELECT CASE *element_name
335 CASE "parameter", "instance-parameter"
336 'if OOP then
337 'var d = find_value("direction", AttNams, AttVals)
338 '.ParaBy = iif(*d <> "in", 1, 0)
339 'end if
340 g_markup_parse_context_push(ctx, @type_parser, UserData)
341
342 _END_PARSER(Para)
343
344 SELECT CASE *element_name
345 CASE "parameter", "instance-parameter"
346 g_markup_parse_context_pop(ctx)
347 IF .ParaCnt THEN .ParaStr &= ", "
348 IF .type_flg = TYPE_VARARG THEN
349 .ParaStr &= "..."
350 ELSE
351 IF .type_flg = TYPE_ARRAY ANDALSO LEN(.ArrayTyp) THEN .TypC = .ArrayTyp
352 IF OOP THEN
353 'if .ParaBy _
354 'then .ParaStr &= "BYREF" : .ParaBy = 0 _
355 'else .ParaStr &= "BYVAL"
356 '.ParaStr &= " P" & .ParaCnt & " AS " & fb_type(UserData)
357 .ParaStr &= "BYVAL P" & .ParaCnt & " AS " & fb_type(UserData)
358 ELSE
359 .ParaStr &= "BYVAL AS " & fb_type(UserData)
360 END IF
361 END IF : .type_flg = 0
362 .ParaCnt += 1
363
364 _NEW_PARSER(Para)
365
366
367 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for functions (function, method, constructor, callback)
368 '& SUB_CDECL Func_parser(){};
369 Func_parser:
370 _START_PARSER(Func)
371
372 SELECT CASE *element_name
373 CASE "return-value"
374 g_markup_parse_context_push(ctx, @type_parser, UserData)
375 CASE "parameters"
376 g_markup_parse_context_push(ctx, @para_parser, UserData)
377
378 _END_PARSER(Func)
379
380 SELECT CASE *element_name
381 CASE "return-value"
382 IF .type_flg = TYPE_ARRAY ANDALSO LEN(.ArrayTyp) THEN .TypC = .ArrayTyp
383 IF .Typ <> "none" THEN .FunTyp = fb_type(UserData)
384 g_markup_parse_context_pop(ctx)
385 CASE "parameters"
386 g_markup_parse_context_pop(ctx)
387
388 _NEW_PARSER(Func)
389
390
391 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for types
392 '& SUB_CDECL Type_parser(){};
393 Type_parser:
394 _START_PARSER(Type)
395
396 SELECT CASE *element_name
397 CASE "type"
398 .Typ = *find_value("name", AttNams, AttVals)
399 VAR c = find_value("c:type", AttNams, AttVals) '*< local variable
400 IF c THEN .TypC = *c ELSE .TypC = ""
401 SELECT CASE .Typ
402 CASE "GLib.List", "GLib.SList", "GLib.Array"
403 .type_flg = TYPE_LIST
404 g_markup_parse_context_push(ctx, @skip_parser, UserData)
405 CASE ELSE
406 .type_flg = TYPE_VAR
407 END SELECT
408 CASE "callback"
409 _START_FUNC()
410 CASE "array"
411 VAR n = find_value("name", AttNams, AttVals) '*< local variable
412 VAR t = find_value("c:type", AttNams, AttVals) '*< local variable
413 IF n THEN
414 .Typ = *n
415 IF t THEN .TypC = *t ELSE .TypC = ""
416 .ArrayLen = -1
417 g_markup_parse_context_push(ctx, @skip_parser, UserData)
418 ELSE
419 n = find_value("length", AttNams, AttVals)
420 IF 0 = n THEN n = find_value("fixed-size", AttNams, AttVals)
421 IF t THEN .ArrayTyp = *t ELSE .ArrayTyp = ""
422 .ArrayLen = IIF(n, CUINT(*n), 0)
423 g_markup_parse_context_push(ctx, @type_parser, UserData)
424 END IF
425 CASE "varargs"
426
427 _END_PARSER(Type)
428
429 SELECT CASE *element_name
430 CASE "type"
431 IF .Type_flg = TYPE_LIST THEN g_markup_parse_context_pop(ctx)
432 CASE "callback"
433 _END_FUNC()
434 CASE "array"
435 .type_flg = TYPE_ARRAY
436 g_markup_parse_context_pop(ctx)
437 CASE "varargs"
438 .type_flg = TYPE_VARARG
439 CASE ELSE
440 g_markup_parse_context_pop(ctx)
441 END SELECT
442
443 END WITH : END SUB ' no _P2() macro since we need the type_parser above
444
445
446 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for interfaces, records and classes (OOP style -> ToDo)
447 '& SUB_CDECL Class_parser(){};
448 Class_parser:
449 _START_PARSER(Class)
450
451 SELECT CASE *element_name
452 CASE "method", "function", "constructor"
453 _START_FUNC()
454 CASE "field"
455 .FieldNam = *FB_NAM.rep(find_value("name", AttNams, AttVals))
456 VAR bits = find_value("bits", AttNams, AttVals) '*< local variable
457 .FieldBits = IIF(bits, CUINT(*bits), 0)
458 g_markup_parse_context_push(ctx, @type_parser, UserData)
459 CASE "property"
460 .FunNam = *FB_NAM.rep(find_value("name", AttNams, AttVals))
461 VAR r = find_value("readable", AttNams, AttVals) '*< local variable
462 VAR w = find_value("writable", AttNams, AttVals) '*< local variable
463 .PropRW = IIF(r ANDALSO *r = "0", 0, 1)
464 .PropRW += IIF(w ANDALSO *w = "0", 0, 2)
465 g_markup_parse_context_push(ctx, @type_parser, UserData)
466 CASE "virtual-method"
467 .ParaCnt = 0 : .ParaStr = "(" : .FunTyp = ""
468 .FunNam = *FB_NAM.rep(find_value("name", AttNams, AttVals))
469 g_markup_parse_context_push(ctx, @func_parser, UserData)
470 CASE "implements"
471
472 _END_PARSER(Class)
473
474 SELECT CASE *element_name
475 CASE "constructor"
476 .BlockCnt += 1
477 _END_FUNC()
478 IF .type_flg <> TYPE_FUN THEN .Raus(.Level) &= NL "'' ??? CTOR w/o type"
479
480 .Raus(.Level) &= NL " DECLARE CONSTRUCTOR " & .ParaStr
481 VAR dll = "__" & .BlockCnt '*< local variable
482 .Raus(.Level) &= NL " " & dll & " AS FUNCTION" & .ParaStr & " AS " & .FunTyp _
483 & " = DYLIBSYMBOL(" & .OopDll & ", """ & .FunDll & """)"
484
485 .Raus(0) &= NL "CONSTRUCTOR " & .Nams(.Level) & .ParaStr
486 IF .ParaCnt THEN .ParaStr = "P1" ELSE .ParaStr = ""
487 FOR i AS INTEGER = 2 TO .ParaCnt
488 .ParaStr &= ", P" & i
489 NEXT
490 .Raus(0) &= NL " __Obj = " & dll & "(" & .ParaStr & ")"
491 .Raus(0) &= NL "END CONSTRUCTOR"
492 .type_flg = 0
493 CASE "field"
494 .BlockCnt += 1
495 SELECT CASE AS CONST .type_flg
496 CASE TYPE_SUB
497 .Raus(.Level) &= NL " " & .FieldNam & " AS SUB CDECL" & .ParaStr
498 CASE TYPE_FUN
499 .Raus(.Level) &= NL " " & .FieldNam & " AS FUNCTION CDECL" & .ParaStr & " AS " & .FunTyp
500 CASE ELSE
501 .Raus(.Level) &= NL " AS " & fb_type(UserData) & " " & .FieldNam
502 IF .FieldBits THEN .Raus(.Level) &= " : " & .FieldBits
503 END SELECT : .type_flg = 0
504 g_markup_parse_context_pop(ctx)
505 CASE "virtual-method"
506 .BlockCnt += 1
507 _END_FUNC()
508 SELECT CASE AS CONST .type_flg
509 CASE TYPE_SUB : .Raus(.Level) &= NL " " & .FunNam & " AS SUB CDECL" & .ParaStr
510 CASE ELSE : .Raus(.Level) &= NL " " & .FunNam & " AS FUNCTION CDECL" & .ParaStr & " AS " & .FunTyp
511 END SELECT
512 CASE "method", "function"
513 .BlockCnt += 1
514 _END_FUNC()
515 VAR dll = "__" & .BlockCnt
516
517 VAR p = INSTR(.ParaStr, ", ") '*< local variable
518 VAR par = "(" '*< local variable
519 IF p THEN par &= MID(.ParaStr, p + 2) ELSE par &= ")"
520
521 VAR parcall = UCASE(.NamSpace & "_" & .Nams(.Level)) & "(@THIS)" '*< local variable
522 FOR i AS INTEGER = 1 TO .ParaCnt - 1
523 parcall &= ", P" & i
524 NEXT
525
526 SELECT CASE AS CONST .type_flg
527 CASE TYPE_SUB
528 .Raus(.Level) &= NL " DECLARE SUB " & .FunNam & par
529 .Raus(.Level) &= NL " " & dll & " AS SUB" & .ParaStr _
530 & " = DYLIBSYMBOL(" & .OopDll & ", """ & .FunDll & """)"
531 .Raus(0) &= NL "SUB " & .Nams(.Level) & "." & .FunNam & par
532 .Raus(0) &= NL " " & dll & "(" & parcall & ")"
533 .Raus(0) &= NL "END SUB"
534 CASE ELSE
535 .Raus(.Level) &= NL " DECLARE FUNCTION " & .FunNam & par & " AS " & .FunTyp
536 .Raus(.Level) &= NL " " & dll & " AS FUNCTION" & .ParaStr & " AS " & .FunTyp _
537 & " = DYLIBSYMBOL(" & .OopDll & ", """ & .FunDll & """)"
538 .Raus(0) &= NL "FUNCTION " & .Nams(.Level) & "." & .FunNam & par & " AS " & .FunTyp
539 .Raus(0) &= NL " RETURN " & dll & "(" & parcall & ")"
540 .Raus(0) &= NL "END FUNCTION"
541 END SELECT : .type_flg = 0
542 CASE "property" ' !!!
543 FOR i AS INTEGER = 0 TO LEN(.FunNam) - 1
544 IF .FunNam[i] = ASC("-") THEN .FunNam[i] = ASC("_")
545 NEXT
546 IF BIT(.PropRW, 0) THEN
547 .Raus(.Level) &= NL " DECLARE PROPERTY " & .FunNam & "() AS " & .Typ
548 .Raus(0) &= NL "PROPERTY " & .Nams(.Level) & "." & .FunNam & "() AS " & .Typ
549 .Raus(0) &= NL " DIM AS " & .Typ & " __r"
550 .Raus(0) &= NL " g_object_get(__Obj, """ & .FunNam & """, @__r, NULL)"
551 .Raus(0) &= NL " RETURN __r"
552 .Raus(0) &= NL "END PROPERTY"
553 END IF
554 IF BIT(.PropRW, 1) THEN
555 .Raus(.Level) &= NL " DECLARE PROPERTY " & .FunNam & "(BYVAL P1 AS" & .Typ & ")"
556 .Raus(0) &= NL "PROPERTY " & .Nams(.Level) & "." & .FunNam & "(BYVAL AS" & .Typ & ")"
557 .Raus(0) &= NL " g_object_set(__Obj, """ & .FunNam & """, P1, NULL)"
558 .Raus(0) &= NL "END PROPERTY"
559 END IF
560 g_markup_parse_context_pop(ctx)
561 CASE "implements"
562
563 _NEW_PARSER(Class)
564
565
566 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for interfaces, records and classes (C-like style)
567 '& SUB_CDECL UDT_parser(){};
568 Udt_parser:
569 _START_PARSER(Udt)
570
571 SELECT CASE *element_name
572 CASE "field"
573 VAR n = find_value("name", AttNams, AttVals)
574 VAR c = find_value("c:identifier", AttNams, AttVals)
575 .FieldNam = *FB_NAM.rep(IIF(c, c, n))
576 VAR bits = find_value("bits", AttNams, AttVals)
577 .FieldBits = IIF(bits, CUINT(*bits), 0)
578 g_markup_parse_context_push(ctx, @type_parser, UserData)
579 CASE "virtual-method"
580 g_markup_parse_context_push(ctx, @skip_parser, UserData)
581 CASE "constructor", "method", "function"
582 .GErrr = find_value("throws", AttNams, AttVals)
583 _START_FUNC()
584 CASE "property"
585
586 _END_PARSER(Udt)
587
588 SELECT CASE *element_name
589 CASE "field"
590 .BlockCnt += 1
591 SELECT CASE AS CONST .type_flg
592 CASE TYPE_SUB
593 .Raus(.Level) &= NL " " & .FieldNam & " AS SUB CDECL" & .ParaStr
594 CASE TYPE_FUN
595 .Raus(.Level) &= NL " " & .FieldNam & " AS FUNCTION CDECL" & .ParaStr & " AS " & .FunTyp
596 CASE ELSE
597 .Raus(.Level) &= NL " AS " & fb_type(UserData) & " " & .FieldNam
598 IF .type_flg = TYPE_ARRAY ANDALSO .ArrayLen > 0 _
599 THEN .Raus(.Level) &= "(" & .ArrayLen - 1 & ")"
600 IF .FieldBits THEN .Raus(.Level) &= " : " & .FieldBits
601 END SELECT : .type_flg = 0
602 g_markup_parse_context_pop(ctx)
603 CASE "virtual-method"
604 g_markup_parse_context_pop(ctx)
605 CASE "method", "function", "constructor"
606 IF .GErrr THEN
607 IF .ParaCnt THEN .ParaStr &= ", "
608 .ParaStr &= "BYVAL AS GError PTR PTR" : .ParaCnt += 1
609 END IF
610 _END_FUNC()
611 SELECT CASE AS CONST .type_flg
612 CASE TYPE_SUB
613 .Raus(0) &= NL "DECLARE SUB " & .FunNam & .ParaStr
614 CASE ELSE
615 .Raus(0) &= NL "DECLARE FUNCTION " & .FunNam & .ParaStr & " AS " & .FunTyp
616 END SELECT : .type_flg = 0
617 CASE "property" ' !!!
618
619 _NEW_PARSER(Udt)
620
621
622 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for unions
623 '& SUB_CDECL Unio_parser(){};
624 Unio_parser:
625 _START_PARSER(Unio)
626
627 SELECT CASE *element_name
628 CASE "field"
629 VAR n = find_value("name", AttNams, AttVals) '*< local variable
630 VAR c = find_value("c:identifier", AttNams, AttVals) '*< local variable
631 .FieldNam = *FB_NAM.rep(IIF(OOP, n, IIF(c, c, n)))
632 VAR bits = find_value("bits", AttNams, AttVals) '*< local variable
633 .FieldBits = IIF(bits, CUINT(*bits), 0)
634 g_markup_parse_context_push(ctx, @type_parser, UserData)
635 CASE "record"
636 .Level += 1 : IF .Level > UBOUND(.Raus) THEN g_error("Raus maximum exeded!")
637 IF .Level > .RausMax THEN .RausMax = .Level
638 VAR nam = *FB_NAM.rep(find_value("name", AttNams, AttVals)) '*< local variable
639 .Nams(.Level) = "__G2B_" & .Nams(.Level - 1) & "_" & nam
640 .Raus(.Level - 1) &= NL " AS " & .Nams(.Level) & " " & nam
641 .Raus(.Level) &= NL "TYPE " & .Nams(.Level)
642 g_markup_parse_context_push(ctx, IIF(OOP, @Class_parser, @UDT_parser), UserData)
643
644 _END_PARSER(Unio)
645
646 SELECT CASE *element_name
647 CASE "field"
648 .BlockCnt += 1
649 SELECT CASE AS CONST .type_flg
650 CASE TYPE_SUB
651 .Raus(.Level) &= NL " " & .FieldNam & " AS SUB CDECL" & .ParaStr
652 CASE TYPE_FUN
653 .Raus(.Level) &= NL " " & .FieldNam & " AS FUNCTION CDECL" & .ParaStr & " AS " & .FunTyp
654 CASE ELSE
655 .Raus(.Level) &= NL " AS " & fb_type(UserData) & " " & .FieldNam
656 IF .FieldBits THEN .Raus(.Level) &= " : " & .FieldBits
657 END SELECT : .type_flg = 0
658 g_markup_parse_context_pop(ctx)
659 CASE "record"
660 .BlockCnt += 1
661 .Raus(.Level) &= NL "END TYPE"
662 .Level -= 1
663 g_markup_parse_context_pop(ctx)
664
665 _NEW_PARSER(Unio)
666
667
668 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for enums
669 '& SUB_CDECL Enum_parser(){};
670 Enum_parser:
671 _START_PARSER(Enum)
672
673 SELECT CASE *element_name
674 CASE "member"
675 VAR nam = *FB_NAM.rep(find_value(*IIF(OOP, @"name", @"c:identifier"), AttNams, AttVals)) '*< local variable
676 VAR value = find_value("value", AttNams, AttVals) '*< local variable
677 PRINT #.FnrBi, NL " " & nam;
678 IF value THEN PRINT #.FnrBi, " = " & CINT(*value);
679
680 _END_PARSER(Enum)
681
682 SELECT CASE *element_name
683 CASE "member"
684
685 _NEW_PARSER(Enum)
686
687
688 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for first pass
689 '& SUB_CDECL pass1_parser(){};
690 pass1_parser:
691 _START_PARSER(pass1)
692
693 SELECT CASE *element_name
694 CASE "constant"
695 VAR n = find_value(IIF(OOP, @"name", @"c:type"), AttNams, AttVals) '*< local variable
696 IF 0 = n THEN n = find_value("c:identifier", AttNams, AttVals)
697 .FieldNam = *FB_NAM.rep(n)
698 .FieldVal = *find_value("value", AttNams, AttVals)
699 g_markup_parse_context_push(ctx, @type_parser, UserData)
700 CASE "enumeration", "bitfield"
701 VAR nam = *FB_NAM.rep(find_value(IIF(OOP, @"name", @"c:type"), AttNams, AttVals))
702 PRINT #.FnrBi, NL "ENUM " & nam;
703 IF OOP THEN PRINT #.FnrBi, " EXPLICIT";
704 g_markup_parse_context_push(ctx, @enum_parser, UserData)
705 CASE "alias"
706 .FieldNam = *FB_NAM.rep(find_value(IIF(OOP, @"name", @"c:type"), AttNams, AttVals))
707 g_markup_parse_context_push(ctx, @type_parser, UserData)
708 CASE "class", "record", "interface"
709 VAR n = find_value(IIF(OOP, @"name", @"c:type"), AttNams, AttVals) '*< local variable
710 IF 0 = n THEN n = find_value("glib:type-name", AttNams, AttVals)
711 VAR nam = *FB_NAM.rep(n) '*< local variable
712 PRINT #.FnrBi, NL "TYPE AS _" & nam & " " & nam;
713 CASE "include"
714 PRINT #.FnrBi, NL "#INCLUDE ONCE """ & _
715 *find_value("name", AttNams, AttVals) & "-" & _
716 *find_value("version", AttNams, AttVals) & ".bi""";
717 CASE "repository"
718 PRINT #.FnrBi, NL "' Repository version " & *find_value("version", AttNams, AttVals);
719 CASE "namespace"
720 .NamSpace = *find_value("name", AttNams, AttVals)
721 SELECT CASE .NamSpace
722 CASE "GLib", "GObject", "GModule", "Gio" : .NamSpace = "G"
723 END SELECT
724 VAR dll = find_value("shared-library", AttNams, AttVals) + 3 '*< local variable
725 IF dll > 3 THEN .NamDll = LEFT(*dll, INSTR(*dll, ".so") - 1)
726
727 IF 0 = OOP THEN EXIT SELECT
728 IF dll > 3 THEN
729 .OopDll = "__G2B_" & *find_value("name", AttNams, AttVals)
730 PRINT #.FnrBi, NL "DIM SHARED AS ANY PTR " & .OopDll;
731 PRINT #.FnrBi, NL .OopDll & " = DYLIBLOAD(""" & .NamDll & """)";
732 END IF
733 PRINT #.FnrBi, NL "NAMESPACE " & .NamSpace
734
735 _END_PARSER(pass1)
736
737 SELECT CASE *element_name
738 CASE "constant"
739 PRINT #.FnrBi, NL "#DEFINE " & .FieldNam;
740 SELECT CASE .Typ
741 CASE "utf8", "filename"
742 PRINT #.FnrBi, " !@""" & .FieldVal & """";
743 CASE ELSE
744 PRINT #.FnrBi, " " & .FieldVal;
745 END SELECT
746 g_markup_parse_context_pop(ctx)
747 CASE "enumeration", "bitfield"
748 PRINT #.FnrBi, NL "END ENUM";
749 g_markup_parse_context_pop(ctx)
750 CASE "alias"
751 PRINT #.FnrBi, NL "TYPE AS " & fb_type(UserData) & " " & .FieldNam;
752 g_markup_parse_context_pop(ctx)
753 CASE "class", "record", "interface"
754 CASE "include", "repository", "namespace"
755
756 _NEW_PARSER(pass1)
757
758
759 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for second pass
760 '& SUB_CDECL passX_parser(){};
761 passX_parser:
762 _START_PARSER(passX)
763 SELECT CASE *element_name
764 CASE "repository", "namespace" : EXIT SUB
765 END SELECT
766
767 VAR n = find_value(*IIF(OOP, @"name", @"c:type"), AttNams, AttVals)
768 IF 0 = n THEN
769 n = find_value("glib:type-name", AttNams, AttVals)
770 IF 0 = n THEN n = find_value("name", AttNams, AttVals)
771 END IF
772 IF FIRST.A = -1 THEN ' we're in P_3
773 IF FIRST.find(n) THEN ' element allready done?
774 .SkipElem = 1
775 g_markup_parse_context_push(ctx, @skip_parser, UserData)
776 EXIT SUB
777 END IF
778 ELSE ' we're in P_X
779 IF *n <> .NextElm THEN ' not our element
780 .SkipElem = 1
781 g_markup_parse_context_push(ctx, @skip_parser, UserData)
782 EXIT SUB
783 END IF
784 .NextElm = FIRST.nxt()
785 END IF
786
787 SELECT CASE *element_name
788 CASE "interface", "class"
789 IF 0 = OOP THEN ' generate class macros
790 VAR g = find_value("glib:get-type", AttNams, AttVals) '*< local variable
791 IF g ANDALSO *g <> "intern" THEN
792 VAR s = find_value("glib:type-struct", AttNams, AttVals) _'*< local variable
793 , t1 = UCASE(.NamSpace) & "_" _ '*< local variable
794 , p = INSTR(*g, "_") _ '*< local variable
795 , t2 = UCASE(MID(*g, p + 1, LEN(*g) - p - 9)) _ '*< local variable
796 , t3 = t1 & "TYPE_" & t2 _ '*< local variable
797 , t4 = t3 & ", " & *g _ '*< local variable
798 , t5 = .NamSpace & *s '*< local variable
799
800 .Raus(0) &= NL "DECLARE FUNCTION " & *g & "() AS GType"
801 .Raus(0) &= NL "#DEFINE " & t3 & " (" & *g & "())"
802 .Raus(0) &= NL "#DEFINE " & t1 & t2 & "(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), " & t3 & ", " & *n & "))"
803 .Raus(0) &= NL "#DEFINE " & t1 & t2 & "_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST((obj), " & t3 & ", " & t5 & "))"
804 .Raus(0) &= NL "#DEFINE " & t1 & "IS_" & t2 & "(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), " & t3 & "))"
805 IF element_name[0] = ASC("i") THEN
806 .Raus(0) &= NL "#DEFINE " & t1 & t2 & "_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE((obj), " & t3 & ", " & t5 &"))"
807 ELSE
808 .Raus(0) &= NL "#DEFINE " & t1 & "IS_CLASS_" & t2 & "(obj) (G_TYPE_CHECK_CLASS_TYPE((obj), " & t3 & "))"
809 .Raus(0) &= NL "#DEFINE " & t1 & t2 & "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), " & t3 & ", " & t5 &"))"
810 END IF
811 END IF
812 END IF
813 .BlockCnt = 0
814 .Nams(.Level) = *FB_NAM.rep(n)
815 .Raus(.Level) &= NL "TYPE _" & .Nams(.Level)
816 g_markup_parse_context_push(ctx, IIF(OOP, @Class_parser, @UDT_parser), UserData)
817 CASE "record"
818 .BlockCnt = 0
819 .Nams(.Level) = *FB_NAM.rep(n)
820 .Raus(.Level) &= NL "TYPE _" & .Nams(.Level)
821 g_markup_parse_context_push(ctx, IIF(OOP, @Class_parser, @UDT_parser), UserData)
822 CASE "union"
823 .Nams(.Level) = *FB_NAM.rep(n)
824 .Raus(.Level) = NL "UNION " & .Nams(.Level)
825 g_markup_parse_context_push(ctx, @Unio_parser, UserData)
826 CASE "callback"
827 .ParaCnt = 0 : .ParaStr = "(" : .FunTyp = ""
828 .FunNam = *FB_NAM.rep(find_value(*IIF(OOP, @"name", @"c:type"), AttNams, AttVals))
829 g_markup_parse_context_push(ctx, @func_parser, UserData)
830
831 _END_PARSER(passX)
832
833 IF .SkipElem THEN
834 .SkipElem = 0
835 g_markup_parse_context_pop(ctx)
836 EXIT SUB
837 END IF
838
839 SELECT CASE *element_name
840 CASE "record", "interface", "class"
841 IF .Level <> 1 THEN g_error("Raus level <> 1")
842 IF .BlockCnt _
843 THEN .Raus(1) &= NL "END TYPE" : .BlockCnt = 0 _
844 ELSE .Raus(1) = ""
845 FOR i AS INTEGER = .RausMax TO 0 STEP -1
846 PRINT #.FnrBi, .Raus(i);
847 .Raus(i) = ""
848 NEXT : .RausMax = 1
849 g_markup_parse_context_pop(ctx)
850 CASE "union"
851 IF .Level <> 1 THEN g_error("Raus level <> 1")
852 IF .BlockCnt _
853 THEN .Raus(1) &= NL "END UNION" : .BlockCnt = 0 _
854 ELSE .Raus(1) = "TYPE AS _" & .Nams(.Level) & " " & .Nams(.Level)
855 FOR i AS INTEGER = .RausMax TO 0 STEP -1
856 PRINT #.FnrBi, .Raus(i);
857 .Raus(i) = ""
858 NEXT : .RausMax = 1
859 g_markup_parse_context_pop(ctx)
860 CASE "callback"
861 _END_FUNC()
862 SELECT CASE AS CONST .type_flg
863 CASE TYPE_SUB : PRINT #.FnrBi, NL "TYPE " & .FunNam & " AS SUB CDECL" & .ParaStr;
864 CASE ELSE : PRINT #.FnrBi, NL "TYPE " & .FunNam & " AS FUNCTION CDECL" & .ParaStr & " AS " & .FunTyp;
865 END SELECT
866 CASE "repository", "namespace"
867
868 _NEW_PARSER(passX)
869
870
871 '* The <A HREF="https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html"> GMarkupParser </A> for last pass
872 '& SUB_CDECL pass4_parser(){};
873 pass4_parser:
874 _START_PARSER(pass4)
875
876 SELECT CASE *element_name
877 CASE "function"
878 .FuncSkip = find_value("moved-to", AttNams, AttVals)
879 IF .FuncSkip THEN EXIT SELECT
880 _START_FUNC()
881 CASE "repository", "namespace"
882
883 _END_PARSER(pass4)
884
885 SELECT CASE *element_name
886 CASE "function"
887 IF .FuncSkip THEN EXIT SELECT
888 _END_FUNC()
889 SELECT CASE AS CONST .type_flg
890 CASE TYPE_SUB : PRINT #.FnrBi, NL "DECLARE SUB " & .FunNam & .ParaStr;
891 CASE ELSE : PRINT #.FnrBi, NL "DECLARE FUNCTION " & .FunNam & .ParaStr & " AS " & .FunTyp;
892 END SELECT : .type_flg = 0
893 CASE "repository"
894 CASE "namespace"
895 PRINT #.FnrBi, NL "END EXTERN"
896 IF OOP THEN PRINT #.FnrBi, NL "END NAMESPACE"
897
898 _NEW_PARSER(pass4)
899
900 /'* \brief Macro to run a parser
901
902 This macro creates a parser context and runs the given parser once.
903
904 '/
905 #macro PARSE(_N_)
906 SCOPE
907 VAR ctx = g_markup_parse_context_new(@pass##_N_##_parser, 0, @UDat, NULL)
908 IF g_markup_parse_context_parse(ctx, buffer, length, @errr) THEN _
909 IF 0 = g_markup_parse_context_end_parse(ctx, @errr) THEN _
910 g_print(!"Cannot parse %s (invalid content)\n", filename, NULL)
911 g_markup_parse_context_free(ctx)
912 END SCOPE
913 #endmacro
914 ' ***** main *****
915
916 IF __FB_ARGC__ <=1 THEN ?"Pass in filename as parameter!" : END
917 VAR filename = COMMAND(1) _ '*< input file name
918 , basename = MID(filename, INSTRREV(filename, ANY "/\") + 1) _ '*< name without path
919 , proto = "" '*< protocol messages
920
921 IF g_str_has_suffix(filename, ".gir") _
922 THEN basename = LEFT(basename, LEN(basename) - 4) _
923 ELSE filename &= ".gir"
924
925 DIM AS GError PTR errr = NULL '*< location for GLib errors
926 DIM AS UserUDT UDat '*< data to exchange between parsers
927
928 DIM AS gchar PTR buffer '*< buffer for input data
929 DIM AS gsize length '*< length of input data
930
931 IF 0 = g_file_get_contents(filename, @buffer, @length, @errr) THEN _
932 g_error(!"Cannot open %s\n", filename, NULL)
933 ?"loading " & filename
934
935 WITH UDat
936 .FnrBi = FREEFILE
937 'if open cons(for output as .FnrBi) then
938 '?"Cannot open console for output!"
939 IF OPEN(basename & ".bi" FOR OUTPUT AS .FnrBi) THEN
940 ?"Cannot open file for output!"
941 ELSE
942 PRINT #.FnrBi, "' FreeBasic header file, auto-generated by"
943 PRINT #.FnrBi, "' ### GirToBac ###"
944 PRINT #.FnrBi, "' LGPLv2.1 (C) by Thomas[ dot }Freiherr[ at ]gmx[ dot }net"
945 PRINT #.FnrBi, "' Auto-translated from file " & filename
946 PRINT #.FnrBi, "#INCLUDE ONCE ""_GirToBac-0.0.bi"""
947
948 DIM AS gchar PTR buff2 '*< buffer for control file
949 DIM AS gsize length2 '*< length of control file
950 basename &= ".GirToBac"
951 IF g_file_get_contents(basename, @buff2, @length2, @errr) THEN
952 ?"loading " & basename
953 VAR ctx = g_markup_parse_context_new(@G2b_parser, 0, NULL, NULL)
954 IF g_markup_parse_context_parse(ctx, buff2, length2, @errr) THEN _
955 IF 0 = g_markup_parse_context_end_parse(ctx, @errr) THEN _
956 g_print(!"Cannot parse %s (invalid content)\n", basename, NULL)
957 g_markup_parse_context_free(ctx)
958 g_free(buff2)
959 END IF
960 ?NL "Translating ..."
961
962 PARSE(1) ' #DEFINE, ENUM, TYPE
963
964 IF OOP ORELSE 0 = LEN(.NamDll) THEN
965 PRINT #.FnrBi, NL "EXTERN ""C""";
966 ELSE
967 PRINT #.FnrBi, NL "EXTERN ""C"" LIB """ & .NamDll & """";
968 END IF
969
970 PRINT #.FnrBi, NL "' P_X" ' UNIONs, CALLBACKs and TYPEs (ordered)
971 .NextElm = FIRST.nxt()
972 WHILE FIRST.A
973 VAR xx = FIRST.A '*< stack position
974 PARSE(X)
975 IF xx <> FIRST.A THEN CONTINUE WHILE
976 proto &= NL !"\t" & .NextElm & " <first>"
977 .NextElm = FIRST.nxt()
978 WEND
979 FIRST.A = -1
980
981 PRINT #.FnrBi, NL "' P_3" ' UNIONs, CALLBACKs and TYPEs (rest)
982 PARSE(X)
983
984 PRINT #.FnrBi, NL "' P_4" ' SUBs and FUNCTIONs
985 PARSE(4)
986
987 PRINT #.FnrBi,
988 CLOSE #.FnrBi
989 END IF
990 END WITH
991 g_free(buffer)
992
993 FB_NAM.list(proto)
994 FB_TYP.list(proto)
995 IF LEN(proto) THEN ?NL "Nonexistent symbols" & proto