yes
[fw/sdcc] / src / SDCCmacro.c
1 /*-------------------------------------------------------------------------
2   SDCCmain.c - Macro support code.
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
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, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include "common.h"
26
27 enum 
28   {
29     MAX_STRING_LENGTH     = 2048,
30     MAX_MACRO_NAME_LENGTH = 128
31   };
32
33 void
34 _evalMacros(char *apinto, hTab *pvals, const char *pfrom, size_t alen)
35 {
36   bool  fdidsomething = FALSE;
37   char  *pinto = apinto;
38   size_t plen = alen;
39   char quote = '\0';
40
41   assert(pinto);
42   assert(pvals);
43   assert(pfrom);
44
45   while (plen && *pfrom) {
46     switch (*pfrom) {
47     case '"':
48     case '\'':
49       quote = *pfrom;
50       ++pfrom;
51       break;
52
53     case '{':
54       {
55         const char *pend = ++pfrom;
56         char name[MAX_MACRO_NAME_LENGTH];
57         const char *pval;
58
59         /* Find the end of macro */
60         while (*pend && *pend != '}') {
61             pend++;
62         }
63         if (*pend != '}') {
64             wassertl(0, "Unterminated macro expansion");
65         }
66
67         /* Pull out the macro name */
68         if (pend - pfrom >= MAX_MACRO_NAME_LENGTH) {
69             wassertl(0, "macro name too long");
70         }
71
72         strncpy(name, pfrom, pend-pfrom);
73         name[pend-pfrom] = '\0';
74
75         /* Look up the value in the hash table */
76         pval = shash_find (pvals, name);
77         
78         if (pval == NULL) {
79           /* Empty macro value */
80           if (quote != '\0') {
81             /* It was a quote */
82             if (pend[1] == quote) {
83               /* Start quote equals end quote: skip both */
84               ++pend;
85             }
86             else {
87               /* Start quote not equals end quote: add both */
88               *pinto++ = quote;
89               --plen;
90             }
91           }
92         }
93         else {
94           if (quote != '\0') {
95             /* It was a quote, add it */
96             *pinto++ = quote;
97           }
98           if (--plen > 0) {
99             /* Replace macro*/
100             strncpy(pinto, pval, plen);
101             pinto += strlen(pval);
102             plen -= plen > strlen(pval) ? strlen(pval) : plen;
103             fdidsomething = TRUE;
104           }
105         }
106
107         pfrom = pend + 1;
108       }
109       break;
110
111     default:
112       if (quote != '\0') {
113         *pinto++ = quote;
114         quote = '\0';
115       }
116
117       if (--plen > 0) {
118         /* Pass through */
119         *pinto++ = *pfrom++;
120         --plen;
121       }
122     }
123   }
124
125   if (!plen) {
126     wassertl(0, "macro expansion too long");
127   }
128     
129   *pinto = '\0';
130
131   /* If we did something then recursivly expand any expanded macros */
132   if (fdidsomething) {
133     char ainto[MAX_STRING_LENGTH];
134     _evalMacros(ainto, pvals, apinto, MAX_STRING_LENGTH);
135     strncpyz(apinto, ainto, alen);
136   }
137 }
138
139 char *
140 mvsprintf(hTab *pvals, const char *pformat, va_list ap)
141 {
142   char ainto[MAX_STRING_LENGTH];
143   char atmp[MAX_STRING_LENGTH];
144
145   /* Recursivly evaluate all the macros in the string */
146   _evalMacros(ainto, pvals, pformat, MAX_STRING_LENGTH);
147   /* Evaluate all the arguments */
148 #if defined(HAVE_VSNPRINTF)
149     if (vsnprintf(atmp, MAX_STRING_LENGTH, ainto, ap) >= MAX_STRING_LENGTH)
150     {
151         fprintf(stderr, "Internal error: mvsprintf output truncated.\n");
152     }
153 #else    
154     {   
155         int wlen; 
156         
157         wlen = vsprintf(atmp, ainto, ap);
158         
159         if (wlen < 0 || wlen >= MAX_STRING_LENGTH)
160         {
161             wassertl(0, "mvsprintf overflowed.");
162         }
163     }
164 #endif    
165     
166   /* Recursivly evaluate any macros that were used as arguments */
167   _evalMacros(ainto, pvals, atmp, MAX_STRING_LENGTH);
168
169   /* Return a copy of the evaluated string. */
170   return Safe_strdup(ainto);
171 }
172
173 char *msprintf(hTab *pvals, const char *pformat, ...)
174 {
175   va_list ap;
176   char *pret;
177
178   va_start(ap, pformat);
179
180   pret = mvsprintf(pvals, pformat, ap);
181
182   va_end(ap);
183
184   return pret;
185 }
186
187 void
188 mfprintf(FILE *fp, hTab *pvals, const char *pformat, ...)
189 {
190   va_list ap;
191   char *p;
192
193   va_start(ap, pformat);
194
195   p = mvsprintf(pvals, pformat, ap);
196
197   va_end(ap);
198
199   fputs(p, fp);
200   Safe_free(p);
201 }