Use 'ao-dbg' instead of 's51' to communicate with TeleMetrum
[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 > 0 && *pfrom) {
46     switch (*pfrom) {
47     case '"':
48     case '\'':
49       if (quote != '\0') {
50         /* write previous quote */
51         *pinto++ = quote;
52         --plen;
53       }
54       quote = *pfrom++;
55       break;
56
57     case '{':
58       {
59         const char *pend = ++pfrom;
60         char name[MAX_MACRO_NAME_LENGTH];
61         const char *pval;
62
63         /* Find the end of macro */
64         while (*pend && '}' != *pend) {
65           pend++;
66         }
67         if ('}' != *pend) {
68           wassertl(0, "Unterminated macro expansion");
69         }
70
71         /* Pull out the macro name */
72         if (pend - pfrom >= MAX_MACRO_NAME_LENGTH) {
73           wassertl(0, "macro name too long");
74         }
75
76         strncpy(name, pfrom, pend - pfrom);
77         name[pend - pfrom] = '\0';
78
79         /* Look up the value in the hash table */
80         pval = shash_find (pvals, name);
81
82         if (NULL == pval) {
83           /* Empty macro value */
84           if ('\0' != quote) {
85             /* It was a quote */
86             if (pend[1] == quote) {
87               /* Start quote equals end quote: skip both */
88               ++pend;
89             }
90             else {
91               /* Start quote not equals end quote: add both */
92               *pinto++ = quote;
93               --plen;
94             }
95           }
96         }
97         else {
98           if ('\0' != quote) {
99             /* It was a quote, add it */
100             *pinto++ = quote;
101             --plen;
102           }
103           if (plen > 0) {
104             /* Replace macro */
105             strncpy(pinto, pval, plen);
106             pinto += strlen(pval);
107             plen -= plen > strlen(pval) ? strlen(pval) : plen;
108             fdidsomething = TRUE;
109           }
110         }
111
112         quote = '\0';
113         pfrom = pend + 1;
114       }
115       break;
116
117     default:
118       if ('\0' != quote) {
119         *pinto++ = quote;
120         --plen;
121         quote = '\0';
122       }
123
124       if (plen > 0) {
125         /* Pass through */
126         *pinto++ = *pfrom++;
127         --plen;
128       }
129     }
130   }
131
132   if (plen > 0 && '\0' != quote) {
133     *pinto++ = quote;
134     --plen;
135   }
136
137   if (plen <= 0) {
138     wassertl(0, "macro expansion too long");
139   }
140
141   *pinto = '\0';
142
143   /* If we did something then recursivly expand any expanded macros */
144   if (fdidsomething) {
145     char ainto[MAX_STRING_LENGTH];
146     _evalMacros(ainto, pvals, apinto, MAX_STRING_LENGTH);
147     strncpyz(apinto, ainto, alen);
148   }
149 }
150
151 char *
152 mvsprintf(hTab *pvals, const char *pformat, va_list ap)
153 {
154   char ainto[MAX_STRING_LENGTH];
155   char atmp[MAX_STRING_LENGTH];
156
157   /* Recursivly evaluate all the macros in the string */
158   _evalMacros(ainto, pvals, pformat, MAX_STRING_LENGTH);
159   /* Evaluate all the arguments */
160 #if defined(HAVE_VSNPRINTF)
161     if (vsnprintf(atmp, MAX_STRING_LENGTH, ainto, ap) >= MAX_STRING_LENGTH)
162     {
163         fprintf(stderr, "Internal error: mvsprintf output truncated.\n");
164     }
165 #else
166     {
167         int wlen; 
168         
169         wlen = vsprintf(atmp, ainto, ap);
170         
171         if (wlen < 0 || wlen >= MAX_STRING_LENGTH)
172         {
173             wassertl(0, "mvsprintf overflowed.");
174         }
175     }
176 #endif
177
178   /* Recursivly evaluate any macros that were used as arguments */
179   _evalMacros(ainto, pvals, atmp, MAX_STRING_LENGTH);
180
181   /* Return a copy of the evaluated string. */
182   return Safe_strdup(ainto);
183 }
184
185 char *msprintf(hTab *pvals, const char *pformat, ...)
186 {
187   va_list ap;
188   char *pret;
189
190   va_start(ap, pformat);
191
192   pret = mvsprintf(pvals, pformat, ap);
193
194   va_end(ap);
195
196   return pret;
197 }
198
199 void
200 mfprintf(FILE *fp, hTab *pvals, const char *pformat, ...)
201 {
202   va_list ap;
203   char *p;
204
205   va_start(ap, pformat);
206
207   p = mvsprintf(pvals, pformat, ap);
208
209   va_end(ap);
210
211   fputs(p, fp);
212   Safe_free(p);
213 }