From e835af7775599a5c942f3813907dfa72d1227553 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Fri, 10 Dec 2010 22:38:24 -0500 Subject: allow real printf formatters for simple strings It's kind of silly to verify this kind of formatting, so I'm just letting it explode (which happens not too horribly) when the user inevitably does something stupid. --- README.pod | 6 +++++- expac.c | 68 +++++++++++++++++++++----------------------------------------- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/README.pod b/README.pod index b675f20..cd29252 100644 --- a/README.pod +++ b/README.pod @@ -119,7 +119,11 @@ The format argument allows the following interpreted sequences: %% literal % -Standard backslash escape sequences are supported. See printf(1). +Note that for any lowercase tokens aside from %m and %k, full printf support is +allowed, e.g. %-20n. This does not apply to any list based, date, or numerical +output. + +Standard backslash escape sequences are supported, as per printf(1). =head1 AUTHOR diff --git a/expac.c b/expac.c index 63c2562..503af54 100644 --- a/expac.c +++ b/expac.c @@ -42,6 +42,9 @@ #define FORMAT_TOKENS_SYNC "f" #define ESCAPE_TOKENS "\"\\abefnrtv" +static char const digits[] = "0123456789"; +static char const printf_flags[] = "'-+ #0I"; + pmdb_t *db_local = NULL; alpm_list_t *dblist = NULL; alpm_list_t *targets = NULL; @@ -344,45 +347,52 @@ static int print_time(time_t timestamp) { static int print_pkg(pmpkg_t *pkg, const char *format) { const char *f; - int out = 0; + char fmt[32]; + int len, out = 0; for (f = format; *f != '\0'; f++) { bool shortdeps = false; + len = 0; if (*f == '%') { - switch (*++f) { + len = strspn(f + 1 + len, printf_flags); + len += strspn(f + 1 + len, digits); + snprintf(fmt, len + 3, "%ss", f); + fmt[len + 1] = 's'; + f += len + 1; + switch (*f) { /* simple attributes */ case 'f': /* filename */ - out += printf("%s", alpm_pkg_get_filename(pkg)); + out += printf(fmt, alpm_pkg_get_filename(pkg)); break; case 'n': /* package name */ - out += printf("%s", alpm_pkg_get_name(pkg)); + out += printf(fmt, alpm_pkg_get_name(pkg)); break; case 'v': /* version */ - out += printf("%s", alpm_pkg_get_version(pkg)); + out += printf(fmt, alpm_pkg_get_version(pkg)); break; case 'd': /* description */ - out += printf("%s", alpm_pkg_get_desc(pkg)); + out += printf(fmt, alpm_pkg_get_desc(pkg)); break; case 'u': /* project url */ - out += printf("%s", alpm_pkg_get_url(pkg)); + out += printf(fmt, alpm_pkg_get_url(pkg)); break; case 'p': /* packager name */ - out += printf("%s", alpm_pkg_get_packager(pkg)); + out += printf(fmt, alpm_pkg_get_packager(pkg)); break; case 's': /* md5sum */ - out += printf("%s", alpm_pkg_get_md5sum(pkg)); + out += printf(fmt, alpm_pkg_get_md5sum(pkg)); break; case 'a': /* architecutre */ - out += printf("%s", alpm_pkg_get_arch(pkg)); + out += printf(fmt, alpm_pkg_get_arch(pkg)); break; case 'i': /* has install scriptlet? */ - out += printf("%s", alpm_pkg_has_scriptlet(pkg) ? "yes" : "no"); + out += printf(fmt, alpm_pkg_has_scriptlet(pkg) ? "yes" : "no"); break; case 'r': /* repo */ - out += printf("%s", alpm_db_get_name(alpm_pkg_get_db(pkg))); + out += printf(fmt, alpm_db_get_name(alpm_pkg_get_db(pkg))); break; case 'w': /* install reason */ - out += printf("%s", alpm_pkg_get_reason(pkg) ? "dependency" : "explicit"); + out += printf(fmt, alpm_pkg_get_reason(pkg) ? "dependency" : "explicit"); break; /* times */ @@ -462,34 +472,6 @@ static int print_pkg(pmpkg_t *pkg, const char *format) { return(0); } -int verify_format_string(const char *format) { - const char *p; - - for (p = format; *p != '\0'; p++) { - if (*p == '%') { - ++p; - if (!strchr(FORMAT_TOKENS FORMAT_TOKENS_LOCAL FORMAT_TOKENS_SYNC, *p)) { - fprintf(stderr, "error: bad token in format string: %%%c\n", *p); - return(1); - } - - /* check for querytype dependent tokens */ - if (!local && strchr(FORMAT_TOKENS_LOCAL, *p)) { - fprintf(stderr, "error: token not available with local queries: %%%c\n", *p); - return(1); - } else if (local && strchr(FORMAT_TOKENS_SYNC, *p)) { - fprintf(stderr, "error: token not available with sync queries: %%%c\n", *p); - return(1); - } - } else if (*p == '\\' && !strchr(ESCAPE_TOKENS, *++p)) { - fprintf(stderr, "error: bad token in format string: \\%c\n", *p); - return(1); - } - } - - return(0); -} - alpm_list_t *resolve_pkg(alpm_list_t *targets) { char *pkgname, *reponame; alpm_list_t *t, *r, *ret = NULL; @@ -569,10 +551,6 @@ int main(int argc, char *argv[]) { listdelim = listdelim ? listdelim : DEFAULT_LISTDELIM; timefmt = timefmt ? timefmt : DEFAULT_TIMEFMT; - if (verify_format_string(format) != 0) { - return(1); - } - results = resolve_pkg(targets); if (!results) { ret = 1; -- cgit v1.2.3-54-g00ecf