Rev 68948 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 2002--2013 The R Core Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, a copy is available at* https://www.R-project.org/Licenses/** Formerly part of src/main/sprintf.c*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <Defn.h>#include "RBufferUtils.h"#undef _#ifdef ENABLE_NLS#include <libintl.h>#define _(String) dgettext ("tools", String)#else#define _(String) (String)#endif#define MAXLINE MAXELTSIZE#define MAXNARGS 100/* ^^^ not entirely arbitrary, but strongly linked to allowing %$1 to %$99 !*/#define TRANSLATE_CHAR(_STR_, _i_) \((use_UTF8) ? translateCharUTF8(STRING_ELT(_STR_, _i_)) \: translateChar(STRING_ELT(_STR_, _i_)))SEXP getfmts(SEXP format){int cnt, v, nfmt;char fmt[MAXLINE+1], bit[MAXLINE+1];const char *formatString;size_t n, cur, chunk, maxlen = 0;int nthis, nstar;Rboolean use_UTF8;const void *vmax = vmaxget();SEXP res = PROTECT(allocVector(STRSXP, MAXNARGS));#define SET_RESULT(n, s) { \if (n >= MAXNARGS) error(_("only %d arguments are allowed"), MAXNARGS); \maxlen = (n) < maxlen ? maxlen : (n) + 1; \SET_STRING_ELT(res, (n), mkChar(s)); \}if (!isString(format)) error(_("'fmt' is not a character vector"));nfmt = LENGTH(format);if (nfmt != 1)error(_("'fmt' must be length 1"));use_UTF8 = getCharCE(STRING_ELT(format, 0)) == CE_UTF8;formatString = TRANSLATE_CHAR(format, 0);n = strlen(formatString);if (n > MAXLINE)error(_("'fmt' length exceeds maximal format length %d"), MAXLINE);/* process the format string */for (cur = 0, cnt = 0; cur < n; cur += chunk) {const char *curFormat = formatString + cur;char *starc;if (formatString[cur] == '%') { /* handle special format command */if (cur < n - 1 && formatString[cur + 1] == '%') {/* take care of %% in the format */chunk = 2;strcpy(bit, "%");}else {/* recognise selected types from Table B-1 of K&R *//* NB: we deal with "%%" in branch above. *//* This is MBCS-OK, as we are in a format spec *//* Include formats c, u, p and n as well as the R formats; this needs to match *//* C code as well */chunk = strcspn(curFormat + 1, "diosfeEgGxXaAcupn") + 2;if (cur + chunk > n)error(_("unrecognised format specification '%s'"), curFormat);strncpy(fmt, curFormat, chunk);fmt[chunk] = '\0';nthis = -1;/* now look for %n$ or %nn$ form */if (strlen(fmt) > 3 && fmt[1] >= '1' && fmt[1] <= '9') {v = fmt[1] - '0';if(fmt[2] == '$') {nthis = v-1;memmove(fmt+1, fmt+3, strlen(fmt)-2);} else if(fmt[2] >= '0' && fmt[2] <= '9' && fmt[3] == '$') {v = 10*v + fmt[2] - '0';nthis = v-1;memmove(fmt+1, fmt+4, strlen(fmt)-3);}}starc = Rf_strchr(fmt, '*');if (starc) { /* handle * format if present */nstar = -1;if (strlen(starc) > 3 && starc[1] >= '1' && starc[1] <= '9') {v = starc[1] - '0';if(starc[2] == '$') {nstar = v-1;memmove(starc+1, starc+3, strlen(starc)-2);} else if(starc[2] >= '0' && starc[2] <= '9'&& starc[3] == '$') {v = 10*v + starc[2] - '0';nstar = v-1;memmove(starc+1, starc+4, strlen(starc)-3);}}if(nstar < 0) {nstar = cnt++;}if (Rf_strchr(starc+1, '*'))error(_("at most one asterisk '*' is supported in each conversion specification"));SET_RESULT(nstar, "*");}if (fmt[strlen(fmt) - 1] == '%') {} else {if(nthis < 0) {nthis = cnt++;}SET_RESULT(nthis, fmt);}}}else { /* not '%' : handle string part */char *ch = Rf_strchr(curFormat, '%'); /* MBCS-aware version used */chunk = (ch) ? (size_t) (ch - curFormat) : strlen(curFormat);strncpy(bit, curFormat, chunk);bit[chunk] = '\0';}} /* end for ( each chunk ) */res = xlengthgets(res, maxlen);vmaxset(vmax);UNPROTECT(1);return res;}