2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
28 ** no two fileloc's may be equal
32 # include "splintMacros.nf"
34 # include "cscanner.h"
35 # include "cgrammar.h"
37 /*@constant int MCEBASESIZE;@*/
38 # define MCEBASESIZE 8
40 /*@constant int DNE;@*/
44 ** Temporary file used for processing macros.
47 static /*:open:*/ /*@null@*/ FILE *s_macFile
= NULL
;
50 ** mcDisable is set to TRUE when a macro is being processed, so
51 ** its contents are not added to the macrocache again, creating
52 ** a nasty infinite loop.
55 static bool mcDisable
= TRUE
;
56 static void macrocache_grow (macrocache p_s
);
57 static int macrocache_exists (macrocache p_s
, fileloc p_fl
);
58 static void macrocache_processMacro (macrocache p_m
, int p_i
);
61 mce_create (/*@only@*/ fileloc fl
, /*@only@*/ cstring def
, bool comment
)
63 mce m
= (mce
) dmalloc (sizeof (*m
));
65 m
->def
= def
; /*< had a copy here! check this carefully */
67 m
->scomment
= comment
;
71 static void mce_free (/*@only@*/ mce m
)
74 cstring_free (m
->def
);
79 macrocache_create (void)
81 macrocache s
= (macrocache
) dmalloc (sizeof (*s
));
84 s
->nspace
= MCEBASESIZE
;
85 s
->contents
= (mce
*) dmalloc (sizeof (*s
->contents
) * MCEBASESIZE
);
93 macrocache_free (macrocache s
)
97 llassert (s_macFile
== NULL
);
99 for (i
= 0; i
< s
->entries
; i
++)
101 mce_free (s
->contents
[i
]);
109 macrocache_grow (macrocache s
)
112 o_mce
*oldcontents
= s
->contents
;
114 s
->nspace
= MCEBASESIZE
;
115 s
->contents
= (mce
*) dmalloc (sizeof (*s
->contents
) * (s
->entries
+ s
->nspace
));
117 for (i
= 0; i
< s
->entries
; i
++)
119 s
->contents
[i
] = oldcontents
[i
];
126 macrocache_addGenEntry (macrocache s
, /*@only@*/ fileloc fl
,
127 /*@only@*/ cstring def
, bool sup
)
138 if ((i
= macrocache_exists (s
, fl
)) != DNE
)
140 if (cstring_equal (def
, s
->contents
[i
]->def
))
150 ** macro definition contained macro that is expanded
153 ** how do we know which is better??
156 cstring_free (s
->contents
[i
]->def
);
157 s
->contents
[i
]->def
= def
;
164 if (s
->nspace
<= 0) {
169 s
->contents
[s
->entries
] = mce_create (fl
, def
, sup
);
174 macrocache_addEntry (macrocache s
, /*@only@*/ fileloc fl
, /*@only@*/ cstring def
)
176 macrocache_addGenEntry (s
, fl
, def
, FALSE
);
181 macrocache_addComment (macrocache s
, /*@only@*/ fileloc fl
, /*@only@*/ cstring def
)
183 DPRINTF (("Macrocache add comment: %s / %s", fileloc_unparse (fl
), def
));
184 macrocache_addGenEntry (s
, fl
, def
, TRUE
);
188 macrocache_exists (macrocache s
, fileloc fl
)
192 for (i
= 0; i
< s
->entries
; i
++)
194 if (fileloc_equal (s
->contents
[i
]->fl
, fl
))
203 macrocache_unparse (macrocache m
)
205 cstring s
= cstring_undefined
;
208 for (i
= 0; i
< m
->entries
; i
++)
210 fileloc fl
= m
->contents
[i
]->fl
;
211 cstring def
= m
->contents
[i
]->def
;
212 bool defined
= m
->contents
[i
]->defined
;
214 s
= message ("%q%q: %s [%s]\n", s
, fileloc_unparse (fl
), def
,
215 bool_unparse (defined
));
220 # endif /* DEADCODE */
223 ** needs to call lex by hand...yuk!
225 ** modifies gc fileloc!
229 ** there's gotta be a better way of doing this!
232 static void pushString (/*@only@*/ cstring s
)
234 static fileId mtid
= fileId_invalid
;
237 if (s_macFile
== NULL
)
240 mtid
= fileTable_addTempFile (context_fileTable (), FILE_MACROS
, fileId_invalid
);
242 fname
= fileTable_fileName (mtid
);
243 s_macFile
= fileTable_createTempFile (context_fileTable (), fname
, TRUE
);
245 if (s_macFile
== NULL
)
247 llfatalerror (message ("Cannot open tmp file %s needed to process macro: %s",
254 llassert (s_macFile
!= NULL
);
256 check (fseek (s_macFile
, 0, SEEK_CUR
) == 0);
258 floc
= ftell (s_macFile
);
260 if (cstring_length (s
) > 0) {
261 check (fputs (cstring_toCharsSafe (s
), s_macFile
) != EOF
);
264 check (fputc ('\n', s_macFile
) == (int) '\n');
266 check (fseek (s_macFile
, floc
, SEEK_SET
) == 0);
269 (void) c_restart (c_in
);
274 macrocache_processMacro (macrocache m
, int i
)
276 fileloc fl
= m
->contents
[i
]->fl
;
278 m
->contents
[i
]->defined
= TRUE
;
280 if (!fileId_equal (currentFile (), fileloc_fileId (fl
)))
282 g_currentloc
= fileloc_update (g_currentloc
, fl
);
283 context_enterMacroFile ();
287 setLine (fileloc_lineno (fl
));
292 DPRINTF (("Process macro: %s", m
->contents
[i
]->def
));
294 if (m
->contents
[i
]->scomment
)
296 pushString (message ("%s%s%s",
297 cstring_fromChars (BEFORE_COMMENT_MARKER
),
299 cstring_fromChars (AFTER_COMMENT_MARKER
)));
304 bool insup
= context_inSuppressRegion ();
306 pushString (message ("%s %s",
307 cstring_makeLiteralTemp (PPMRCODE
),
308 m
->contents
[i
]->def
));
311 if (context_inSuppressRegion () && !insup
)
315 message ("Macro ends in ignore region: %s", m
->contents
[i
]->def
),
321 context_exitAllClauses ();
322 context_exitMacroCache ();
325 extern void macrocache_processUndefinedElements (macrocache m
)
327 fileloc lastfl
= fileloc_undefined
;
332 DPRINTF (("Processing undefined elements"));
334 if (!context_getFlag (FLG_PARTIAL
))
336 for (i
= 0; i
< m
->entries
; i
++)
338 if (m
->contents
[i
]->defined
)
344 fileloc fl
= m
->contents
[i
]->fl
;
346 if (fileloc_isDefined (lastfl
) && fileloc_sameFile (fl
, lastfl
))
352 if (!fileloc_isLib (fl
))
354 displayScan (message ("checking macros %q",
355 fileloc_outputFilename (fl
)));
362 macrocache_processMacro (m
, i
);
370 extern /*@observer@*/ fileloc
macrocache_processFileElements (macrocache m
, cstring base
)
372 fileloc lastfl
= fileloc_undefined
;
377 for (i
= 0; i
< m
->entries
; i
++)
379 if (m
->contents
[i
]->defined
)
385 fileloc fl
= m
->contents
[i
]->fl
; /* should be dependent! */
386 cstring fb
= fileloc_getBase (fl
);
388 if (cstring_equal (fb
, base
))
391 macrocache_processMacro (m
, i
);
400 void macrocache_finalize (void)
402 if (s_macFile
!= NULL
)
404 check (fileTable_closeFile (context_fileTable (), s_macFile
));