/*------------------------------------------------------------------ * snprintf_support.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" #include "snprintf_s.h" #define FMT_CHAR 'c' #define FMT_WCHAR 'C' #define FMT_SHORT 'h' #define FMT_INT 'd' #define FMT_LONG 'l' #define FMT_STRING 's' #define FMT_WSTRING 'S' #define FMT_DOUBLE 'g' #define FMT_LDOUBLE 'G' #define FMT_VOID 'p' #define FMT_PCHAR '1' #define FMT_PSHORT '2' #define FMT_PINT '3' #define FMT_PLONG '4' #define MAX_FORMAT_ELEMENTS 16 #define CHK_FORMAT(X,Y) (((X)==(Y))?1:0) #pragma GCC diagnostic ignored "-Wmissing-prototypes" unsigned int parse_format(const char *format, char pformatList[], unsigned int maxFormats) { unsigned int numFormats = 0; unsigned int index = 0; unsigned int start = 0; char lmod = 0; while (index < RSIZE_MAX_STR && format[index] != '\0' && numFormats < maxFormats) { if (format[index] == '%') { start = index; // remember where the format string started // Check for flags switch( format[++index]) { case '\0': continue; // skip - end of format string case '%' : continue; // skip - actually a percent character case '#' : // convert to alternate form case '0' : // zero pad case '-' : // left adjust case ' ' : // pad with spaces case '+' : // force a sign be used index++; // skip the flag character break; } // check for and skip the optional field width while ( format[index] != '\0' && format[index] >= '0' && format[index] <= '9') { index++; } // Check for an skip the optional precision if ( format[index] != '\0' && format[index] == '.') { index++; // skip the period while ( format[index] != '\0' && format[index] >= '0' && format[index] <= '9') { index++; } } // Check for and skip the optional length modifiers lmod = ' '; switch( format[index]) { case 'h' : if ( format[++index] == 'h') { ++index; //also recognize the 'hh' modifier lmod = 'H'; // for char } else { lmod = 'h'; // for short } break; case 'l' : if ( format[++index] == 'l') { ++index; //also recognize the 'll' modifier lmod = 'd'; // for long long } else { lmod = 'l'; // for long } break; case 'L' : lmod = 'L'; break; case 'j' : case 'z' : case 't' : index++; break; } // Recognize and record the actual modifier switch( format[index]) { case 'c' : if ( lmod == 'l') { pformatList[numFormats] = FMT_WCHAR; // store the format character } else { pformatList[numFormats] = FMT_CHAR; } numFormats++; index++; // skip the format character break; case 'd' : case 'i' : // signed case 'o' : case 'u' : // unsigned case 'x' : case 'X' : // unsigned if ( lmod == 'H') { pformatList[numFormats] = FMT_CHAR; // store the format character } else if ( lmod == 'l') { pformatList[numFormats] = FMT_LONG; // store the format character } else if ( lmod == 'h') { pformatList[numFormats] = FMT_SHORT; // store the format character } else{ pformatList[numFormats] = FMT_INT; } numFormats++; index++; // skip the format character break; case 'e' : case 'E' : case 'f' : case 'F' : case 'g' : case 'G' : case 'a' : case 'A' : if ( lmod == 'L') { pformatList[numFormats] = FMT_LDOUBLE; // store the format character } else{ pformatList[numFormats] = FMT_DOUBLE; } numFormats++; index++; // skip the format character break; case 's' : if ( lmod == 'l' || lmod == 'L') { pformatList[numFormats] = FMT_WSTRING; // store the format character } else { pformatList[numFormats] = FMT_STRING; } numFormats++; index++; // skip the format character break; case 'p' : pformatList[numFormats] = FMT_VOID; numFormats++; index++; // skip the format character break; case 'n' : if ( lmod == 'H') { pformatList[numFormats] = FMT_PCHAR; // store the format character } else if ( lmod == 'l') { pformatList[numFormats] = FMT_PLONG; // store the format character } else if ( lmod == 'h') { pformatList[numFormats] = FMT_PSHORT; // store the format character } else{ pformatList[numFormats] = FMT_PINT; } numFormats++; index++; // skip the format character break; case 'm' : // Does not represent an argument in the call stack index++; // skip the format character continue; default: printf("failed to recognize format string ["); for (;start