1 /*******************************************************************************
2 *
3 * MODULE: sourcify.c
4 *
5 ********************************************************************************
6 *
7 * DESCRIPTION: C::B::C sourcify
8 *
9 ********************************************************************************
10 *
11 * Copyright (c) 2002-2020 Marcus Holland-Moritz. All rights reserved.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the same terms as Perl itself.
14 *
15 *******************************************************************************/
16 
17 /*===== GLOBAL INCLUDES ======================================================*/
18 
19 #define PERL_NO_GET_CONTEXT
20 #include <EXTERN.h>
21 #include <perl.h>
22 #include <XSUB.h>
23 
24 #include "ppport.h"
25 
26 
27 /*===== LOCAL INCLUDES =======================================================*/
28 
29 #include "ctlib/cttype.h"
30 
31 #include "cbc/cbc.h"
32 #include "cbc/idl.h"
33 #include "cbc/sourcify.h"
34 #include "cbc/util.h"
35 
36 
37 /*===== DEFINES ==============================================================*/
38 
39 #define T_ALREADY_DUMPED   T_USER_FLAG_1
40 
41 #define F_NEWLINE          0x00000001
42 #define F_KEYWORD          0x00000002
43 #define F_DONT_EXPAND      0x00000004
44 #define F_PRAGMA_PACK_POP  0x00000008
45 
46 #define SRC_INDENT                       \
47         STMT_START {                     \
48           if (level > 0)                 \
49             add_indent(aTHX_ s, level);  \
50         } STMT_END
51 
52 #define CHECK_SET_KEYWORD                \
53         STMT_START {                     \
54           if (pSS->flags & F_KEYWORD)    \
55             sv_catpvn(s, " ", 1);        \
56           else                           \
57             SRC_INDENT;                  \
58           pSS->flags &= ~F_NEWLINE;      \
59           pSS->flags |= F_KEYWORD;       \
60         } STMT_END
61 
62 #define SvGROW_early(s, granularity)                   \
63         STMT_START {                                   \
64           if (SvCUR(s) + ((granularity)/2) > SvLEN(s)) \
65             SvGROW(s, SvCUR(s) + (granularity));       \
66         } STMT_END
67 
68 #define SVG_STRUCT 512
69 #define SVG_ENUM   512
70 
71 /*===== TYPEDEFS =============================================================*/
72 
73 typedef struct {
74   U32      flags;
75   unsigned pack;
76 } SourcifyState;
77 
78 
79 /*===== STATIC FUNCTION PROTOTYPES ===========================================*/
80 
81 static void check_define_type(pTHX_ SourcifyConfig *pSC, SV *str, TypeSpec *pTS);
82 
83 static void add_type_spec_string_rec(pTHX_ SourcifyConfig *pSC, SV *str, SV *s,
84                                      TypeSpec *pTS, int level, SourcifyState *pSS);
85 static void add_enum_spec_string_rec(pTHX_ SourcifyConfig *pSC, SV *s,
86                                      EnumSpecifier *pES, int level, SourcifyState *pSS);
87 static void add_struct_spec_string_rec(pTHX_ SourcifyConfig *pSC, SV *str, SV *s,
88                                        Struct *pStruct, int level, SourcifyState *pSS);
89 
90 static void add_typedef_list_decl_string(pTHX_ SV *str, TypedefList *pTDL);
91 static void add_typedef_list_spec_string(pTHX_ SourcifyConfig *pSC, SV *str, TypedefList *pTDL);
92 static void add_enum_spec_string(pTHX_ SourcifyConfig *pSC, SV *str, EnumSpecifier *pES);
93 static void add_struct_spec_string(pTHX_ SourcifyConfig *pSC, SV *str, Struct *pStruct);
94 
95 static void pp_macro_callback(const CMacroInfo *pmi);
96 static void add_preprocessor_definitions(pTHX_ CParseInfo *pCPI, SV *str);
97 
98 
99 /*===== EXTERNAL VARIABLES ===================================================*/
100 
101 /*===== GLOBAL VARIABLES =====================================================*/
102 
103 /*===== STATIC VARIABLES =====================================================*/
104 
105 /*===== STATIC FUNCTIONS =====================================================*/
106 
107 /*******************************************************************************
108 *
109 *   ROUTINE: check_define_type
110 *
111 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
112 *   CHANGED BY:                                   ON:
113 *
114 ********************************************************************************
115 *
116 * DESCRIPTION:
117 *
118 *   ARGUMENTS:
119 *
120 *     RETURNS:
121 *
122 *******************************************************************************/
123 
check_define_type(pTHX_ SourcifyConfig * pSC,SV * str,TypeSpec * pTS)124 static void check_define_type(pTHX_ SourcifyConfig *pSC, SV *str, TypeSpec *pTS)
125 {
126   u_32 flags = pTS->tflags;
127 
128   CT_DEBUG(MAIN, (XSCLASS "::check_define_type( pTS=(tflags=0x%08lX, ptr=%p) )",
129                   (unsigned long) pTS->tflags, pTS->ptr));
130 
131   if (flags & T_TYPE)
132   {
133     Typedef *pTypedef= (Typedef *) pTS->ptr;
134 
135     while (!pTypedef->pDecl->pointer_flag && pTypedef->pType->tflags & T_TYPE)
136       pTypedef = (Typedef *) pTypedef->pType->ptr;
137 
138     if (pTypedef->pDecl->pointer_flag)
139       return;
140 
141     pTS   = pTypedef->pType;
142     flags = pTS->tflags;
143   }
144 
145   if (flags & T_ENUM)
146   {
147     EnumSpecifier *pES = (EnumSpecifier *) pTS->ptr;
148 
149     if (pES && (pES->tflags & T_ALREADY_DUMPED) == 0)
150       add_enum_spec_string(aTHX_ pSC, str, pES);
151   }
152   else if (flags & T_COMPOUND)
153   {
154     Struct *pStruct = (Struct *) pTS->ptr;
155 
156     if (pStruct && (pStruct->tflags & T_ALREADY_DUMPED) == 0)
157       add_struct_spec_string(aTHX_ pSC, str, pStruct);
158   }
159 }
160 
161 /*******************************************************************************
162 *
163 *   ROUTINE: add_type_spec_string_rec
164 *
165 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
166 *   CHANGED BY:                                   ON:
167 *
168 ********************************************************************************
169 *
170 * DESCRIPTION:
171 *
172 *   ARGUMENTS:
173 *
174 *     RETURNS:
175 *
176 *******************************************************************************/
177 
add_type_spec_string_rec(pTHX_ SourcifyConfig * pSC,SV * str,SV * s,TypeSpec * pTS,int level,SourcifyState * pSS)178 static void add_type_spec_string_rec(pTHX_ SourcifyConfig *pSC, SV *str, SV *s,
179                                      TypeSpec *pTS, int level, SourcifyState *pSS)
180 {
181   u_32 flags = pTS->tflags;
182 
183   CT_DEBUG(MAIN, (XSCLASS "::add_type_spec_string_rec( pTS=(tflags=0x%08lX, ptr=%p"
184                           "), level=%d, pSS->flags=0x%08lX, pSS->pack=%u )",
185                           (unsigned long) pTS->tflags, pTS->ptr, level,
186                           (unsigned long) pSS->flags, pSS->pack));
187 
188   if (flags & T_TYPE)
189   {
190     Typedef *pTypedef= (Typedef *) pTS->ptr;
191 
192     if (pTypedef && pTypedef->pDecl->identifier[0])
193     {
194       CHECK_SET_KEYWORD;
195       sv_catpv(s, pTypedef->pDecl->identifier);
196     }
197   }
198   else if (flags & T_ENUM)
199   {
200     EnumSpecifier *pES = (EnumSpecifier *) pTS->ptr;
201 
202     if (pES)
203     {
204       if (pES->identifier[0] && ((pES->tflags & T_ALREADY_DUMPED) ||
205                                  (pSS->flags & F_DONT_EXPAND)))
206       {
207         CHECK_SET_KEYWORD;
208         sv_catpvf(s, "enum %s", pES->identifier);
209       }
210       else
211         add_enum_spec_string_rec(aTHX_ pSC, s, pES, level, pSS);
212     }
213   }
214   else if (flags & T_COMPOUND)
215   {
216     Struct *pStruct = (Struct *) pTS->ptr;
217 
218     if (pStruct)
219     {
220       if (pStruct->identifier[0] && ((pStruct->tflags & T_ALREADY_DUMPED) ||
221                                      (pSS->flags & F_DONT_EXPAND)))
222       {
223         CHECK_SET_KEYWORD;
224         sv_catpvf(s, "%s %s", flags & T_UNION ? "union" : "struct",
225                               pStruct->identifier);
226       }
227       else
228         add_struct_spec_string_rec(aTHX_ pSC, str, s, pStruct, level, pSS);
229     }
230   }
231   else
232   {
233     CHECK_SET_KEYWORD;
234     get_basic_type_spec_string(aTHX_ &s, flags);
235   }
236 }
237 
238 /*******************************************************************************
239 *
240 *   ROUTINE: add_enum_spec_string_rec
241 *
242 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
243 *   CHANGED BY:                                   ON:
244 *
245 ********************************************************************************
246 *
247 * DESCRIPTION:\
248 *             \
249 *   ARGUMENTS:
250 *
251 *     RETURNS:
252 *
253 *******************************************************************************/
254 
add_enum_spec_string_rec(pTHX_ SourcifyConfig * pSC,SV * s,EnumSpecifier * pES,int level,SourcifyState * pSS)255 static void add_enum_spec_string_rec(pTHX_ SourcifyConfig *pSC, SV *s,
256                                      EnumSpecifier *pES, int level, SourcifyState *pSS)
257 {
258   CT_DEBUG(MAIN, (XSCLASS "::add_enum_spec_string_rec( pES=(identifier=\"%s\"),"
259                           " level=%d, pSS->flags=0x%08lX, pSS->pack=%u )",
260                           pES->identifier, level, (unsigned long) pSS->flags, pSS->pack));
261 
262   SvGROW_early(s, SVG_ENUM);
263 
264   pES->tflags |= T_ALREADY_DUMPED;
265 
266   if (pSC->context)
267   {
268     if ((pSS->flags & F_NEWLINE) == 0)
269     {
270       sv_catpvn(s, "\n", 1);
271       pSS->flags &= ~F_KEYWORD;
272       pSS->flags |= F_NEWLINE;
273     }
274     sv_catpvf(s, "#line %lu \"%s\"\n", pES->context.line,
275                                        pES->context.pFI->name);
276   }
277 
278   if (pSS->flags & F_KEYWORD)
279     sv_catpvn(s, " ", 1);
280   else
281     SRC_INDENT;
282 
283   pSS->flags &= ~(F_NEWLINE|F_KEYWORD);
284 
285   sv_catpvn(s, "enum", 4);
286   if (pES->identifier[0])
287     sv_catpvf(s, " %s", pES->identifier);
288 
289   if (pES->enumerators)
290   {
291     ListIterator ei;
292     Enumerator *pEnum;
293     int         first = 1;
294     Value       lastVal;
295 
296     sv_catpvn(s, "\n", 1);
297     SRC_INDENT;
298     sv_catpvn(s, "{", 1);
299 
300     LL_foreach(pEnum, ei, pES->enumerators)
301     {
302       if (!first)
303         sv_catpvn(s, ",", 1);
304 
305       sv_catpvn(s, "\n", 1);
306       SRC_INDENT;
307 
308       if (( first && pEnum->value.iv == 0) ||
309           (!first && pEnum->value.iv == lastVal.iv + 1))
310         sv_catpvf(s, "\t%s", pEnum->identifier);
311       else
312         sv_catpvf(s, "\t%s = %ld", pEnum->identifier, pEnum->value.iv);
313 
314       if (first)
315         first = 0;
316 
317       lastVal = pEnum->value;
318     }
319 
320     sv_catpvn(s, "\n", 1);
321     SRC_INDENT;
322     sv_catpvn(s, "}", 1);
323   }
324 }
325 
326 /*******************************************************************************
327 *
328 *   ROUTINE: add_struct_spec_string_rec
329 *
330 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
331 *   CHANGED BY:                                   ON:
332 *
333 ********************************************************************************
334 *
335 * DESCRIPTION:
336 *
337 *   ARGUMENTS:
338 *
339 *     RETURNS:
340 *
341 *******************************************************************************/
342 
add_struct_spec_string_rec(pTHX_ SourcifyConfig * pSC,SV * str,SV * s,Struct * pStruct,int level,SourcifyState * pSS)343 static void add_struct_spec_string_rec(pTHX_ SourcifyConfig *pSC, SV *str, SV *s,
344                                        Struct *pStruct, int level, SourcifyState *pSS)
345 {
346   int pack_pushed;
347 
348   CT_DEBUG(MAIN, (XSCLASS "::add_struct_spec_string_rec( pStruct=(identifier="
349                           "\"%s\", pack=%d, tflags=0x%08lX), level=%d"
350                           " pSS->flags=0x%08lX, pSS->pack=%u )",
351                           pStruct->identifier,
352                           pStruct->pack, (unsigned long) pStruct->tflags,
353                           level, (unsigned long) pSS->flags, pSS->pack));
354 
355   SvGROW_early(s, SVG_STRUCT);
356 
357   pStruct->tflags |= T_ALREADY_DUMPED;
358 
359   pack_pushed = pStruct->declarations
360              && pStruct->pack
361              && pStruct->pack != pSS->pack;
362 
363   if (pack_pushed)
364   {
365     if ((pSS->flags & F_NEWLINE) == 0)
366     {
367       sv_catpvn(s, "\n", 1);
368       pSS->flags &= ~F_KEYWORD;
369       pSS->flags |= F_NEWLINE;
370     }
371     sv_catpvf(s, "#pragma pack(push, %u)\n", pStruct->pack);
372   }
373 
374   if (pSC->context)
375   {
376     if ((pSS->flags & F_NEWLINE) == 0)
377     {
378       sv_catpvn(s, "\n", 1);
379       pSS->flags &= ~F_KEYWORD;
380       pSS->flags |= F_NEWLINE;
381     }
382     sv_catpvf(s, "#line %lu \"%s\"\n", pStruct->context.line,
383                                        pStruct->context.pFI->name);
384   }
385 
386   if (pSS->flags & F_KEYWORD)
387     sv_catpvn(s, " ", 1);
388   else
389     SRC_INDENT;
390 
391   pSS->flags &= ~(F_NEWLINE|F_KEYWORD);
392 
393   if(pStruct->tflags & T_STRUCT)
394     sv_catpvn(s, "struct", 6);
395   else
396     sv_catpvn(s, "union", 5);
397 
398   if (pStruct->identifier[0])
399     sv_catpvf(s, " %s", pStruct->identifier);
400 
401   if (pStruct->declarations)
402   {
403     ListIterator sdi;
404     StructDeclaration *pStructDecl;
405 
406     sv_catpvn(s, "\n", 1);
407     SRC_INDENT;
408     sv_catpvn(s, "{\n", 2);
409 
410     LL_foreach(pStructDecl, sdi, pStruct->declarations)
411     {
412       ListIterator di;
413       Declarator *pDecl;
414       int first = 1, need_def = 0;
415       SourcifyState ss;
416 
417       ss.flags = F_NEWLINE;
418       ss.pack  = pack_pushed ? pStruct->pack : 0;
419 
420       LL_foreach(pDecl, di, pStructDecl->declarators)
421         if (pDecl->pointer_flag == 0)
422         {
423           need_def = 1;
424           break;
425         }
426 
427       if (!need_def)
428         ss.flags |= F_DONT_EXPAND;
429 
430       add_type_spec_string_rec(aTHX_ pSC, str, s, &pStructDecl->type, level+1, &ss);
431 
432       ss.flags &= ~F_DONT_EXPAND;
433 
434       if (ss.flags & F_NEWLINE)
435         add_indent(aTHX_ s, level+1);
436       else if (pStructDecl->declarators)
437         sv_catpvn(s, " ", 1);
438 
439       LL_foreach(pDecl, di, pStructDecl->declarators)
440       {
441         Value *pValue;
442 
443         if (first)
444           first = 0;
445         else
446           sv_catpvn(s, ", ", 2);
447 
448         if (pDecl->bitfield_flag)
449         {
450           sv_catpvf(s, "%s:%d", pDecl->identifier, pDecl->ext.bitfield.bits);
451         }
452         else {
453           sv_catpvf(s, "%s%s", pDecl->pointer_flag ? "*" : "",
454                                pDecl->identifier);
455 
456           if (pDecl->array_flag)
457           {
458             ListIterator ai;
459 
460             LL_foreach(pValue, ai, pDecl->ext.array)
461             {
462               if (pValue->flags & V_IS_UNDEF)
463                 sv_catpvn(s, "[]", 2);
464               else
465                 sv_catpvf(s, "[%ld]", pValue->iv);
466             }
467           }
468         }
469       }
470 
471       sv_catpvn(s, ";\n", 2);
472 
473       if (ss.flags & F_PRAGMA_PACK_POP)
474         sv_catpvn(s, "#pragma pack(pop)\n", 18);
475 
476       if (need_def)
477         check_define_type(aTHX_ pSC, str, &pStructDecl->type);
478     }
479 
480     SRC_INDENT;
481     sv_catpvn(s, "}", 1);
482   }
483 
484   if (pack_pushed)
485     pSS->flags |= F_PRAGMA_PACK_POP;
486 }
487 
488 /*******************************************************************************
489 *
490 *   ROUTINE: add_typedef_list_decl_string
491 *
492 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
493 *   CHANGED BY:                                   ON:
494 *
495 ********************************************************************************
496 *
497 * DESCRIPTION:
498 *
499 *   ARGUMENTS:
500 *
501 *     RETURNS:
502 *
503 *******************************************************************************/
504 
add_typedef_list_decl_string(pTHX_ SV * str,TypedefList * pTDL)505 static void add_typedef_list_decl_string(pTHX_ SV *str, TypedefList *pTDL)
506 {
507   ListIterator ti;
508   Typedef *pTypedef;
509   int first = 1;
510 
511   CT_DEBUG(MAIN, (XSCLASS "::add_typedef_list_decl_string( pTDL=%p )", pTDL));
512 
513   LL_foreach(pTypedef, ti, pTDL->typedefs)
514   {
515     Declarator *pDecl = pTypedef->pDecl;
516     Value *pValue;
517 
518     if (first)
519       first = 0;
520     else
521       sv_catpvn(str, ", ", 2);
522 
523     sv_catpvf(str, "%s%s", pDecl->pointer_flag ? "*" : "", pDecl->identifier);
524 
525     if (pDecl->array_flag)
526     {
527       ListIterator ai;
528 
529       LL_foreach(pValue, ai, pDecl->ext.array)
530       {
531         if (pValue->flags & V_IS_UNDEF)
532           sv_catpvn(str, "[]", 2);
533         else
534           sv_catpvf(str, "[%ld]", pValue->iv);
535       }
536     }
537   }
538 }
539 
540 /*******************************************************************************
541 *
542 *   ROUTINE: add_typedef_list_spec_string
543 *
544 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
545 *   CHANGED BY:                                   ON:
546 *
547 ********************************************************************************
548 *
549 * DESCRIPTION:
550 *
551 *   ARGUMENTS:
552 *
553 *     RETURNS:
554 *
555 *******************************************************************************/
556 
add_typedef_list_spec_string(pTHX_ SourcifyConfig * pSC,SV * str,TypedefList * pTDL)557 static void add_typedef_list_spec_string(pTHX_ SourcifyConfig *pSC, SV *str, TypedefList *pTDL)
558 {
559   SV *s = newSVpv("typedef", 0);
560   SourcifyState ss;
561 
562   CT_DEBUG(MAIN, (XSCLASS "::add_typedef_list_spec_string( pTDL=%p )", pTDL));
563 
564   ss.flags = F_KEYWORD;
565   ss.pack  = 0;
566 
567   add_type_spec_string_rec(aTHX_ pSC, str, s, &pTDL->type, 0, &ss);
568 
569   if ((ss.flags & F_NEWLINE) == 0)
570     sv_catpvn(s, " ", 1);
571 
572   add_typedef_list_decl_string(aTHX_ s, pTDL);
573 
574   sv_catpvn(s, ";\n", 2);
575 
576   if (ss.flags & F_PRAGMA_PACK_POP)
577     sv_catpvn(s, "#pragma pack(pop)\n", 18);
578 
579   sv_catsv(str, s);
580 
581   SvREFCNT_dec(s);
582 }
583 
584 /*******************************************************************************
585 *
586 *   ROUTINE: add_enum_spec_string
587 *
588 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
589 *   CHANGED BY:                                   ON:
590 *
591 ********************************************************************************
592 *
593 * DESCRIPTION:
594 *
595 *   ARGUMENTS:
596 *
597 *     RETURNS:
598 *
599 *******************************************************************************/
600 
add_enum_spec_string(pTHX_ SourcifyConfig * pSC,SV * str,EnumSpecifier * pES)601 static void add_enum_spec_string(pTHX_ SourcifyConfig *pSC, SV *str, EnumSpecifier *pES)
602 {
603   SV *s = newSVpvn("", 0);
604   SourcifyState ss;
605 
606   CT_DEBUG(MAIN, (XSCLASS "::add_enum_spec_string( pES=%p )", pES));
607 
608   ss.flags = 0;
609   ss.pack  = 0;
610 
611   add_enum_spec_string_rec(aTHX_ pSC, s, pES, 0, &ss);
612   sv_catpvn(s, ";\n", 2);
613   sv_catsv(str, s);
614 
615   SvREFCNT_dec(s);
616 }
617 
618 /*******************************************************************************
619 *
620 *   ROUTINE: add_struct_spec_string
621 *
622 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
623 *   CHANGED BY:                                   ON:
624 *
625 ********************************************************************************
626 *
627 * DESCRIPTION:
628 *
629 *   ARGUMENTS:
630 *
631 *     RETURNS:
632 *
633 *******************************************************************************/
634 
add_struct_spec_string(pTHX_ SourcifyConfig * pSC,SV * str,Struct * pStruct)635 static void add_struct_spec_string(pTHX_ SourcifyConfig *pSC, SV *str, Struct *pStruct)
636 {
637   SV *s = newSVpvn("", 0);
638   SourcifyState ss;
639 
640   CT_DEBUG(MAIN, (XSCLASS "::add_struct_spec_string( pStruct=%p )", pStruct));
641 
642   ss.flags = 0;
643   ss.pack  = 0;
644 
645   add_struct_spec_string_rec(aTHX_ pSC, str, s, pStruct, 0, &ss);
646   sv_catpvn(s, ";\n", 2);
647 
648   if (ss.flags & F_PRAGMA_PACK_POP)
649     sv_catpvn(s, "#pragma pack(pop)\n", 18);
650 
651   sv_catsv(str, s);
652 
653   SvREFCNT_dec(s);
654 }
655 
656 /*******************************************************************************
657 *
658 *   ROUTINE: pp_macro_callback
659 *
660 *   WRITTEN BY: Marcus Holland-Moritz             ON: Feb 2006
661 *   CHANGED BY:                                   ON:
662 *
663 ********************************************************************************
664 *
665 * DESCRIPTION:
666 *
667 *   ARGUMENTS:
668 *
669 *     RETURNS:
670 *
671 *******************************************************************************/
672 
673 #define SvGROWexp(s, amount)                                                   \
674         BEGIN_STMT {                                                           \
675           if (SvCUR(s) + pmi->definition_len + 10 >= SvLEN(s))                 \
676             SvGROW(s, 2*SvLEN(s));                                             \
677         } END_STMT
678 
679 struct macro_cb_arg
680 {
681 #ifdef PERL_IMPLICIT_CONTEXT
682   void *interp;
683 #endif
684   SV *string;
685 };
686 
pp_macro_callback(const CMacroInfo * pmi)687 static void pp_macro_callback(const CMacroInfo *pmi)
688 {
689   struct macro_cb_arg *a = pmi->arg;
690   SV *s = a->string;
691   dTHXa(a->interp);
692 
693   if (SvCUR(s) + pmi->definition_len + 10 >= SvLEN(s))
694     SvGROW(s, 2*SvLEN(s));
695 
696   sv_catpvn(s, "#define ", 8);
697   sv_catpvn(s, pmi->definition, pmi->definition_len);
698   sv_catpvn(s, "\n", 1);
699 }
700 
701 /*******************************************************************************
702 *
703 *   ROUTINE: add_preprocessor_definitions
704 *
705 *   WRITTEN BY: Marcus Holland-Moritz             ON: Feb 2006
706 *   CHANGED BY:                                   ON:
707 *
708 ********************************************************************************
709 *
710 * DESCRIPTION:
711 *
712 *   ARGUMENTS:
713 *
714 *     RETURNS:
715 *
716 *******************************************************************************/
717 
add_preprocessor_definitions(pTHX_ CParseInfo * pCPI,SV * str)718 static void add_preprocessor_definitions(pTHX_ CParseInfo *pCPI, SV *str)
719 {
720   struct macro_cb_arg a;
721   SV *s = newSVpvn("", 0);
722 
723 #ifdef PERL_IMPLICIT_CONTEXT
724   a.interp = aTHX;
725 #endif
726   a.string = s;
727 
728   SvGROW(s, 512);
729 
730   macro_iterate_defs(pCPI, pp_macro_callback, &a, CMIF_WITH_DEFINITION |
731                                                   CMIF_NO_PREDEFINED);
732 
733   if (SvCUR(s) > 0)
734   {
735     sv_catpv(str, "/* preprocessor defines */\n\n");
736     sv_catsv(str, s);
737     sv_catpvn(str, "\n", 1);
738   }
739 
740   SvREFCNT_dec(s);
741 }
742 
743 /*******************************************************************************
744 *
745 *   ROUTINE: get_sourcify_config_option
746 *
747 *   WRITTEN BY: Marcus Holland-Moritz             ON: Aug 2003
748 *   CHANGED BY:                                   ON:
749 *
750 ********************************************************************************
751 *
752 * DESCRIPTION:
753 *
754 *   ARGUMENTS:
755 *
756 *     RETURNS:
757 *
758 *******************************************************************************/
759 
760 #include "token/t_sourcify.c"
761 
762 
763 /*===== FUNCTIONS ============================================================*/
764 
765 /*******************************************************************************
766 *
767 *   ROUTINE: get_sourcify_config
768 *
769 *   WRITTEN BY: Marcus Holland-Moritz             ON: Aug 2003
770 *   CHANGED BY:                                   ON:
771 *
772 ********************************************************************************
773 *
774 * DESCRIPTION:
775 *
776 *   ARGUMENTS:
777 *
778 *     RETURNS:
779 *
780 *******************************************************************************/
781 
get_sourcify_config(pTHX_ HV * cfg,SourcifyConfig * pSC)782 void get_sourcify_config(pTHX_ HV *cfg, SourcifyConfig *pSC)
783 {
784   HE *opt;
785 
786   (void) hv_iterinit(cfg);
787 
788   while ((opt = hv_iternext(cfg)) != NULL)
789   {
790     const char *key;
791     I32 keylen;
792     SV *value;
793 
794     key   = hv_iterkey(opt, &keylen);
795     value = hv_iterval(cfg, opt);
796 
797     switch (get_sourcify_config_option(key))
798     {
799       case SOURCIFY_OPTION_Context:
800         pSC->context = SvTRUE(value);
801         break;
802 
803       case SOURCIFY_OPTION_Defines:
804         pSC->defines = SvTRUE(value);
805         break;
806 
807       default:
808         Perl_croak(aTHX_ "Invalid option '%s'", key);
809     }
810   }
811 }
812 
813 /*******************************************************************************
814 *
815 *   ROUTINE: get_parsed_definitions_string
816 *
817 *   WRITTEN BY: Marcus Holland-Moritz             ON: Oct 2002
818 *   CHANGED BY:                                   ON:
819 *
820 ********************************************************************************
821 *
822 * DESCRIPTION:
823 *
824 *   ARGUMENTS:
825 *
826 *     RETURNS:
827 *
828 *******************************************************************************/
829 
get_parsed_definitions_string(pTHX_ CParseInfo * pCPI,SourcifyConfig * pSC)830 SV *get_parsed_definitions_string(pTHX_ CParseInfo *pCPI, SourcifyConfig *pSC)
831 {
832   ListIterator   li;
833   TypedefList   *pTDL;
834   EnumSpecifier *pES;
835   Struct        *pStruct;
836   int            fTypedefPre = 0, fTypedef = 0, fEnum = 0,
837                  fStruct = 0, fUndefEnum = 0, fUndefStruct = 0;
838 
839   SV *s = newSVpvn("", 0);
840 
841   CT_DEBUG(MAIN, (XSCLASS "::get_parsed_definitions_string( pCPI=%p, pSC=%p )", pCPI, pSC));
842 
843   /* typedef predeclarations */
844 
845   LL_foreach(pTDL, li, pCPI->typedef_lists)
846   {
847     u_32 tflags = pTDL->type.tflags;
848 
849     if ((tflags & (T_ENUM|T_STRUCT|T_UNION|T_TYPE)) == 0)
850     {
851       if (!fTypedefPre)
852       {
853         sv_catpv(s, "/* typedef predeclarations */\n\n");
854         fTypedefPre = 1;
855       }
856       add_typedef_list_spec_string(aTHX_ pSC, s, pTDL);
857     }
858     else
859     {
860       const char *what = NULL, *ident;
861 
862       if (tflags & T_ENUM)
863       {
864         EnumSpecifier *pES = (EnumSpecifier *) pTDL->type.ptr;
865         if (pES && pES->identifier[0] != '\0')
866         {
867           what  = "enum";
868           ident = pES->identifier;
869         }
870       }
871       else if (tflags & T_COMPOUND)
872       {
873         Struct *pStruct = (Struct *) pTDL->type.ptr;
874         if (pStruct && pStruct->identifier[0] != '\0')
875         {
876           what  = pStruct->tflags & T_STRUCT ? "struct" : "union";
877           ident = pStruct->identifier;
878         }
879       }
880 
881       if (what != NULL)
882       {
883         if (!fTypedefPre)
884         {
885           sv_catpv(s, "/* typedef predeclarations */\n\n");
886           fTypedefPre = 1;
887         }
888         sv_catpvf(s, "typedef %s %s ", what, ident);
889         add_typedef_list_decl_string(aTHX_ s, pTDL);
890         sv_catpvn(s, ";\n", 2);
891       }
892     }
893   }
894 
895   /* typedefs */
896 
897   LL_foreach(pTDL, li, pCPI->typedef_lists)
898     if (pTDL->type.ptr != NULL)
899       if (((pTDL->type.tflags & T_ENUM) &&
900            ((EnumSpecifier *) pTDL->type.ptr)->identifier[0] == '\0') ||
901           ((pTDL->type.tflags & T_COMPOUND) &&
902            ((Struct *) pTDL->type.ptr)->identifier[0] == '\0') ||
903           (pTDL->type.tflags & T_TYPE))
904       {
905         if (!fTypedef)
906         {
907           sv_catpv(s, "\n\n/* typedefs */\n\n");
908           fTypedef = 1;
909         }
910         add_typedef_list_spec_string(aTHX_ pSC, s, pTDL);
911         sv_catpvn(s, "\n", 1);
912       }
913 
914   /* defined enums */
915 
916   LL_foreach(pES, li, pCPI->enums)
917     if (pES->enumerators &&
918         pES->identifier[0] != '\0' &&
919         (pES->tflags & (T_ALREADY_DUMPED)) == 0)
920     {
921       if (!fEnum)
922       {
923         sv_catpv(s, "\n/* defined enums */\n\n");
924         fEnum = 1;
925       }
926       add_enum_spec_string(aTHX_ pSC, s, pES);
927       sv_catpvn(s, "\n", 1);
928     }
929 
930   /* defined structs and unions */
931 
932   LL_foreach(pStruct, li, pCPI->structs)
933     if(pStruct->declarations &&
934        pStruct->identifier[0] != '\0' &&
935        (pStruct->tflags & (T_ALREADY_DUMPED)) == 0)
936     {
937       if (!fStruct)
938       {
939         sv_catpv(s, "\n/* defined structs and unions */\n\n");
940         fStruct = 1;
941       }
942       add_struct_spec_string(aTHX_ pSC, s, pStruct);
943       sv_catpvn(s, "\n", 1);
944     }
945 
946   /* undefined enums */
947 
948   LL_foreach(pES, li, pCPI->enums)
949   {
950     if ((pES->tflags & T_ALREADY_DUMPED) == 0 && pES->refcount == 0)
951     {
952       if (pES->enumerators || pES->identifier[0] != '\0')
953       {
954         if (!fUndefEnum)
955         {
956           sv_catpv(s, "\n/* undefined enums */\n\n");
957           fUndefEnum = 1;
958         }
959         add_enum_spec_string(aTHX_ pSC, s, pES);
960         sv_catpvn(s, "\n", 1);
961       }
962     }
963 
964     pES->tflags &= ~T_ALREADY_DUMPED;
965   }
966 
967   /* undefined structs and unions */
968 
969   LL_foreach(pStruct, li, pCPI->structs)
970   {
971     if ((pStruct->tflags & T_ALREADY_DUMPED) == 0 && pStruct->refcount == 0)
972     {
973       if (pStruct->declarations || pStruct->identifier[0] != '\0')
974       {
975         if (!fUndefStruct)
976         {
977           sv_catpv(s, "\n/* undefined/unnamed structs and unions */\n\n");
978           fUndefStruct = 1;
979         }
980         add_struct_spec_string(aTHX_ pSC, s, pStruct);
981         sv_catpvn(s, "\n", 1);
982       }
983     }
984 
985     pStruct->tflags &= ~T_ALREADY_DUMPED;
986   }
987 
988   /*
989    * preprocessor stuff
990    *
991    * NOTE: This _must_ be at the end, because, if placed at the top, some
992    *       defines may already interfere with the C code.
993    */
994 
995   if (pSC->defines)
996     add_preprocessor_definitions(aTHX_ pCPI, s);
997 
998   return s;
999 }
1000 
1001