|      1 /* | 
        | 
|      2 	Copyright 2014, 2015 Teemu Piippo | 
        | 
|      3 	All rights reserved. | 
        | 
|      4  | 
        | 
|      5 	Redistribution and use in source and binary forms, with or without | 
        | 
|      6 	modification, are permitted provided that the following conditions | 
        | 
|      7 	are met: | 
        | 
|      8  | 
        | 
|      9 	1. Redistributions of source code must retain the above copyright | 
        | 
|     10 	   notice, this list of conditions and the following disclaimer. | 
        | 
|     11 	2. Redistributions in binary form must reproduce the above copyright | 
        | 
|     12 	   notice, this list of conditions and the following disclaimer in the | 
        | 
|     13 	   documentation and/or other materials provided with the distribution. | 
        | 
|     14 	3. Neither the name of the copyright holder nor the names of its | 
        | 
|     15 	   contributors may be used to endorse or promote products derived from | 
        | 
|     16 	   this software without specific prior written permission. | 
        | 
|     17  | 
        | 
|     18 	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
        | 
|     19 	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 
        | 
|     20 	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | 
        | 
|     21 	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER | 
        | 
|     22 	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
        | 
|     23 	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
        | 
|     24 	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
        | 
|     25 	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 
        | 
|     26 	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
        | 
|     27 	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
        | 
|     28 	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
        | 
|     29 */ | 
        | 
|     30  | 
        | 
|     31 #include <cstdio> | 
        | 
|     32 #include "format.h" | 
        | 
|     33  | 
        | 
|     34 // ------------------------------------------------------------------------------------------------- | 
        | 
|     35 // | 
        | 
|     36 // Throws an error while formatting the string | 
        | 
|     37 // | 
        | 
|     38 static auto format_error (String fmtstr, const String errdescribe, int pos) -> void | 
        | 
|     39 { | 
        | 
|     40 	fmtstr.replace ("\n", " "); | 
        | 
|     41 	fmtstr.replace ("\t", " "); | 
        | 
|     42 	String errmsg ("With format string:\n" + fmtstr + "\n"); | 
        | 
|     43  | 
        | 
|     44 	for (int x = 0; x < pos; ++x) | 
        | 
|     45 		errmsg += "-"; | 
        | 
|     46  | 
        | 
|     47 	errmsg += "^\n" + errdescribe; | 
        | 
|     48 	throw std::logic_error (errmsg.std_string()); | 
        | 
|     49 } | 
        | 
|     50  | 
        | 
|     51 // ------------------------------------------------------------------------------------------------- | 
        | 
|     52 // | 
        | 
|     53 // Main formatter algorithm. | 
        | 
|     54 // | 
        | 
|     55 auto format_args (const String& fmtstr, const Vector<String>& args) -> String | 
        | 
|     56 { | 
        | 
|     57 	String fmt = fmtstr; | 
        | 
|     58 	int pos = 0; | 
        | 
|     59  | 
        | 
|     60 	while ((pos = fmt.find ("%", pos)) != -1) | 
        | 
|     61 	{ | 
        | 
|     62 		if (fmt[pos + 1] == '%') | 
        | 
|     63 		{ | 
        | 
|     64 			fmt.replace (pos, 2, "%"); | 
        | 
|     65 			pos++; | 
        | 
|     66 			continue; | 
        | 
|     67 		} | 
        | 
|     68  | 
        | 
|     69 		int ofs = 1; | 
        | 
|     70 		char mod = '\0'; | 
        | 
|     71  | 
        | 
|     72 		// handle modifiers | 
        | 
|     73 		if (fmt[pos + ofs] == 's' or fmt[pos + ofs] == 'x' or fmt[pos + ofs] == 'd') | 
        | 
|     74 		{ | 
        | 
|     75 			mod = fmt[pos + ofs]; | 
        | 
|     76 			ofs++; | 
        | 
|     77 		} | 
        | 
|     78  | 
        | 
|     79 		if (fmt[pos + ofs] < '1' or fmt[pos + ofs] > '9') | 
        | 
|     80 		{ | 
        | 
|     81 			format_error (fmtstr, "bad format string, expected non-zero digit with " | 
        | 
|     82 				"optional modifier after '%%'", pos); | 
        | 
|     83 		} | 
        | 
|     84  | 
        | 
|     85 		int i = fmt[pos + ofs] - '0'; | 
        | 
|     86  | 
        | 
|     87 		if (i > args.size()) | 
        | 
|     88 			format_error (fmtstr, String ("Format argument #") + i + " used but not defined.", pos); | 
        | 
|     89  | 
        | 
|     90 		String replacement = args[i - 1]; | 
        | 
|     91  | 
        | 
|     92 		switch (mod) | 
        | 
|     93 		{ | 
        | 
|     94 		case 's': replacement = (replacement == "1") ? "" : "s";      break; | 
        | 
|     95 		case 'd': replacement.sprintf ("%d", replacement[0]);         break; | 
        | 
|     96 		case 'x': replacement.sprintf ("0x%x", replacement.to_int()); break; | 
        | 
|     97 		default: break; | 
        | 
|     98 		} | 
        | 
|     99  | 
        | 
|    100 		fmt.replace (pos, 1 + ofs, replacement); | 
        | 
|    101 		pos += replacement.length(); | 
        | 
|    102 	} | 
        | 
|    103  | 
        | 
|    104 	return fmt; | 
        | 
|    105 } | 
        | 
|    106  | 
        |