printf.c revision cc39d95a344240bec8f0c74a02c74d54620b735d
10d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma/* printf.c - Format and Print the data. 20d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma * 30d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com> 40d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma * Copyright 2014 Kyungwan Han <asura321@gmail.com> 50d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma * 60d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html 70d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 80d8467b371d93bff03f59a8f11f01094f7618372Ashwini SharmaUSE_PRINTF(NEWTOY(printf, "<1", TOYFLAG_USR|TOYFLAG_BIN)) 90d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 100d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharmaconfig PRINTF 1187fd25f20b86731dd01332ce828424e7047ef29dRob Landley bool "printf" 1287fd25f20b86731dd01332ce828424e7047ef29dRob Landley default n 1387fd25f20b86731dd01332ce828424e7047ef29dRob Landley help 1487fd25f20b86731dd01332ce828424e7047ef29dRob Landley usage: printf FORMAT [ARGUMENT...] 150d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 1687fd25f20b86731dd01332ce828424e7047ef29dRob Landley Format and print ARGUMENT(s) according to FORMAT, using C printf syntax 17cc39d95a344240bec8f0c74a02c74d54620b735dRob Landley (% escapes for cdeEfgGiosuxX, \ escapes for abefnrtv0 or \OCTAL or \xHEX). 180d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma*/ 1987fd25f20b86731dd01332ce828424e7047ef29dRob Landley 200d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma#define FOR_printf 210d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma#include "toys.h" 220d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 230d8467b371d93bff03f59a8f11f01094f7618372Ashwini SharmaGLOBALS( 240d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma char *hv_w; 250d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma char *hv_p; 260d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma int encountered; 270d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma) 280d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 2977c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley// Detect matching character (return true/valse) and advance pointer if match. 3077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landleystatic int eat(char **s, char c) 310d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma{ 3277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley int x = (**s == c); 3387fd25f20b86731dd01332ce828424e7047ef29dRob Landley 3477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (x) ++*s; 3587fd25f20b86731dd01332ce828424e7047ef29dRob Landley 3677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley return x; 370d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma} 380d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 390d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma// Add ll and L to Interger and floating point formats respectively. 400d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharmastatic char *get_format(char *f) 410d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma{ 420d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma int len = strlen(f); 430d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma char last = f[--len], *post = ""; 440d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 4587fd25f20b86731dd01332ce828424e7047ef29dRob Landley f[len] = 0; 460d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma if (strchr("diouxX", last)) post = "ll"; // add ll to integer modifier. 470d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma else if (strchr("feEgG", last)) post = "L"; // add L to float modifier. 480d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma return xmprintf("%s%s%c", f, post, last); 490d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma} 500d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 510d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma// Print arguments with corresponding conversion and width and precision. 52cc39d95a344240bec8f0c74a02c74d54620b735dRob Landleystatic void print(char *fmt, int w, int p, char *arg) 530d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma{ 54cc39d95a344240bec8f0c74a02c74d54620b735dRob Landley char *ptr = fmt, *ep = 0, *format = 0; 5587fd25f20b86731dd01332ce828424e7047ef29dRob Landley 560d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma errno = 0; 5787fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (strchr("diouxX", *ptr)) { 5887fd25f20b86731dd01332ce828424e7047ef29dRob Landley long long val = 0; 5987fd25f20b86731dd01332ce828424e7047ef29dRob Landley 6087fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (arg) { 6187fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (*arg == '\'' || *arg == '"') val = arg[1]; 620d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma else { 6387fd25f20b86731dd01332ce828424e7047ef29dRob Landley val = strtoll(arg, &ep, 0); 6487fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (errno || (ep && (*ep || ep == arg))) { 6587fd25f20b86731dd01332ce828424e7047ef29dRob Landley perror_msg("Invalid num %s", arg); 6687fd25f20b86731dd01332ce828424e7047ef29dRob Landley val = 0; 670d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma } 680d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma } 6987fd25f20b86731dd01332ce828424e7047ef29dRob Landley } 7087fd25f20b86731dd01332ce828424e7047ef29dRob Landley format = get_format(fmt); 7187fd25f20b86731dd01332ce828424e7047ef29dRob Landley TT.hv_w ? (TT.hv_p ? printf(format, w, p, val) : printf(format, w, val)) 7287fd25f20b86731dd01332ce828424e7047ef29dRob Landley : (TT.hv_p ? printf(format, p, val) : printf(format, val)); 7387fd25f20b86731dd01332ce828424e7047ef29dRob Landley } else if (strchr("gGeEf", *ptr)) { 7487fd25f20b86731dd01332ce828424e7047ef29dRob Landley long double dval = 0; 7587fd25f20b86731dd01332ce828424e7047ef29dRob Landley 7687fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (arg) { 7787fd25f20b86731dd01332ce828424e7047ef29dRob Landley dval = strtold(arg, &ep); 7887fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (errno || (ep && (*ep || ep == arg))) { 7987fd25f20b86731dd01332ce828424e7047ef29dRob Landley perror_msg("Invalid num %s", arg); 8087fd25f20b86731dd01332ce828424e7047ef29dRob Landley dval = 0; 810d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma } 8287fd25f20b86731dd01332ce828424e7047ef29dRob Landley } 8387fd25f20b86731dd01332ce828424e7047ef29dRob Landley format = get_format(fmt); 8487fd25f20b86731dd01332ce828424e7047ef29dRob Landley TT.hv_w ? (TT.hv_p ? printf(format, w, p, dval) : printf(format, w, dval)) 8587fd25f20b86731dd01332ce828424e7047ef29dRob Landley : (TT.hv_p ? printf(format, p, dval) : printf(format, dval)); 8687fd25f20b86731dd01332ce828424e7047ef29dRob Landley } else if (*ptr == 's') { 8787fd25f20b86731dd01332ce828424e7047ef29dRob Landley char *str = arg; 8887fd25f20b86731dd01332ce828424e7047ef29dRob Landley 8987fd25f20b86731dd01332ce828424e7047ef29dRob Landley if (!str) str = ""; 9087fd25f20b86731dd01332ce828424e7047ef29dRob Landley 9187fd25f20b86731dd01332ce828424e7047ef29dRob Landley TT.hv_w ? (TT.hv_p ? printf(fmt,w,p,str): printf(fmt, w, str)) 9287fd25f20b86731dd01332ce828424e7047ef29dRob Landley : (TT.hv_p ? printf(fmt, p, str) : printf(fmt, str)); 9387fd25f20b86731dd01332ce828424e7047ef29dRob Landley } else if (*ptr == 'c') printf(fmt, arg ? *arg : 0); 9487fd25f20b86731dd01332ce828424e7047ef29dRob Landley 950d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma if (format) free(format); 960d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma} 970d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 9877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley// Parse escape sequences. 990d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharmastatic int handle_slash(char **esc_val) 1000d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma{ 1010d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma char *ptr = *esc_val; 10277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley int len = 1, base = 0; 10377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley unsigned result = 0; 10477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 10577c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (*ptr == 'c') xexit(); 10677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 10777c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley // 0x12 hex escapes have 1-2 digits, \123 octal escapes have 1-3 digits. 10877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (eat(&ptr, 'x')) base = 16; 10977c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley else if (*ptr >= '0' && *ptr <= '8') base = 8; 11077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley len += (base-8)/8; 11177c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 11277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley // Not a hex or octal escape? (This catches trailing \) 11377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (!len) { 11477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (!(result = unescape(*ptr))) result = '\\'; 11577c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley else ++*esc_val; 11677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 11777c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley return result; 11877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley } 1190d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 12077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley while (len) { 12177c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley unsigned num = tolower(*ptr)-'0'; 12277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 12377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (num > 10) num += '0'-'a'+10; 1240d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma if (num >= base) { 12577c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley // Don't parse invalid hex value ala "\xvd", print it verbatim 12677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (base == 16 && len == 2) { 12777c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley ptr--; 12877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley result = '\\'; 1290d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma } 1300d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma break; 1310d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma } 13277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley result = (result*base)+num; 1330d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma ptr++; 13477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley len--; 1350d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma } 1360d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma *esc_val = ptr; 1370d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 13877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley return (char)result; 1390d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma} 1400d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma 1410d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharmavoid printf_main(void) 1420d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma{ 14377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley char *format = *toys.optargs, **arg = toys.optargs+1, *f, *p; 14477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 14577c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley for (f = format; *f; f++) { 14677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (eat(&f, '\\')) putchar(handle_slash(&f)); 147cc39d95a344240bec8f0c74a02c74d54620b735dRob Landley else if (!eat(&f, '%') || *f == '%') putchar(*f); 14877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley else if (*f == 'b') 14977c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley for (p = *arg ? *(arg++) : ""; *p; p++) 15077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley putchar(eat(&p, '\\') ? handle_slash(&p) : *p); 15177c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley else { 15277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley char *start = f; 15377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley int wp[2], i; 15477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 15577c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley // todo: we currently ignore these? 15677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (strchr("-+# ", *f)) f++; 15777c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley memset(wp, 0, 8); 15877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley for (i=0; i<2; i++) { 15977c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (eat(&f, '*')) { 16077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (*arg) wp[i] = atolx(*(arg++)); 16177c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley } else while (isdigit(*f)) f++; 16277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (!eat(&f, '.')) break; 16377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley } 16477c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (!(p = strchr("diouxXfeEgGcs", *f))) 165cc39d95a344240bec8f0c74a02c74d54620b735dRob Landley error_exit("bad format@%ld", f-format); 16677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley else { 16777c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley int len = f-start; 16877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley 16977c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley TT.hv_p = strstr(start, ".*"); 17077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley TT.hv_w = strchr(start, '*'); 17177c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley //pitfall: handle diff b/w * and .* 17277c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if ((TT.hv_w-1) == TT.hv_p) TT.hv_w = NULL; 17377c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley memcpy((p = xzalloc(len+1)), start, len); 174cc39d95a344240bec8f0c74a02c74d54620b735dRob Landley print(p+len-1, wp[0], wp[1], *arg); 17577c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley if (*arg) arg++; 17677c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley free(p); 17777c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley p = NULL; 17877c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley } 17977c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley TT.encountered = 1; 18077c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley } 18177c8d1a7d006e177bd0283b48530a3397b687b6cRob Landley } 1820d8467b371d93bff03f59a8f11f01094f7618372Ashwini Sharma} 183