diff options
| author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2009-03-06 11:21:46 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-03-06 11:39:04 -0500 |
| commit | 4370aa4aa75391a5e2e06bccb0919109f725ed8e (patch) | |
| tree | 602a6ea4e404d17e610d4a9979d615ff2d0bfd98 | |
| parent | f036be96dd9ce442ffb9ab33e3c165f5178815c0 (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>
| -rw-r--r-- | include/linux/string.h | 7 | ||||
| -rw-r--r-- | lib/Kconfig | 3 | ||||
| -rw-r--r-- | lib/vsprintf.c | 442 |
3 files changed, 452 insertions, 0 deletions
diff --git a/include/linux/string.h b/include/linux/string.h index d18fc198aa2f..27ac31784ad2 100644 --- a/include/linux/string.h +++ b/include/linux/string.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/compiler.h> /* for inline */ | 10 | #include <linux/compiler.h> /* for inline */ |
| 11 | #include <linux/types.h> /* for size_t */ | 11 | #include <linux/types.h> /* for size_t */ |
| 12 | #include <linux/stddef.h> /* for NULL */ | 12 | #include <linux/stddef.h> /* for NULL */ |
| 13 | #include <stdarg.h> | ||
| 13 | 14 | ||
| 14 | extern char *strndup_user(const char __user *, long); | 15 | extern char *strndup_user(const char __user *, long); |
| 15 | 16 | ||
| @@ -111,6 +112,12 @@ extern void argv_free(char **argv); | |||
| 111 | 112 | ||
| 112 | extern bool sysfs_streq(const char *s1, const char *s2); | 113 | extern bool sysfs_streq(const char *s1, const char *s2); |
| 113 | 114 | ||
| 115 | #ifdef CONFIG_BINARY_PRINTF | ||
| 116 | int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); | ||
| 117 | int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf); | ||
| 118 | int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); | ||
| 119 | #endif | ||
| 120 | |||
| 114 | extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, | 121 | extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, |
| 115 | const void *from, size_t available); | 122 | const void *from, size_t available); |
| 116 | 123 | ||
diff --git a/lib/Kconfig b/lib/Kconfig index 03c2c24b9083..97d62cf091a7 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | # Library configuration | 2 | # Library configuration |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | config BINARY_PRINTF | ||
| 6 | def_bool n | ||
| 7 | |||
| 5 | menu "Library routines" | 8 | menu "Library routines" |
| 6 | 9 | ||
| 7 | config BITREVERSE | 10 | config BITREVERSE |
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 | } |
| 1059 | EXPORT_SYMBOL(sprintf); | 1059 | EXPORT_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 | */ | ||
| 1085 | int 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) \ | ||
| 1094 | do { \ | ||
| 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 | |||
| 1117 | repeat: | ||
| 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 | } | ||
| 1222 | EXPORT_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 | */ | ||
| 1249 | int 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; | ||
| 1303 | repeat: | ||
| 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 | } | ||
| 1477 | EXPORT_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 | */ | ||
| 1489 | int 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 | } | ||
| 1499 | EXPORT_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 |
