]> andersk Git - splint.git/blob - src/lh.c
Merged code tree with Dave Evans's version. Many changes to numberous to list....
[splint.git] / src / lh.c
1 /*
2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
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.
10 ** 
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.
15 ** 
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.
19 **
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
23 */
24 /*
25 ** lh.c
26 **
27 **  MODULE DESCRIPTION:
28 **
29 **      This module contains the I/O routines for writing out the .lh file
30 **      generated from the .lcl file.
31 **
32 **  AUTHORS:
33 **
34 **      Gary Feldman, Technical Languages and Environments, DECspec project
35 **      Yang Meng Tan, MIT.
36 **
37 **  CREATION DATE:  9 April 91
38 **
39 **      The lh.c module controls formatting policy.
40 */
41
42 # include "lclintMacros.nf"
43 # include "llbasic.h"
44 # include "osd.h"
45 # include "herald.h"
46 # include "lh.h"
47 # include "llmain.h"
48
49 /*@constant static char TABCH; @*/
50 # define TABCH          '\1'
51
52 /*@constant static char TABINCH; @*/
53 # define TABINCH        '\2'
54
55 /*@constant static char TABOUTCH; @*/
56 # define TABOUTCH       '\3'
57
58 /*
59   # define TAB                  fputc (TABCH,   LhFile.f);
60   # define TABIN                fputc (TABINCH,         LhFile.f);
61   # define TABOUT               fputc (TABOUTCH, LhFile.f);
62 */
63
64 /*@private@*/ typedef struct
65 {
66   /*@open@*/ /*@dependent@*/ /*@null@*/ /*@reldef@*/ FILE *f;
67   /*@reldef@*/ cstring name;
68 } outFile;
69
70 static bool genLh;
71 static outFile LhFile;
72 static bool needIncludeBool = FALSE;
73
74 /*
75 **
76 **  FORWARD FUNCTIONS
77 **
78 */
79
80 /* static int colpos (int startcol, cstring line); */
81
82 static cstring lhTypeSpecNode (lclTypeSpecNode p_typespec);
83 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr p_x);
84 static /*@only@*/ cstring lhDeclaratorNode (declaratorNode p_x);
85
86 static /*@open@*/ /*@dependent@*/ /*@null@*/ FILE *out_open (cstring name, cstring suffix)
87      /*@modifies fileSystem@*/
88 {
89   cstring fullname = cstring_concat (name, suffix);
90   FILE *ret = fopen (cstring_toCharsSafe (fullname), "w+");
91   cstring_free (fullname);
92   return ret;
93 }
94
95 /*@only@*/ cstring 
96 lhFunction (lclTypeSpecNode lclTypeSpec, declaratorNode declarator)
97 {
98   cstring s;
99
100   if (!genLh)
101     return cstring_undefined;
102   
103   s = message ("extern %q\1%q;", lhTypeSpecNode (lclTypeSpec),
104                lhDeclaratorNode (declarator));
105   
106   return s;
107 }
108
109 static /*@only@*/ cstring
110 lhDeclaratorNode (declaratorNode x)
111 {
112   return (lhTypeExpr (x->type));
113 }
114
115 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr x)
116 {
117   cstring s = cstring_undefined; /* print out types in order of appearance in source */
118   paramNodeList params;
119   int i;
120
121   if (x != (typeExpr) 0)
122     {
123       cstring front = cstring_undefined;
124       cstring back  = cstring_undefined;
125
126       for (i = x->wrapped; i >= 1; i--)
127         {
128           front = cstring_appendChar (front, '(');
129           back  = cstring_appendChar (back, ')');
130         }
131
132       switch (x->kind)
133         {
134         case TEXPR_BASE:
135           s = message ("%q%s", s, ltoken_getRawString (x->content.base));
136           break;
137         case TEXPR_PTR:
138           s = message ("%q*%q", s, lhTypeExpr (x->content.pointer));
139           break;
140         case TEXPR_ARRAY:
141           s = message ("%q%q[%q]", s, 
142                        lhTypeExpr (x->content.array.elementtype),
143                        termNode_unparse (x->content.array.size));
144           break;
145         case TEXPR_FCN:
146           s = message ("%q%q (", s, lhTypeExpr (x->content.function.returntype));
147           params = x->content.function.args;
148
149           if (!paramNodeList_empty (params))
150             {
151               s = message ("%q%q", s, 
152                            paramNodeList_unparseComments (x->content.function.args));
153             }
154
155           s = message ("%q)", s);
156           break;
157         }
158       s = message ("%q%q%q", front, s, back);
159     }
160   else
161     {
162       s = cstring_makeLiteral ("?");
163     }
164
165   return s;
166 }
167
168 extern void
169 lhForwardStruct (ltoken t)
170 {
171   if (!genLh)
172     return;
173
174   lhOutLine (message ("struct %s;", ltoken_unparse (t)));
175 }
176
177
178 extern void
179 lhForwardUnion (ltoken t)
180 {
181   if (!genLh)
182     return;
183
184   lhOutLine (message ("union %s;", ltoken_unparse (t)));
185 }
186
187 extern /*@only@*/ cstring 
188 lhType (typeNode t)
189 {
190   if (!genLh)
191     return cstring_undefined;
192
193   if (t->kind == TK_EXPOSED)
194     {
195       exposedNode n = t->content.exposed;
196
197       if (n != (exposedNode) 0)
198         {
199           if (declaratorInvNodeList_size (n->decls) == 0)
200             {
201               /* 
202               ** Forward struct or union declaration
203               */
204
205               return (cstring_appendChar (lhTypeSpecNode (n->type), ';'));
206             }
207           else
208             {
209               cstring s = cstring_undefined;
210
211               declaratorInvNodeList_elements (n->decls, d)
212                 {
213                   cstring name = declaratorNode_unparse (d->declarator);
214                   cstring pname = declaratorNode_unparseCode (d->declarator); 
215                   
216                   s = message ("%q\n# ifndef EXPOSED_TYPE_%q\ntypedef %q %q;\n# endif\n", 
217                                s, pname, lhTypeSpecNode (n->type), name);
218                 } end_declaratorInvNodeList_elements;
219               
220               return s;
221             }
222         }
223     }
224
225   return cstring_undefined;
226 }
227
228 static /*@only@*/ cstring 
229 lhTypeSpecNode (lclTypeSpecNode typespec)
230 {
231   if (!genLh)
232     {
233       return cstring_undefined;
234     }
235
236   return (lclTypeSpecNode_unparseComments (typespec));
237 }
238
239 /*@only@*/ cstring
240 lhVarDecl (lclTypeSpecNode lclTypeSpec, initDeclNodeList initDecls,
241            qualifierKind qualifier)
242 {
243   bool first = TRUE;
244   cstring s;
245
246   if (!genLh)
247     return cstring_undefined;
248
249   s = cstring_makeLiteral ("extern");
250
251   switch (qualifier)
252     {
253     case QLF_NONE:
254       break;
255     case QLF_CONST:
256       s = message ("%q const", s);
257       break;
258     case QLF_VOLATILE:
259       s = message ("%q volatile", s);
260       break;
261     default:                    /* ignore it */
262       break;
263     }
264   
265   s = message ("%q %q\1", s, lhTypeSpecNode (lclTypeSpec));
266
267   initDeclNodeList_elements (initDecls, i)
268   {
269     if (first)
270       {
271         s = message ("%q %q", s, declaratorNode_unparse (i->declarator));
272         first = FALSE;
273       }
274     else
275       {
276         s = message ("%q, %q", s, declaratorNode_unparse (i->declarator));
277       }
278   } end_initDeclNodeList_elements;
279   
280   return (message ("%q;", s));
281 }
282
283 extern void
284 lhCleanup (void)
285    /*@modifies fileSystem@*/
286 {
287   if (!genLh)
288     {
289       return;
290     }
291   else
292     {
293       FILE *f;
294       int c, col = 0, tabcol = 0;
295       cstring fullname;
296
297       f = out_open (LhFile.name, LH_EXTENSION);
298       llassert (LhFile.f != NULL);
299       
300       fullname = cstring_concat (LhFile.name, LHTMP_EXTENSION);
301
302       if (f == NULL)
303         {
304           /*@i25534  check this!  does it report the right filename? */
305           lldiagmsg (message ("Cannot open lh file for output: %s", 
306                               fullname));
307         }
308       else
309         {
310           fprintf (f, "/* Output from %s */\n", LCL_PARSE_VERSION);
311
312           rewind (LhFile.f);
313
314           while (EOF != (c = getc (LhFile.f)))
315             {
316               switch (c)
317                 {
318                 case TABCH:
319                   if (col == 0)
320                     {
321                       if (tabcol > 0)
322                         fprintf (f, "%*s", tabcol, "");
323                     }
324                   else
325                     {
326                       check (fputc (' ', f) == (int) ' ');
327                     }
328                   /*@switchbreak@*/ break;
329                   
330                 case TABINCH:
331                   tabcol += 4;
332                   /*@switchbreak@*/ break;
333                   
334                 case TABOUTCH:
335                   tabcol -= 4;
336                   /*@switchbreak@*/ break;
337                   
338                 case '\n':
339                   col = 0;
340                   check (fputc (c, f) == (int) c);
341                   /*@switchbreak@*/ break;
342                   
343                 default:
344                   col++;
345                   check (fputc (c, f) == (int) c);
346                   /*@switchbreak@*/ break;
347                 }
348             }
349
350           check (fclose (f) == 0);
351           check (fclose (LhFile.f) == 0);
352
353           (void) osd_unlink (fullname);
354           LhFile.f = NULL;
355         }
356       
357       cstring_free (fullname);
358     }
359 }
360
361 /* Write an #include of bool.h if we have't done so already.  */
362 extern void
363 lhIncludeBool (void)
364 {
365   needIncludeBool = TRUE;
366 }
367
368 /*
369 **++
370 **  FUNCTIONAL DESCRIPTION:
371 **
372 **      Initialize the .lh file processing.
373 **
374 **  FORMAL PARAMETERS:
375 **
376 **      source * f: The source file, from which we compute the name of
377 **      the .lh file.
378 **
379 **      bool outputLh: If true, produce a .lh file, otherwise don't.
380 **
381 **  RETURN VALUE:
382 **
383 **      None
384 **
385 **  SIDE EFFECTS:
386 **
387 **      The .lh file may be opened.
388 **
389 **
390 **--
391 */
392
393 void lhInit (inputStream  f) /*@globals undef LhFile; @*/
394 {
395   static bool lherror = FALSE;
396   
397   genLh = context_msgLh ();
398   needIncludeBool = FALSE;
399
400   if (!genLh)
401     {
402       return;
403     }
404   
405   LhFile.name = LSLRootName (inputStream_fileName (f));
406   LhFile.f = out_open (LhFile.name, LHTMP_EXTENSION);
407
408   if (LhFile.f == NULL)
409     {
410       genLh = FALSE;
411       if (!lherror)
412         {
413           lclplainerror (message ("Cannot write temporary %s file: %s%s", 
414                                   LH_EXTENSION,
415                                   LhFile.name,
416                                   LHTMP_EXTENSION));
417           lherror = TRUE;
418         }
419     } 
420
421
422 void lhOutLine (/*@only@*/ cstring s)
423 {
424   if (genLh)
425     {
426       llassert (LhFile.f != NULL);
427
428       if (cstring_length (s) > 0) 
429         {
430           check (fputs (cstring_toCharsSafe (s), LhFile.f) != EOF); 
431         }
432
433       check (fputc ('\n', LhFile.f) == (int) '\n'); 
434     }
435
436   cstring_free (s);
437 }
438
439 void lhExternals (interfaceNodeList x)
440 {
441   if (genLh)
442     {
443       llassert (LhFile.f != NULL);
444
445       /*
446       ** Need to make sure all standard library includes come first.
447       */
448
449       interfaceNodeList_elements (x, el)
450         {
451           if (el->kind == INF_IMPORTS)
452             {
453               importNodeList imps = el->content.imports;
454
455               importNodeList_elements (imps, il)
456                 {
457                   if (il->kind == IMPBRACKET)
458                     {
459                       lhOutLine (message ("# include <%s.h>", 
460                                           ltoken_getRawString (il->val)));
461                     }
462                 } end_importNodeList_elements ;
463             }
464         } end_interfaceNodeList_elements;
465
466       lhOutLine (cstring_makeLiteral ("# include \"bool.h\""));
467       
468       interfaceNodeList_elements (x, el)
469         {
470           if (el->kind == INF_IMPORTS)
471             {
472               importNodeList imps = el->content.imports;
473
474               importNodeList_elements (imps, il)
475                 {
476                   if (il->kind != IMPBRACKET)
477                     {
478                       lhOutLine (message ("# include \"%s.h\"", 
479                                           ltoken_getRawString (il->val)));
480                     }
481                 } end_importNodeList_elements ;
482             }
483         } end_interfaceNodeList_elements;
484
485       lhOutLine (cstring_undefined);
486     }
487 }
488
489
490
This page took 0.072905 seconds and 5 git commands to generate.