GDB (API)
/home/stan/gdb/src/gdb/common/format.c
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines