Update copyright to LGPL on all files
[dyninst.git] / parseThat / src / utils.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <ctype.h>
35 #include <errno.h>
36
37 #include "config.h"
38 #include "utils.h"
39 #include "log.h"
40
41 #define MAX_RETRY 10
42 #define INITIAL_STRLEN 1024
43
44 char *chomp(char *str)
45 {
46     unsigned tail = strlen(str);
47     if (tail && str[tail - 1] == '\n')
48         str[tail - 1] = '\0';
49     return str;
50 }
51
52 char *fgets_static(FILE *stream)
53 {
54     static int len = 0;
55     static char *buf = NULL;
56
57     if (!buf) {
58         buf = (char *)realloc(NULL, INITIAL_STRLEN);
59         if (!buf) {
60             dlog(ERR, "Could not allocate %d bytes in fgets_static().\n", INITIAL_STRLEN);
61             return NULL;
62         }
63         len = INITIAL_STRLEN;
64     }
65
66     // Initialize the buffer for safety.
67     *buf = '\0';
68
69     int i = 0;
70     int tail = 0;
71     char *retval = NULL;
72     while (!feof(stream)) {
73         errno = 0;
74         retval = fgets(buf + tail, len - tail, stream);
75
76         if (errno == EINTR || errno == ECHILD) {
77             if (config.state != NORMAL) {
78                 errno = 0;
79                 return NULL;
80
81             } else if (errno == EINTR && ++i > MAX_RETRY) {
82                 dlog(ERR, "fgets() has been interrupted %d times.  Giving up.\n", MAX_RETRY);
83                 return NULL;
84             }
85             continue;
86
87         } else if (errno) {
88             dlog(ERR, "Error in fgets(): %s\n", strerror(errno));
89             return NULL;
90
91         } else if (!retval) {
92             return NULL;
93         }
94
95         tail = strlen(buf);
96         if (tail && buf[tail - 1] != '\n' && !feof(stream)) {
97             char *newbuf = (char *)realloc(buf, len * 2);
98             if (!newbuf) {
99                 dlog(ERR, "Could not allocate %d bytes in fgets_static().\n", len * 2);
100                 return NULL;
101             }
102             buf = newbuf;
103             len *= 2;
104
105             continue;
106         }
107         break;
108     }
109     return (*buf ? buf : NULL);
110 }
111
112 char *sprintf_static(const char *fmt, ...)
113 {
114     static int len = 0;
115     static char *buf = NULL;
116
117     if (!buf) {
118         buf = (char *)realloc(NULL, INITIAL_STRLEN);
119         if (!buf) {
120             dlog(ERR, "Could not allocate %d bytes in sprintf_static().\n", INITIAL_STRLEN);
121             return NULL;
122         }
123         len = INITIAL_STRLEN;
124     }
125
126     int retval = len;
127     va_list ap;
128
129     while (1) {
130         va_start(ap, fmt);
131         retval = vsnprintf(buf, len, fmt, ap);
132         va_end(ap);
133
134         if (retval < 0) {
135             dlog(ERR, "vsnprintf() returned %d in sprintf_static().\n", retval);
136             return NULL;
137
138         } else if (len < retval) {
139             char *newbuf = (char *)realloc(buf, ++retval);
140             if (!newbuf) {
141                 dlog(ERR, "Could not allocate %d bytes in sprintf_static().\n", retval);
142                 return NULL;
143             }
144             buf = newbuf;
145             len = retval;
146
147             continue;
148         }
149         break;
150     }
151     return buf;
152 }
153
154 char *strcat_static(const char *s1, const char *s2)
155 {
156     static int len = 0;
157     static char *buf = NULL;
158
159     int maxlen = strlen(s1) + strlen(s2) + 1;
160     bool same_str = (buf == s1);
161
162     if (maxlen > len) {
163         char *newbuf = (char *)realloc(buf, maxlen);
164         if (!newbuf) {
165             dlog(ERR, "Could not allocate %d bytes in strcat_strlen().\n", maxlen);
166             return NULL;
167         }
168         buf = newbuf;
169         len = maxlen;
170     }
171
172     if (!same_str) strcpy(buf, s1);
173     return strcat(buf, s2);
174 }
175
176 char *strcat_static(char *s1, char *s2)
177 {
178   return strcat_static((const char *) s1, (const char *) s2);
179 }
180
181 bool checkStr(const char *s)
182 {
183     if (!(*s)) return true;
184     while (*s) {
185         if (*s == '\"' || isspace(*s))
186             return true;
187         ++s;
188     }
189     return false;
190 }
191
192 char *encodeStr(const char *s)
193 {
194     static unsigned len = 0;
195     static char *buf = NULL;
196
197     unsigned maxlen = 2 + (strlen(s) * 2) + 1;
198     if (len < maxlen) {
199         char *newbuf = (char *)realloc(buf, maxlen);
200         if (!newbuf) {
201             dlog(ERR, "Could not allocate %d bytes in encodeStr().\n", maxlen);
202             return NULL;
203         }
204         buf = newbuf;
205         len = maxlen;
206     }
207
208     if (!checkStr(s))
209         return strcpy(buf, s);
210
211     buf[0] = '\"';
212     unsigned j = 0;
213     for (unsigned i = 0; s[i] != '\0'; ++i) {
214         if (s[i] == '\"' || s[i] == '\\')
215             buf[++j] = '\\';
216         buf[++j] = s[i];
217     }
218     buf[++j] = '\"';
219     buf[++j] = '\0';
220
221     return buf;
222 }
223
224 char *decodeStr(const char *s, char **end_ptr)
225 {
226     static unsigned len = 0;
227     static char *buf = NULL;
228
229     unsigned newlen = strlen(s) + 1;
230     if (newlen > len) {
231         char *newbuf = (char *)realloc(buf, newlen);
232         if (!newbuf) {
233             dlog(ERR, "Could not allocate %d bytes in decodeStr().\n", newlen);
234             return NULL;
235         }
236         len = newlen;
237         buf = newbuf;
238     }
239
240     unsigned i;
241     if (s[0] != '\"') {
242         for (i = 0; s[i] && !isspace(s[i]); ++i);
243         if (i > 0) strncpy(buf, s, i);
244         buf[i] = '\0';
245
246         if (end_ptr) *end_ptr = const_cast<char *>(s + i);
247         return buf;
248     }
249
250     unsigned j = 0;
251     for (i = 1; s[i] != '\"'; ++i) {
252         if (s[i] == '\\') ++i;
253         buf[j++] = s[i];
254     }
255     buf[j] = '\0';
256
257     if (end_ptr) *end_ptr = const_cast<char *>(s + i + 1);
258     return buf;
259 }