geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

geany_lcpp.c
Go to the documentation of this file.
1/*
2* Copyright (c) 1996-2002, Darren Hiebert
3*
4* This source code is released for free distribution under the terms of the
5* GNU General Public License version 2 or (at your option) any later version.
6*
7* This module contains the high level input read functions (preprocessor
8* directives are handled within this level).
9*/
10
11/*
12* INCLUDE FILES
13*/
14#include "general.h" /* must always come first */
15
16#include <string.h>
17
18#include "debug.h"
19#include "entry.h"
20#include "geany_lcpp.h"
21#include "kind.h"
22#include "options_p.h"
23#include "read.h"
24#include "vstring.h"
25#include "parse.h"
26#include "xtag.h"
27
28/*
29* MACROS
30*/
31#define stringMatch(s1,s2) (strcmp (s1,s2) == 0)
32#define isspacetab(c) ((c) == SPACE || (c) == TAB)
33
34/*
35* DATA DECLARATIONS
36*/
38
42};
43
44/* Defines the one nesting level of a preprocessor conditional.
45 */
46typedef struct sConditionalInfo {
47 bool ignoreAllBranches; /* ignoring parent conditional branch */
48 bool singleBranch; /* choose only one branch */
49 bool branchChosen; /* branch already selected */
50 bool ignoring; /* current ignore state */
52
53enum eState {
54 DRCTV_NONE, /* no known directive - ignore to end of line */
55 DRCTV_DEFINE, /* "#define" encountered */
56 DRCTV_HASH, /* initial '#' read; determine directive */
57 DRCTV_IF, /* "#if" or "#ifdef" encountered */
58 DRCTV_PRAGMA, /* #pragma encountered */
59 DRCTV_UNDEF /* "#undef" encountered */
60};
61
62/* Defines the current state of the pre-processor.
63 */
64typedef struct sCppState {
65 int ungetch, ungetch2; /* ungotten characters, if any */
66 bool resolveRequired; /* must resolve if/else/elif/endif branch */
67 bool hasAtLiteralStrings; /* supports @"c:\" strings */
68 bool hasCxxRawLiteralStrings; /* supports R"xxx(...)xxx" strings */
70 struct sDirective {
71 enum eState state; /* current directive being processed */
72 bool accept; /* is a directive syntactically permitted? */
73 vString * name; /* macro name */
74 unsigned int nestLevel; /* level 0 is not used */
78
79/*
80* DATA DEFINITIONS
81*/
82
84static bool collectingSignature = false;
85
86/* Use brace formatting to detect end of block.
87 */
88static bool BraceFormat = false;
89
90static cppState Cpp = {
91 '\0', '\0', /* ungetch characters */
92 false, /* resolveRequired */
93 false, /* hasAtLiteralStrings */
94 false, /* hasCxxRawLiteralStrings */
95 -1, /* defineMacroKindIndex */
96 {
97 DRCTV_NONE, /* state */
98 false, /* accept */
99 NULL, /* tag name */
100 0, /* nestLevel */
101 { {false,false,false,false} } /* ifdef array */
102 } /* directive */
103};
104
105/*
106* FUNCTION DEFINITIONS
107*/
108
109extern bool cppIsBraceFormat (void)
110{
111 return BraceFormat;
112}
113
114extern unsigned int cppGetDirectiveNestLevel (void)
115{
116 return Cpp.directive.nestLevel;
117}
118
119extern void cppInit (const bool state, const bool hasAtLiteralStrings,
120 const bool hasCxxRawLiteralStrings,
121 int defineMacroKindIndex)
122{
123 BraceFormat = state;
124
125 Cpp.ungetch = '\0';
126 Cpp.ungetch2 = '\0';
127 Cpp.resolveRequired = false;
128 Cpp.hasAtLiteralStrings = hasAtLiteralStrings;
129 Cpp.hasCxxRawLiteralStrings = hasCxxRawLiteralStrings;
130 Cpp.defineMacroKindIndex = defineMacroKindIndex;
131
133 Cpp.directive.accept = true;
135
137 Cpp.directive.ifdef [0].singleBranch = false;
138 Cpp.directive.ifdef [0].branchChosen = false;
139 Cpp.directive.ifdef [0].ignoring = false;
140
142}
143
144extern void cppTerminate (void)
145{
146 if (Cpp.directive.name != NULL)
147 {
150 }
151}
152
153extern void cppBeginStatement (void)
154{
155 Cpp.resolveRequired = true;
156}
157
158extern void cppEndStatement (void)
159{
160 Cpp.resolveRequired = false;
161}
162
163/*
164* Scanning functions
165*
166* This section handles preprocessor directives. It strips out all
167* directives and may emit a tag for #define directives.
168*/
169
170/* This puts a character back into the input queue for the input File.
171 * Up to two characters may be ungotten.
172 */
173extern void cppUngetc (const int c)
174{
175 Assert (Cpp.ungetch2 == '\0');
177 Cpp.ungetch = c;
180}
181
182static inline int getcAndCollect (void)
183{
184 int c = getcFromInputFile ();
185 if (collectingSignature && c != EOF)
187 return c;
188}
189
190static inline void ungetcAndCollect (int c)
191{
195}
196
197/* Reads a directive, whose first character is given by "c", into "name".
198 */
199static bool readDirective (int c, char *const name, unsigned int maxLength)
200{
201 unsigned int i;
202
203 for (i = 0 ; i < maxLength - 1 ; ++i)
204 {
205 if (i > 0)
206 {
207 c = getcAndCollect ();
208 if (c == EOF || ! isalpha (c))
209 {
211 break;
212 }
213 }
214 name [i] = c;
215 }
216 name [i] = '\0'; /* null terminate */
217
218 return (bool) isspacetab (c);
219}
220
221/* Reads an identifier, whose first character is given by "c", into "tag",
222 * together with the file location and corresponding line number.
223 */
224static void readIdentifier (int c, vString *const name)
225{
227 do
228 {
229 vStringPut (name, c);
230 c = getcAndCollect ();
231 } while (c != EOF && cppIsident (c));
233}
234
236{
238}
239
240static bool isIgnore (void)
241{
243}
244
245static bool setIgnore (const bool ignore)
246{
248}
249
250static bool isIgnoreBranch (void)
251{
252 conditionalInfo *const ifdef = currentConditional ();
253
254 /* Force a single branch if an incomplete statement is discovered
255 * en route. This may have allowed earlier branches containing complete
256 * statements to be followed, but we must follow no further branches.
257 */
259 ifdef->singleBranch = true;
260
261 /* We will ignore this branch in the following cases:
262 *
263 * 1. We are ignoring all branches (conditional was within an ignored
264 * branch of the parent conditional)
265 * 2. A branch has already been chosen and either of:
266 * a. A statement was incomplete upon entering the conditional
267 * b. A statement is incomplete upon encountering a branch
268 */
269 return (bool) (ifdef->ignoreAllBranches ||
270 (ifdef->branchChosen && ifdef->singleBranch));
271}
272
273static void chooseBranch (void)
274{
275 if (! BraceFormat)
276 {
277 conditionalInfo *const ifdef = currentConditional ();
278
279 ifdef->branchChosen = (bool) (ifdef->singleBranch ||
281 }
282}
283
284/* Pushes one nesting level for an #if directive, indicating whether or not
285 * the branch should be ignored and whether a branch has already been chosen.
286 */
287static bool pushConditional (const bool firstBranchChosen)
288{
289 const bool ignoreAllBranches = isIgnore (); /* current ignore */
290 bool ignoreBranch = false;
291
292 if (Cpp.directive.nestLevel < (unsigned int) MaxCppNestingLevel - 1)
293 {
294 conditionalInfo *ifdef;
295
297 ifdef = currentConditional ();
298
299 /* We take a snapshot of whether there is an incomplete statement in
300 * progress upon encountering the preprocessor conditional. If so,
301 * then we will flag that only a single branch of the conditional
302 * should be followed.
303 */
304 ifdef->ignoreAllBranches = ignoreAllBranches;
306 ifdef->branchChosen = firstBranchChosen;
307 ifdef->ignoring = (bool) (ignoreAllBranches || (
308 ! firstBranchChosen && ! BraceFormat));
309 ignoreBranch = ifdef->ignoring;
310 }
311 return ignoreBranch;
312}
313
314/* Pops one nesting level for an #endif directive.
315 */
316static bool popConditional (void)
317{
318 if (Cpp.directive.nestLevel > 0)
320
321 return isIgnore ();
322}
323
324static int makeDefineTag (const char *const name, bool parameterized, bool undef)
325{
326 const bool isFileScope = (bool) (! isInputHeaderFile ());
327
328 if (Cpp.defineMacroKindIndex == -1)
329 return CORK_NIL;
331 return CORK_NIL;
332
333 if ( /* condition for definition tag */
335 || /* condition for reference tag */
337 {
338 tagEntryInfo e;
339
341 e.lineNumberEntry = (bool) (Option.locate == EX_LINENUM);
343 e.truncateLineAfterTag = true;
344 if (parameterized)
346 makeTagEntry (&e);
347 if (parameterized)
348 eFree((char *) e.extensionFields.signature);
349 }
350 return CORK_NIL;
351}
352
353static int directiveDefine (const int c, bool undef)
354{
355 int r = CORK_NIL;
356
357 if (cppIsident1 (c))
358 {
359 bool parameterized;
360 int nc;
361
363 nc = getcAndCollect ();
364 parameterized = (nc == '(');
365 if (parameterized)
366 {
368 while (nc != EOF)
369 {
370 int lastC = nc;
371 nc = getcAndCollect ();
372 if (nc == '\n' && lastC != '\\')
373 break;
374 }
376 }
377 ungetcAndCollect (nc);
378 if (! isIgnore ())
379 makeDefineTag (vStringValue (Cpp.directive.name), parameterized, undef);
380 }
382 return r;
383}
384
385static void directiveUndef (const int c)
386{
388 {
389 directiveDefine (c, true);
390 }
391 else
392 {
394 }
395}
396
397static void directivePragma (int c)
398{
399 if (cppIsident1 (c))
400 {
402 if (stringMatch (vStringValue (Cpp.directive.name), "weak"))
403 {
404 /* generate macro tag for weak name */
405 do
406 {
407 c = getcAndCollect ();
408 } while (c == SPACE);
409 if (cppIsident1 (c))
410 {
413 }
414 }
415 }
417}
418
419static bool directiveIf (const int c)
420{
421 const bool ignore = pushConditional ((bool) (c != '0'));
422
424
425 return ignore;
426}
427
428static bool directiveHash (const int c)
429{
430 bool ignore = false;
431 char directive [MaxDirectiveName];
432 DebugStatement ( const bool ignore0 = isIgnore (); )
433
434 readDirective (c, directive, MaxDirectiveName);
435 if (stringMatch (directive, "define"))
437 else if (stringMatch (directive, "undef"))
439 else if (strncmp (directive, "if", (size_t) 2) == 0)
441 else if (stringMatch (directive, "elif") ||
442 stringMatch (directive, "else"))
443 {
444 ignore = setIgnore (isIgnoreBranch ());
445 if (! ignore && stringMatch (directive, "else"))
446 chooseBranch ();
448 DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
449 }
450 else if (stringMatch (directive, "endif"))
451 {
453 ignore = popConditional ();
455 DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
456 }
457 else if (stringMatch (directive, "pragma"))
459 else
461
462 return ignore;
463}
464
465/* Handles a pre-processor directive whose first character is given by "c".
466 */
467static bool handleDirective (const int c, int *macroCorkIndex)
468{
469 bool ignore = isIgnore ();
470
471 switch (Cpp.directive.state)
472 {
473 case DRCTV_NONE: ignore = isIgnore (); break;
474 case DRCTV_DEFINE:
475 *macroCorkIndex = directiveDefine (c, false);
476 break;
477 case DRCTV_HASH: ignore = directiveHash (c); break;
478 case DRCTV_IF: ignore = directiveIf (c); break;
479 case DRCTV_PRAGMA: directivePragma (c); break;
480 case DRCTV_UNDEF: directiveUndef (c); break;
481 }
482 return ignore;
483}
484
485/* Called upon reading of a slash ('/') characters, determines whether a
486 * comment is encountered, and its type.
487 */
488static Comment isComment (void)
489{
490 Comment comment;
491 const int next = getcAndCollect ();
492
493 if (next == '*')
494 comment = COMMENT_C;
495 else if (next == '/')
496 comment = COMMENT_CPLUS;
497 else if (next == '+')
498 comment = COMMENT_D;
499 else
500 {
501 ungetcAndCollect (next);
502 comment = COMMENT_NONE;
503 }
504 return comment;
505}
506
507/* Skips over a C style comment. According to ANSI specification a comment
508 * is treated as white space, so we perform this substitution.
509 */
511{
512 int c = getcAndCollect ();
513
514 while (c != EOF)
515 {
516 if (c != '*')
517 c = getcAndCollect ();
518 else
519 {
520 const int next = getcAndCollect ();
521
522 if (next != '/')
523 c = next;
524 else
525 {
526 c = SPACE; /* replace comment with space */
527 break;
528 }
529 }
530 }
531 return c;
532}
533
534/* Skips over a C++ style comment.
535 */
536static int skipOverCplusComment (void)
537{
538 int c;
539
540 while ((c = getcAndCollect ()) != EOF)
541 {
542 if (c == BACKSLASH)
543 getcAndCollect (); /* throw away next character, too */
544 else if (c == NEWLINE)
545 break;
546 }
547 return c;
548}
549
550/* Skips over a D style comment.
551 * Really we should match nested /+ comments. At least they're less common.
552 */
553static int skipOverDComment (void)
554{
555 int c = getcAndCollect ();
556
557 while (c != EOF)
558 {
559 if (c != '+')
560 c = getcAndCollect ();
561 else
562 {
563 const int next = getcAndCollect ();
564
565 if (next != '/')
566 c = next;
567 else
568 {
569 c = SPACE; /* replace comment with space */
570 break;
571 }
572 }
573 }
574 return c;
575}
576
577/* Skips to the end of a string, returning a special character to
578 * symbolically represent a generic string.
579 */
580static int skipToEndOfString (bool ignoreBackslash)
581{
582 int c;
583
584 while ((c = getcAndCollect ()) != EOF)
585 {
586 if (c == BACKSLASH && ! ignoreBackslash)
587 getcAndCollect (); /* throw away next character, too */
588 else if (c == DOUBLE_QUOTE)
589 break;
590 }
591 return STRING_SYMBOL; /* symbolic representation of string */
592}
593
595{
596 return (c != ' ' && c != '\f' && c != '\n' && c != '\r' && c != '\t' && c != '\v' &&
597 c != '(' && c != ')' && c != '\\');
598}
599
601{
602 int c = getcAndCollect ();
603
604 if (c != '(' && ! isCxxRawLiteralDelimiterChar (c))
605 {
607 c = skipToEndOfString (false);
608 }
609 else
610 {
611 char delim[16];
612 unsigned int delimLen = 0;
613 bool collectDelim = true;
614
615 do
616 {
617 if (collectDelim)
618 {
620 delimLen < (sizeof delim / sizeof *delim))
621 delim[delimLen++] = c;
622 else
623 collectDelim = false;
624 }
625 else if (c == ')')
626 {
627 unsigned int i = 0;
628
629 while ((c = getcAndCollect ()) != EOF && i < delimLen && delim[i] == c)
630 i++;
631 if (i == delimLen && c == DOUBLE_QUOTE)
632 break;
633 else
635 }
636 }
637 while ((c = getcAndCollect ()) != EOF);
638 c = STRING_SYMBOL;
639 }
640 return c;
641}
642
643/* Skips to the end of the three (possibly four) 'c' sequence, returning a
644 * special character to symbolically represent a generic character.
645 */
646static int skipToEndOfChar (void)
647{
648 int c;
649 int count = 0;
650
651 while ((c = getcAndCollect ()) != EOF)
652 {
653 ++count;
654 if (c == BACKSLASH)
655 getcAndCollect (); /* throw away next character, too */
656 else if (c == SINGLE_QUOTE)
657 break;
658 else if (c == NEWLINE)
659 {
661 break;
662 }
663 }
664 return CHAR_SYMBOL; /* symbolic representation of character */
665}
666
667/* This function returns the next character, stripping out comments,
668 * C pre-processor directives, and the contents of single and double
669 * quoted strings. In short, strip anything which places a burden upon
670 * the tokenizer.
671 */
672extern int cppGetc (void)
673{
674 bool directive = false;
675 bool ignore = false;
676 int c;
677 int macroCorkIndex = CORK_NIL;
678
679 if (Cpp.ungetch != '\0')
680 {
681 c = Cpp.ungetch;
683 Cpp.ungetch2 = '\0';
686 return c; /* return here to avoid re-calling debugPutc () */
687 }
688 else do
689 {
690start_loop:
691 c = getcAndCollect ();
692process:
693 switch (c)
694 {
695 case EOF:
696 ignore = false;
697 directive = false;
698 macroCorkIndex = CORK_NIL;
699 break;
700
701 case TAB:
702 case SPACE:
703 break; /* ignore most white space */
704
705 case NEWLINE:
706 if (directive && ! ignore)
707 {
708 macroCorkIndex = CORK_NIL;
709 directive = false;
710 }
711 Cpp.directive.accept = true;
712 break;
713
714 case DOUBLE_QUOTE:
715 Cpp.directive.accept = false;
716 c = skipToEndOfString (false);
717 break;
718
719 case '#':
720 if (Cpp.directive.accept)
721 {
722 directive = true;
724 Cpp.directive.accept = false;
725 }
726 break;
727
728 case SINGLE_QUOTE:
729 Cpp.directive.accept = false;
730 c = skipToEndOfChar ();
731 break;
732
733 case '/':
734 {
735 const Comment comment = isComment ();
736
737 if (comment == COMMENT_C)
738 c = cppSkipOverCComment ();
739 else if (comment == COMMENT_CPLUS)
740 {
742 if (c == NEWLINE)
744 }
745 else if (comment == COMMENT_D)
746 c = skipOverDComment ();
747 else
748 Cpp.directive.accept = false;
749 break;
750 }
751
752 case BACKSLASH:
753 {
754 int next = getcAndCollect ();
755
756 if (next == NEWLINE)
757 goto start_loop;
758 else
759 ungetcAndCollect (next);
760 break;
761 }
762
763 case '?':
764 {
765 int next = getcAndCollect ();
766 if (next != '?')
767 ungetcAndCollect (next);
768 else
769 {
770 next = getcAndCollect ();
771 switch (next)
772 {
773 case '(': c = '['; break;
774 case ')': c = ']'; break;
775 case '<': c = '{'; break;
776 case '>': c = '}'; break;
777 case '/': c = BACKSLASH; goto process;
778 case '!': c = '|'; break;
779 case SINGLE_QUOTE: c = '^'; break;
780 case '-': c = '~'; break;
781 case '=': c = '#'; goto process;
782 default:
783 ungetcAndCollect ('?');
784 ungetcAndCollect (next);
785 break;
786 }
787 }
788 } break;
789
790 /* digraphs:
791 * input: <: :> <% %> %: %:%:
792 * output: [ ] { } # ##
793 */
794 case '<':
795 {
796 int next = getcAndCollect ();
797 switch (next)
798 {
799 case ':': c = '['; break;
800 case '%': c = '{'; break;
801 default: ungetcAndCollect (next);
802 }
803 goto enter;
804 }
805 case ':':
806 {
807 int next = getcAndCollect ();
808 if (next == '>')
809 c = ']';
810 else
811 ungetcAndCollect (next);
812 goto enter;
813 }
814 case '%':
815 {
816 int next = getcAndCollect ();
817 switch (next)
818 {
819 case '>': c = '}'; break;
820 case ':': c = '#'; goto process;
821 default: ungetcAndCollect (next);
822 }
823 goto enter;
824 }
825
826 default:
827 if (c == '@' && Cpp.hasAtLiteralStrings)
828 {
829 int next = getcAndCollect ();
830 if (next == DOUBLE_QUOTE)
831 {
832 Cpp.directive.accept = false;
833 c = skipToEndOfString (true);
834 break;
835 }
836 else
837 ungetcAndCollect (next);
838 }
839 else if (c == 'R' && Cpp.hasCxxRawLiteralStrings)
840 {
841 /* OMG!11 HACK!!11 Get the previous character.
842 *
843 * We need to know whether the previous character was an identifier or not,
844 * because "R" has to be on its own, not part of an identifier. This allows
845 * for constructs like:
846 *
847 * #define FOUR "4"
848 * const char *p = FOUR"5";
849 *
850 * which is not a raw literal, but a preprocessor concatenation.
851 *
852 * FIXME: handle
853 *
854 * const char *p = R\
855 * "xxx(raw)xxx";
856 *
857 * which is perfectly valid (yet probably very unlikely). */
858 int prev = getNthPrevCFromInputFile (1, '\0');
859 int prev2 = getNthPrevCFromInputFile (2, '\0');
860 int prev3 = getNthPrevCFromInputFile (3, '\0');
861
862 if (! cppIsident (prev) ||
863 (! cppIsident (prev2) && (prev == 'L' || prev == 'u' || prev == 'U')) ||
864 (! cppIsident (prev3) && (prev2 == 'u' && prev == '8')))
865 {
866 int next = getcAndCollect ();
867 if (next != DOUBLE_QUOTE)
868 ungetcAndCollect (next);
869 else
870 {
871 Cpp.directive.accept = false;
873 break;
874 }
875 }
876 }
877 enter:
878 Cpp.directive.accept = false;
879 if (directive)
880 ignore = handleDirective (c, &macroCorkIndex);
881 break;
882 }
883 } while (directive || ignore);
884
886 DebugStatement ( if (c == NEWLINE)
887 debugPrintf (DEBUG_CPP, "%6ld: ", getInputLineNumber () + 1); )
888
889 return c;
890}
891
892typedef enum
893{
901
902static void stripCodeBuffer(char *buf)
903{
904 int i = 0, pos = 0;
905 ParseState state = st_none_t, prev_state = st_none_t;
906
907 while (buf[i] != '\0')
908 {
909 switch(buf[i])
910 {
911 case '/':
912 if (st_none_t == state)
913 {
914 /* Check if this is the start of a comment */
915 if (buf[i+1] == '*') /* C comment */
916 state = st_c_comment_t;
917 else if (buf[i+1] == '/') /* C++ comment */
918 state = st_cpp_comment_t;
919 else /* Normal character */
920 buf[pos++] = '/';
921 }
922 else if (st_c_comment_t == state)
923 {
924 /* Check if this is the end of a C comment */
925 if (buf[i-1] == '*')
926 {
927 if ((pos > 0) && (buf[pos-1] != ' '))
928 buf[pos++] = ' ';
929 state = st_none_t;
930 }
931 }
932 break;
933 case '"':
934 if (st_none_t == state)
935 state = st_double_quote_t;
936 else if (st_double_quote_t == state)
937 state = st_none_t;
938 break;
939 case '\'':
940 if (st_none_t == state)
941 state = st_single_quote_t;
942 else if (st_single_quote_t == state)
943 state = st_none_t;
944 break;
945 default:
946 if ((buf[i] == '\\') && (st_escape_t != state))
947 {
948 prev_state = state;
949 state = st_escape_t;
950 }
951 else if (st_escape_t == state)
952 {
953 state = prev_state;
954 prev_state = st_none_t;
955 }
956 else if ((buf[i] == '\n') && (st_cpp_comment_t == state))
957 {
958 if ((pos > 0) && (buf[pos-1] != ' '))
959 buf[pos++] = ' ';
960 state = st_none_t;
961 }
962 else if (st_none_t == state)
963 {
964 if (isspace(buf[i]))
965 {
966 if ((pos > 0) && (buf[pos-1] != ' '))
967 buf[pos++] = ' ';
968 }
969 else
970 buf[pos++] = buf[i];
971 }
972 break;
973 }
974 ++i;
975 }
976 buf[pos] = '\0';
977 return;
978}
979
980extern char *cppGetSignature(void)
981{
982 char *start, *end;
983 int level;
984
985 if (NULL == signature || vStringLength (signature) < 2)
986 return NULL;
987
988 start = eStrdup (vStringValue (signature));
989 stripCodeBuffer(start);
990 for (level = 1, end = start + 1; level > 0; ++end)
991 {
992 if ('\0' == *end)
993 break;
994 else if ('(' == *end)
995 ++ level;
996 else if (')' == *end)
997 -- level;
998 }
999 *end = '\0';
1000 return start;
1001}
1002
1004{
1006 vStringPut (signature, '(');
1007 collectingSignature = true;
1008}
1009
1011{
1012 collectingSignature = false;
1013}
1014
1015extern void cppClearSignature (void)
1016{
1018 collectingSignature = false;
1019}
1020
1021/* tags_ignore is a NULL-terminated array of strings, read from ~/.config/geany/ignore.tags.
1022 * This file contains a space or newline separated list of symbols which should be ignored
1023 * by the C/C++ parser, see -I command line option of ctags for details. */
1025
1026/* Determines whether or not "name" should be ignored, per the ignore list.
1027 */
1028extern bool cppIsIgnoreToken (const char *const name,
1029 bool *const pIgnoreParens,
1030 const char **const replacement)
1031{
1032 bool result = false;
1033
1034 if (c_tags_ignore != NULL)
1035 {
1036 const size_t nameLen = strlen (name);
1037 unsigned int i;
1038 unsigned int len = 0;
1039 vString *token = vStringNew();
1040
1041 while (c_tags_ignore[len])
1042 len++;
1043
1044 if (pIgnoreParens != NULL)
1045 *pIgnoreParens = false;
1046
1047 for (i = 0 ; i < len ; ++i)
1048 {
1049 size_t tokenLen;
1050
1051 vStringCopyS (token, c_tags_ignore[i]);
1052 tokenLen = vStringLength (token);
1053
1054 if (tokenLen >= 2 && vStringChar (token, tokenLen - 1) == '*' &&
1055 strncmp (vStringValue (token), name, tokenLen - 1) == 0)
1056 {
1057 result = true;
1058 break;
1059 }
1060 if (strncmp (vStringValue (token), name, nameLen) == 0)
1061 {
1062 if (nameLen == tokenLen)
1063 {
1064 result = true;
1065 break;
1066 }
1067 else if (tokenLen == nameLen + 1 &&
1068 vStringChar (token, tokenLen - 1) == '+')
1069 {
1070 result = true;
1071 if (pIgnoreParens != NULL)
1072 *pIgnoreParens = true;
1073 break;
1074 }
1075 else if (vStringChar (token, nameLen) == '=')
1076 {
1077 if (replacement != NULL)
1078 *replacement = vStringValue (token) + nameLen + 1;
1079 break;
1080 }
1081 }
1082 }
1083 vStringDelete (token);
1084 }
1085 return result;
1086}
#define Assert(c)
Definition: debug.h:47
#define DebugStatement(x)
Definition: debug.h:45
void debugCppIgnore(const bool ignore)
void debugCppNest(const bool begin, const unsigned int level)
@ DEBUG_CPP
Definition: debug.h:69
void debugPrintf(const enum eDebugLevels level, const char *const format,...)
void debugPutc(const int level, const int c)
const gchar * name
Definition: document.c:3219
gint pos
Definition: editor.c:87
int makeTagEntry(const tagEntryInfo *const tag)
Definition: entry.c:1675
void initTagEntry(tagEntryInfo *const e, const char *const name, int kindIndex)
Definition: entry.c:1823
#define CORK_NIL
Definition: entry.h:145
unsigned int count
static bool isFileScope(const tagType type)
static void directivePragma(int c)
Definition: geany_lcpp.c:397
static void chooseBranch(void)
Definition: geany_lcpp.c:273
static int getcAndCollect(void)
Definition: geany_lcpp.c:182
bool cppIsIgnoreToken(const char *const name, bool *const pIgnoreParens, const char **const replacement)
Definition: geany_lcpp.c:1028
eCppLimits
Definition: geany_lcpp.c:39
@ MaxDirectiveName
Definition: geany_lcpp.c:41
@ MaxCppNestingLevel
Definition: geany_lcpp.c:40
static bool collectingSignature
Definition: geany_lcpp.c:84
static void ungetcAndCollect(int c)
Definition: geany_lcpp.c:190
bool cppIsBraceFormat(void)
Definition: geany_lcpp.c:109
void cppUngetc(const int c)
Definition: geany_lcpp.c:173
static vString * signature
Definition: geany_lcpp.c:83
int cppGetc(void)
Definition: geany_lcpp.c:672
int cppSkipOverCComment(void)
Definition: geany_lcpp.c:510
static bool setIgnore(const bool ignore)
Definition: geany_lcpp.c:245
static bool directiveIf(const int c)
Definition: geany_lcpp.c:419
unsigned int cppGetDirectiveNestLevel(void)
Definition: geany_lcpp.c:114
static int skipToEndOfChar(void)
Definition: geany_lcpp.c:646
static void stripCodeBuffer(char *buf)
Definition: geany_lcpp.c:902
static conditionalInfo * currentConditional(void)
Definition: geany_lcpp.c:235
static int isCxxRawLiteralDelimiterChar(int c)
Definition: geany_lcpp.c:594
static int skipToEndOfCxxRawLiteralString(void)
Definition: geany_lcpp.c:600
static bool pushConditional(const bool firstBranchChosen)
Definition: geany_lcpp.c:287
static void readIdentifier(int c, vString *const name)
Definition: geany_lcpp.c:224
void cppEndStatement(void)
Definition: geany_lcpp.c:158
Comment
Definition: geany_lcpp.c:37
@ COMMENT_C
Definition: geany_lcpp.c:37
@ COMMENT_CPLUS
Definition: geany_lcpp.c:37
@ COMMENT_NONE
Definition: geany_lcpp.c:37
@ COMMENT_D
Definition: geany_lcpp.c:37
void cppStopCollectingSignature(void)
Definition: geany_lcpp.c:1010
static bool BraceFormat
Definition: geany_lcpp.c:88
void cppInit(const bool state, const bool hasAtLiteralStrings, const bool hasCxxRawLiteralStrings, int defineMacroKindIndex)
Definition: geany_lcpp.c:119
static int makeDefineTag(const char *const name, bool parameterized, bool undef)
Definition: geany_lcpp.c:324
static void directiveUndef(const int c)
Definition: geany_lcpp.c:385
static Comment isComment(void)
Definition: geany_lcpp.c:488
ParseState
Definition: geany_lcpp.c:893
@ st_escape_t
Definition: geany_lcpp.c:895
@ st_double_quote_t
Definition: geany_lcpp.c:898
@ st_none_t
Definition: geany_lcpp.c:894
@ st_c_comment_t
Definition: geany_lcpp.c:896
@ st_single_quote_t
Definition: geany_lcpp.c:899
@ st_cpp_comment_t
Definition: geany_lcpp.c:897
void cppTerminate(void)
Definition: geany_lcpp.c:144
void cppClearSignature(void)
Definition: geany_lcpp.c:1015
static bool isIgnoreBranch(void)
Definition: geany_lcpp.c:250
static bool handleDirective(const int c, int *macroCorkIndex)
Definition: geany_lcpp.c:467
static bool popConditional(void)
Definition: geany_lcpp.c:316
char ** c_tags_ignore
Definition: geany_lcpp.c:1024
struct sConditionalInfo conditionalInfo
#define isspacetab(c)
Definition: geany_lcpp.c:32
#define stringMatch(s1, s2)
Definition: geany_lcpp.c:31
static int skipOverDComment(void)
Definition: geany_lcpp.c:553
static int skipToEndOfString(bool ignoreBackslash)
Definition: geany_lcpp.c:580
char * cppGetSignature(void)
Definition: geany_lcpp.c:980
void cppBeginStatement(void)
Definition: geany_lcpp.c:153
struct sCppState cppState
static bool directiveHash(const int c)
Definition: geany_lcpp.c:428
static bool isIgnore(void)
Definition: geany_lcpp.c:240
static int directiveDefine(const int c, bool undef)
Definition: geany_lcpp.c:353
static bool readDirective(int c, char *const name, unsigned int maxLength)
Definition: geany_lcpp.c:199
static int skipOverCplusComment(void)
Definition: geany_lcpp.c:536
void cppStartCollectingSignature(void)
Definition: geany_lcpp.c:1003
eState
Definition: geany_lcpp.c:53
@ DRCTV_HASH
Definition: geany_lcpp.c:56
@ DRCTV_UNDEF
Definition: geany_lcpp.c:59
@ DRCTV_IF
Definition: geany_lcpp.c:57
@ DRCTV_DEFINE
Definition: geany_lcpp.c:55
@ DRCTV_NONE
Definition: geany_lcpp.c:54
@ DRCTV_PRAGMA
Definition: geany_lcpp.c:58
static cppState Cpp
Definition: geany_lcpp.c:90
#define cppIsident(c)
Definition: geany_lcpp.h:24
#define cppIsident1(c)
Definition: geany_lcpp.h:31
optionValues Option
Definition: options.c:137
@ EX_LINENUM
Definition: options_p.h:55
bool isLanguageKindEnabled(const langType language, int kindIndex)
Definition: parse.c:2223
#define NULL
Definition: rbtree.h:150
bool isInputHeaderFile(void)
Definition: read.c:216
int getNthPrevCFromInputFile(unsigned int nth, int def)
Definition: read.c:961
unsigned long getInputLineNumber(void)
Definition: read.c:142
int getcFromInputFile(void)
Definition: read.c:923
langType getInputLanguage(void)
Definition: read.c:196
void ungetcToInputFile(int c)
Definition: read.c:813
@ BACKSLASH
Definition: read.h:44
@ STRING_SYMBOL
Definition: read.h:47
@ NEWLINE
Definition: read.h:35
@ CHAR_SYMBOL
Definition: read.h:48
@ TAB
Definition: read.h:38
@ DOUBLE_QUOTE
Definition: read.h:42
@ SPACE
Definition: read.h:34
@ SINGLE_QUOTE
Definition: read.h:43
char * eStrdup(const char *str)
Definition: routines.c:327
void eFree(void *const ptr)
Definition: routines.c:252
bool ignoreAllBranches
Definition: geany_lcpp.c:47
unsigned int nestLevel
Definition: geany_lcpp.c:74
conditionalInfo ifdef[MaxCppNestingLevel]
Definition: geany_lcpp.c:75
enum eState state
Definition: geany_lcpp.c:71
int ungetch2
Definition: geany_lcpp.c:65
int defineMacroKindIndex
Definition: geany_lcpp.c:69
bool resolveRequired
Definition: geany_lcpp.c:66
int ungetch
Definition: geany_lcpp.c:65
struct sCppState::sDirective directive
bool hasAtLiteralStrings
Definition: geany_lcpp.c:67
bool hasCxxRawLiteralStrings
Definition: geany_lcpp.c:68
exCmd locate
Definition: options_p.h:93
struct sTagEntryInfo::@3 extensionFields
unsigned int lineNumberEntry
Definition: entry.h:44
unsigned int isFileScope
Definition: entry.h:45
unsigned int truncateLineAfterTag
Definition: entry.h:47
const char * signature
Definition: entry.h:85
void vStringCopyS(vString *const string, const char *const s)
Definition: vstring.c:213
vString * vStringNewOrClear(vString *const string)
Definition: vstring.c:368
vString * vStringNew(void)
Definition: vstring.c:70
void vStringDelete(vString *const string)
Definition: vstring.c:60
void vStringChop(vString *const string)
Definition: vstring.c:198
#define vStringChar(vs, i)
Definition: vstring.h:29
#define vStringClear(string)
Definition: vstring.h:36
#define vStringLength(vs)
Definition: vstring.h:31
#define vStringValue(vs)
Definition: vstring.h:28
static void vStringPut(vString *const string, const int c)
Definition: vstring.h:101
bool isXtagEnabled(xtagType type)
Definition: xtag.c:235
@ XTAG_FILE_SCOPE
Definition: xtag.h:28
@ XTAG_REFERENCE_TAGS
Definition: xtag.h:32