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