GDB (API)
|
00001 /* Parse a printf-style format string. 00002 00003 Copyright (C) 1986-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #ifdef GDBSERVER 00021 #include "server.h" 00022 #else 00023 #include "defs.h" 00024 #endif 00025 00026 #include <string.h> 00027 00028 #include "format.h" 00029 00030 struct format_piece * 00031 parse_format_string (const char **arg) 00032 { 00033 const char *s; 00034 char *f, *string; 00035 const char *prev_start; 00036 const char *percent_loc; 00037 char *sub_start, *current_substring; 00038 struct format_piece *pieces; 00039 int next_frag; 00040 int max_pieces; 00041 enum argclass this_argclass; 00042 00043 s = *arg; 00044 00045 /* Parse the format-control string and copy it into the string STRING, 00046 processing some kinds of escape sequence. */ 00047 00048 f = string = (char *) alloca (strlen (s) + 1); 00049 00050 while (*s != '"' && *s != '\0') 00051 { 00052 int c = *s++; 00053 switch (c) 00054 { 00055 case '\0': 00056 continue; 00057 00058 case '\\': 00059 switch (c = *s++) 00060 { 00061 case '\\': 00062 *f++ = '\\'; 00063 break; 00064 case 'a': 00065 *f++ = '\a'; 00066 break; 00067 case 'b': 00068 *f++ = '\b'; 00069 break; 00070 case 'f': 00071 *f++ = '\f'; 00072 break; 00073 case 'n': 00074 *f++ = '\n'; 00075 break; 00076 case 'r': 00077 *f++ = '\r'; 00078 break; 00079 case 't': 00080 *f++ = '\t'; 00081 break; 00082 case 'v': 00083 *f++ = '\v'; 00084 break; 00085 case '"': 00086 *f++ = '"'; 00087 break; 00088 default: 00089 /* ??? TODO: handle other escape sequences. */ 00090 error (_("Unrecognized escape character \\%c in format string."), 00091 c); 00092 } 00093 break; 00094 00095 default: 00096 *f++ = c; 00097 } 00098 } 00099 00100 /* Terminate our escape-processed copy. */ 00101 *f++ = '\0'; 00102 00103 /* Whether the format string ended with double-quote or zero, we're 00104 done with it; it's up to callers to complain about syntax. */ 00105 *arg = s; 00106 00107 /* Need extra space for the '\0's. Doubling the size is sufficient. */ 00108 00109 current_substring = xmalloc (strlen (string) * 2 + 1000); 00110 00111 max_pieces = strlen (string) + 2; 00112 00113 pieces = (struct format_piece *) 00114 xmalloc (max_pieces * sizeof (struct format_piece)); 00115 00116 next_frag = 0; 00117 00118 /* Now scan the string for %-specs and see what kinds of args they want. 00119 argclass classifies the %-specs so we can give printf-type functions 00120 something of the right size. */ 00121 00122 f = string; 00123 prev_start = string; 00124 while (*f) 00125 if (*f++ == '%') 00126 { 00127 int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0; 00128 int seen_space = 0, seen_plus = 0; 00129 int seen_big_l = 0, seen_h = 0, seen_big_h = 0; 00130 int seen_big_d = 0, seen_double_big_d = 0; 00131 int bad = 0; 00132 00133 /* Skip over "%%", it will become part of a literal piece. */ 00134 if (*f == '%') 00135 { 00136 f++; 00137 continue; 00138 } 00139 00140 sub_start = current_substring; 00141 00142 strncpy (current_substring, prev_start, f - 1 - prev_start); 00143 current_substring += f - 1 - prev_start; 00144 *current_substring++ = '\0'; 00145 00146 pieces[next_frag].string = sub_start; 00147 pieces[next_frag].argclass = literal_piece; 00148 next_frag++; 00149 00150 percent_loc = f - 1; 00151 00152 /* Check the validity of the format specifier, and work 00153 out what argument it expects. We only accept C89 00154 format strings, with the exception of long long (which 00155 we autoconf for). */ 00156 00157 /* The first part of a format specifier is a set of flag 00158 characters. */ 00159 while (*f != '\0' && strchr ("0-+ #", *f)) 00160 { 00161 if (*f == '#') 00162 seen_hash = 1; 00163 else if (*f == '0') 00164 seen_zero = 1; 00165 else if (*f == ' ') 00166 seen_space = 1; 00167 else if (*f == '+') 00168 seen_plus = 1; 00169 f++; 00170 } 00171 00172 /* The next part of a format specifier is a width. */ 00173 while (*f != '\0' && strchr ("0123456789", *f)) 00174 f++; 00175 00176 /* The next part of a format specifier is a precision. */ 00177 if (*f == '.') 00178 { 00179 seen_prec = 1; 00180 f++; 00181 while (*f != '\0' && strchr ("0123456789", *f)) 00182 f++; 00183 } 00184 00185 /* The next part of a format specifier is a length modifier. */ 00186 if (*f == 'h') 00187 { 00188 seen_h = 1; 00189 f++; 00190 } 00191 else if (*f == 'l') 00192 { 00193 f++; 00194 lcount++; 00195 if (*f == 'l') 00196 { 00197 f++; 00198 lcount++; 00199 } 00200 } 00201 else if (*f == 'L') 00202 { 00203 seen_big_l = 1; 00204 f++; 00205 } 00206 /* Decimal32 modifier. */ 00207 else if (*f == 'H') 00208 { 00209 seen_big_h = 1; 00210 f++; 00211 } 00212 /* Decimal64 and Decimal128 modifiers. */ 00213 else if (*f == 'D') 00214 { 00215 f++; 00216 00217 /* Check for a Decimal128. */ 00218 if (*f == 'D') 00219 { 00220 f++; 00221 seen_double_big_d = 1; 00222 } 00223 else 00224 seen_big_d = 1; 00225 } 00226 00227 switch (*f) 00228 { 00229 case 'u': 00230 if (seen_hash) 00231 bad = 1; 00232 /* FALLTHROUGH */ 00233 00234 case 'o': 00235 case 'x': 00236 case 'X': 00237 if (seen_space || seen_plus) 00238 bad = 1; 00239 /* FALLTHROUGH */ 00240 00241 case 'd': 00242 case 'i': 00243 if (lcount == 0) 00244 this_argclass = int_arg; 00245 else if (lcount == 1) 00246 this_argclass = long_arg; 00247 else 00248 this_argclass = long_long_arg; 00249 00250 if (seen_big_l) 00251 bad = 1; 00252 break; 00253 00254 case 'c': 00255 this_argclass = lcount == 0 ? int_arg : wide_char_arg; 00256 if (lcount > 1 || seen_h || seen_big_l) 00257 bad = 1; 00258 if (seen_prec || seen_zero || seen_space || seen_plus) 00259 bad = 1; 00260 break; 00261 00262 case 'p': 00263 this_argclass = ptr_arg; 00264 if (lcount || seen_h || seen_big_l) 00265 bad = 1; 00266 if (seen_prec) 00267 bad = 1; 00268 if (seen_hash || seen_zero || seen_space || seen_plus) 00269 bad = 1; 00270 break; 00271 00272 case 's': 00273 this_argclass = lcount == 0 ? string_arg : wide_string_arg; 00274 if (lcount > 1 || seen_h || seen_big_l) 00275 bad = 1; 00276 if (seen_zero || seen_space || seen_plus) 00277 bad = 1; 00278 break; 00279 00280 case 'e': 00281 case 'f': 00282 case 'g': 00283 case 'E': 00284 case 'G': 00285 if (seen_big_h || seen_big_d || seen_double_big_d) 00286 this_argclass = decfloat_arg; 00287 else if (seen_big_l) 00288 this_argclass = long_double_arg; 00289 else 00290 this_argclass = double_arg; 00291 00292 if (lcount || seen_h) 00293 bad = 1; 00294 break; 00295 00296 case '*': 00297 error (_("`*' not supported for precision or width in printf")); 00298 00299 case 'n': 00300 error (_("Format specifier `n' not supported in printf")); 00301 00302 case '\0': 00303 error (_("Incomplete format specifier at end of format string")); 00304 00305 default: 00306 error (_("Unrecognized format specifier '%c' in printf"), *f); 00307 } 00308 00309 if (bad) 00310 error (_("Inappropriate modifiers to " 00311 "format specifier '%c' in printf"), 00312 *f); 00313 00314 f++; 00315 00316 sub_start = current_substring; 00317 00318 if (lcount > 1 && USE_PRINTF_I64) 00319 { 00320 /* Windows' printf does support long long, but not the usual way. 00321 Convert %lld to %I64d. */ 00322 int length_before_ll = f - percent_loc - 1 - lcount; 00323 00324 strncpy (current_substring, percent_loc, length_before_ll); 00325 strcpy (current_substring + length_before_ll, "I64"); 00326 current_substring[length_before_ll + 3] = 00327 percent_loc[length_before_ll + lcount]; 00328 current_substring += length_before_ll + 4; 00329 } 00330 else if (this_argclass == wide_string_arg 00331 || this_argclass == wide_char_arg) 00332 { 00333 /* Convert %ls or %lc to %s. */ 00334 int length_before_ls = f - percent_loc - 2; 00335 00336 strncpy (current_substring, percent_loc, length_before_ls); 00337 strcpy (current_substring + length_before_ls, "s"); 00338 current_substring += length_before_ls + 2; 00339 } 00340 else 00341 { 00342 strncpy (current_substring, percent_loc, f - percent_loc); 00343 current_substring += f - percent_loc; 00344 } 00345 00346 *current_substring++ = '\0'; 00347 00348 prev_start = f; 00349 00350 pieces[next_frag].string = sub_start; 00351 pieces[next_frag].argclass = this_argclass; 00352 next_frag++; 00353 } 00354 00355 /* Record the remainder of the string. */ 00356 00357 sub_start = current_substring; 00358 00359 strncpy (current_substring, prev_start, f - prev_start); 00360 current_substring += f - prev_start; 00361 *current_substring++ = '\0'; 00362 00363 pieces[next_frag].string = sub_start; 00364 pieces[next_frag].argclass = literal_piece; 00365 next_frag++; 00366 00367 /* Record an end-of-array marker. */ 00368 00369 pieces[next_frag].string = NULL; 00370 pieces[next_frag].argclass = literal_piece; 00371 00372 return pieces; 00373 } 00374 00375 void 00376 free_format_pieces (struct format_piece *pieces) 00377 { 00378 if (!pieces) 00379 return; 00380 00381 /* We happen to know that all the string pieces are in the block 00382 pointed to by the first string piece. */ 00383 if (pieces[0].string) 00384 xfree (pieces[0].string); 00385 00386 xfree (pieces); 00387 } 00388 00389 void 00390 free_format_pieces_cleanup (void *ptr) 00391 { 00392 void **location = ptr; 00393 00394 if (location == NULL) 00395 return; 00396 00397 if (*location != NULL) 00398 { 00399 free_format_pieces (*location); 00400 *location = NULL; 00401 } 00402 } 00403