aboutsummaryrefslogtreecommitdiffstats
path: root/lib/vsprintf.c
diff options
context:
space:
mode:
authorLai Jiangshan <laijs@cn.fujitsu.com>2009-03-06 11:21:46 -0500
committerIngo Molnar <mingo@elte.hu>2009-03-06 11:39:04 -0500
commit4370aa4aa75391a5e2e06bccb0919109f725ed8e (patch)
tree602a6ea4e404d17e610d4a9979d615ff2d0bfd98 /lib/vsprintf.c
parentf036be96dd9ce442ffb9ab33e3c165f5178815c0 (diff)
vsprintf: add binary printf
Impact: add new APIs for binary trace printk infrastructure vbin_printf(): write args to binary buffer, string is copied when "%s" is occurred. bstr_printf(): read from binary buffer for args and format a string [fweisbec@gmail.com: rebase] Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> LKML-Reference: <1236356510-8381-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r--lib/vsprintf.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 0fbd0121d91d..3543bbe8b1bc 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1058,6 +1058,448 @@ int sprintf(char * buf, const char *fmt, ...)
1058} 1058}
1059EXPORT_SYMBOL(sprintf); 1059EXPORT_SYMBOL(sprintf);
1060 1060
1061#ifdef CONFIG_BINARY_PRINTF
1062/*
1063 * bprintf service:
1064 * vbin_printf() - VA arguments to binary data
1065 * bstr_printf() - Binary data to text string
1066 */
1067
1068/**
1069 * vbin_printf - Parse a format string and place args' binary value in a buffer
1070 * @bin_buf: The buffer to place args' binary value
1071 * @size: The size of the buffer(by words(32bits), not characters)
1072 * @fmt: The format string to use
1073 * @args: Arguments for the format string
1074 *
1075 * The format follows C99 vsnprintf, except %n is ignored, and its argument
1076 * is skiped.
1077 *
1078 * The return value is the number of words(32bits) which would be generated for
1079 * the given input.
1080 *
1081 * NOTE:
1082 * If the return value is greater than @size, the resulting bin_buf is NOT
1083 * valid for bstr_printf().
1084 */
1085int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
1086{
1087 char *str, *end;
1088 int qualifier;
1089
1090 str = (char *)bin_buf;
1091 end = (char *)(bin_buf + size);
1092
1093#define save_arg(type) \
1094do { \
1095 if (sizeof(type) == 8) { \
1096 unsigned long long value; \
1097 str = PTR_ALIGN(str, sizeof(u32)); \
1098 value = va_arg(args, unsigned long long); \
1099 if (str + sizeof(type) <= end) { \
1100 *(u32 *)str = *(u32 *)&value; \
1101 *(u32 *)(str + 4) = *((u32 *)&value + 1); \
1102 } \
1103 } else { \
1104 unsigned long value; \
1105 str = PTR_ALIGN(str, sizeof(type)); \
1106 value = va_arg(args, int); \
1107 if (str + sizeof(type) <= end) \
1108 *(typeof(type) *)str = (type)value; \
1109 } \
1110 str += sizeof(type); \
1111} while (0)
1112
1113 for (; *fmt ; ++fmt) {
1114 if (*fmt != '%')
1115 continue;
1116
1117repeat:
1118 /* parse flags */
1119 ++fmt; /* this also skips first '%' */
1120 if (*fmt == '-' || *fmt == '+' || *fmt == ' '
1121 || *fmt == '#' || *fmt == '0')
1122 goto repeat;
1123
1124 /* parse field width */
1125 if (isdigit(*fmt))
1126 skip_atoi(&fmt);
1127 else if (*fmt == '*') {
1128 ++fmt;
1129 /* it's the next argument */
1130 save_arg(int);
1131 }
1132
1133 /* parse the precision */
1134 if (*fmt == '.') {
1135 ++fmt;
1136 if (isdigit(*fmt))
1137 skip_atoi(&fmt);
1138 else if (*fmt == '*') {
1139 ++fmt;
1140 /* it's the next argument */
1141 save_arg(int);
1142 }
1143 }
1144
1145 /* parse the conversion qualifier */
1146 qualifier = -1;
1147 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
1148 *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
1149 qualifier = *fmt;
1150 ++fmt;
1151 if (qualifier == 'l' && *fmt == 'l') {
1152 qualifier = 'L';
1153 ++fmt;
1154 }
1155 }
1156
1157 /* parse format type */
1158 switch (*fmt) {
1159 case 'c':
1160 save_arg(char);
1161 continue;
1162 case 's': {
1163 /* save the string argument */
1164 const char *save_str = va_arg(args, char *);
1165 size_t len;
1166 if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
1167 || (unsigned long)save_str < PAGE_SIZE)
1168 save_str = "<NULL>";
1169 len = strlen(save_str);
1170 if (str + len + 1 < end)
1171 memcpy(str, save_str, len + 1);
1172 str += len + 1;
1173 continue;
1174 }
1175 case 'p':
1176 save_arg(void *);
1177 /* skip all alphanumeric pointer suffixes */
1178 while (isalnum(fmt[1]))
1179 fmt++;
1180 continue;
1181 case 'n': {
1182 /* skip %n 's argument */
1183 void *skip_arg;
1184 if (qualifier == 'l')
1185 skip_arg = va_arg(args, long *);
1186 else if (qualifier == 'Z' || qualifier == 'z')
1187 skip_arg = va_arg(args, size_t *);
1188 else
1189 skip_arg = va_arg(args, int *);
1190 continue;
1191 }
1192 case 'o':
1193 case 'x':
1194 case 'X':
1195 case 'd':
1196 case 'i':
1197 case 'u':
1198 /* save arg for case: 'o', 'x', 'X', 'd', 'i', 'u' */
1199 if (qualifier == 'L')
1200 save_arg(long long);
1201 else if (qualifier == 'l')
1202 save_arg(unsigned long);
1203 else if (qualifier == 'Z' || qualifier == 'z')
1204 save_arg(size_t);
1205 else if (qualifier == 't')
1206 save_arg(ptrdiff_t);
1207 else if (qualifier == 'h')
1208 save_arg(short);
1209 else
1210 save_arg(int);
1211 continue;
1212 default:
1213 if (!*fmt)
1214 --fmt;
1215 continue;
1216 }
1217 }
1218#undef save_arg
1219
1220 return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
1221}
1222EXPORT_SYMBOL_GPL(vbin_printf);
1223
1224/**
1225 * bstr_printf - Format a string from binary arguments and place it in a buffer
1226 * @buf: The buffer to place the result into
1227 * @size: The size of the buffer, including the trailing null space
1228 * @fmt: The format string to use
1229 * @bin_buf: Binary arguments for the format string
1230 *
1231 * This function like C99 vsnprintf, but the difference is that vsnprintf gets
1232 * arguments from stack, and bstr_printf gets arguments from @bin_buf which is
1233 * a binary buffer that generated by vbin_printf.
1234 *
1235 * The format follows C99 vsnprintf, but has some extensions:
1236 * %pS output the name of a text symbol
1237 * %pF output the name of a function pointer
1238 * %pR output the address range in a struct resource
1239 * %n is ignored
1240 *
1241 * The return value is the number of characters which would
1242 * be generated for the given input, excluding the trailing
1243 * '\0', as per ISO C99. If you want to have the exact
1244 * number of characters written into @buf as return value
1245 * (not including the trailing '\0'), use vscnprintf(). If the
1246 * return is greater than or equal to @size, the resulting
1247 * string is truncated.
1248 */
1249int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
1250{
1251 unsigned long long num;
1252 int base;
1253 char *str, *end, c;
1254 const char *args = (const char *)bin_buf;
1255
1256 int flags;
1257 int field_width;
1258 int precision;
1259 int qualifier;
1260
1261 if (unlikely((int) size < 0)) {
1262 /* There can be only one.. */
1263 static char warn = 1;
1264 WARN_ON(warn);
1265 warn = 0;
1266 return 0;
1267 }
1268
1269 str = buf;
1270 end = buf + size;
1271
1272#define get_arg(type) \
1273({ \
1274 typeof(type) value; \
1275 if (sizeof(type) == 8) { \
1276 args = PTR_ALIGN(args, sizeof(u32)); \
1277 *(u32 *)&value = *(u32 *)args; \
1278 *((u32 *)&value + 1) = *(u32 *)(args + 4); \
1279 } else { \
1280 args = PTR_ALIGN(args, sizeof(type)); \
1281 value = *(typeof(type) *)args; \
1282 } \
1283 args += sizeof(type); \
1284 value; \
1285})
1286
1287 /* Make sure end is always >= buf */
1288 if (end < buf) {
1289 end = ((void *)-1);
1290 size = end - buf;
1291 }
1292
1293 for (; *fmt ; ++fmt) {
1294 if (*fmt != '%') {
1295 if (str < end)
1296 *str = *fmt;
1297 ++str;
1298 continue;
1299 }
1300
1301 /* process flags */
1302 flags = 0;
1303repeat:
1304 ++fmt; /* this also skips first '%' */
1305 switch (*fmt) {
1306 case '-':
1307 flags |= LEFT;
1308 goto repeat;
1309 case '+':
1310 flags |= PLUS;
1311 goto repeat;
1312 case ' ':
1313 flags |= SPACE;
1314 goto repeat;
1315 case '#':
1316 flags |= SPECIAL;
1317 goto repeat;
1318 case '0':
1319 flags |= ZEROPAD;
1320 goto repeat;
1321 }
1322
1323 /* get field width */
1324 field_width = -1;
1325 if (isdigit(*fmt))
1326 field_width = skip_atoi(&fmt);
1327 else if (*fmt == '*') {
1328 ++fmt;
1329 /* it's the next argument */
1330 field_width = get_arg(int);
1331 if (field_width < 0) {
1332 field_width = -field_width;
1333 flags |= LEFT;
1334 }
1335 }
1336
1337 /* get the precision */
1338 precision = -1;
1339 if (*fmt == '.') {
1340 ++fmt;
1341 if (isdigit(*fmt))
1342 precision = skip_atoi(&fmt);
1343 else if (*fmt == '*') {
1344 ++fmt;
1345 /* it's the next argument */
1346 precision = get_arg(int);
1347 }
1348 if (precision < 0)
1349 precision = 0;
1350 }
1351
1352 /* get the conversion qualifier */
1353 qualifier = -1;
1354 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
1355 *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
1356 qualifier = *fmt;
1357 ++fmt;
1358 if (qualifier == 'l' && *fmt == 'l') {
1359 qualifier = 'L';
1360 ++fmt;
1361 }
1362 }
1363
1364 /* default base */
1365 base = 10;
1366
1367 switch (*fmt) {
1368 case 'c':
1369 if (!(flags & LEFT)) {
1370 while (--field_width > 0) {
1371 if (str < end)
1372 *str = ' ';
1373 ++str;
1374 }
1375 }
1376 c = (unsigned char) get_arg(char);
1377 if (str < end)
1378 *str = c;
1379 ++str;
1380 while (--field_width > 0) {
1381 if (str < end)
1382 *str = ' ';
1383 ++str;
1384 }
1385 continue;
1386
1387 case 's':{
1388 const char *str_arg = args;
1389 size_t len = strlen(str_arg);
1390 args += len + 1;
1391 str = string(str, end, (char *)str_arg, field_width,
1392 precision, flags);
1393 continue;
1394 }
1395
1396 case 'p':
1397 str = pointer(fmt+1, str, end, get_arg(void *),
1398 field_width, precision, flags);
1399 /* Skip all alphanumeric pointer suffixes */
1400 while (isalnum(fmt[1]))
1401 fmt++;
1402 continue;
1403
1404 case 'n':
1405 /* skip %n */
1406 continue;
1407
1408 case '%':
1409 if (str < end)
1410 *str = '%';
1411 ++str;
1412 continue;
1413
1414 /* integer number formats - set up the flags and "break" */
1415 case 'o':
1416 base = 8;
1417 break;
1418
1419 case 'x':
1420 flags |= SMALL;
1421 case 'X':
1422 base = 16;
1423 break;
1424
1425 case 'd':
1426 case 'i':
1427 flags |= SIGN;
1428 case 'u':
1429 break;
1430
1431 default:
1432 if (str < end)
1433 *str = '%';
1434 ++str;
1435 if (*fmt) {
1436 if (str < end)
1437 *str = *fmt;
1438 ++str;
1439 } else {
1440 --fmt;
1441 }
1442 continue;
1443 }
1444 if (qualifier == 'L')
1445 num = get_arg(long long);
1446 else if (qualifier == 'l') {
1447 num = get_arg(unsigned long);
1448 if (flags & SIGN)
1449 num = (signed long) num;
1450 } else if (qualifier == 'Z' || qualifier == 'z') {
1451 num = get_arg(size_t);
1452 } else if (qualifier == 't') {
1453 num = get_arg(ptrdiff_t);
1454 } else if (qualifier == 'h') {
1455 num = (unsigned short) get_arg(short);
1456 if (flags & SIGN)
1457 num = (signed short) num;
1458 } else {
1459 num = get_arg(unsigned int);
1460 if (flags & SIGN)
1461 num = (signed int) num;
1462 }
1463 str = number(str, end, num, base,
1464 field_width, precision, flags);
1465 }
1466 if (size > 0) {
1467 if (str < end)
1468 *str = '\0';
1469 else
1470 end[-1] = '\0';
1471 }
1472#undef get_arg
1473
1474 /* the trailing null byte doesn't count towards the total */
1475 return str - buf;
1476}
1477EXPORT_SYMBOL_GPL(bstr_printf);
1478
1479/**
1480 * bprintf - Parse a format string and place args' binary value in a buffer
1481 * @bin_buf: The buffer to place args' binary value
1482 * @size: The size of the buffer(by words(32bits), not characters)
1483 * @fmt: The format string to use
1484 * @...: Arguments for the format string
1485 *
1486 * The function returns the number of words(u32) written
1487 * into @bin_buf.
1488 */
1489int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...)
1490{
1491 va_list args;
1492 int ret;
1493
1494 va_start(args, fmt);
1495 ret = vbin_printf(bin_buf, size, fmt, args);
1496 va_end(args);
1497 return ret;
1498}
1499EXPORT_SYMBOL_GPL(bprintf);
1500
1501#endif /* CONFIG_BINARY_PRINTF */
1502
1061/** 1503/**
1062 * vsscanf - Unformat a buffer into a list of arguments 1504 * vsscanf - Unformat a buffer into a list of arguments
1063 * @buf: input buffer 1505 * @buf: input buffer