diff options
author | Antti-Juhani Kaijanaho <ajk@debian.org> | 2006-01-28 22:33:02 +0100 |
---|---|---|
committer | Antti-Juhani Kaijanaho <ajk@debian.org> | 2006-01-28 22:33:02 +0100 |
commit | 95cd00fbe60769c79bd24f109f982f4eff18751e (patch) | |
tree | b81a1b6935f2f20090582de2bf69d0fd0f324a55 /tbl-dctrl.c | |
parent | 389733d0f7f73f1d1c33b2974657be7888507111 (diff) | |
download | dctrl-tools-95cd00fbe60769c79bd24f109f982f4eff18751e.tar.gz |
Import 2.8
Diffstat (limited to 'tbl-dctrl.c')
-rw-r--r-- | tbl-dctrl.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/tbl-dctrl.c b/tbl-dctrl.c new file mode 100644 index 0000000..641e9fa --- /dev/null +++ b/tbl-dctrl.c @@ -0,0 +1,420 @@ +/* dctrl-tools - Debian control file inspection tools + Copyright (C) 2005 Antti-Juhani Kaijanaho + + 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <argp.h> +#include <locale.h> +#include <stdlib.h> +#include "misc.h" +#include "msg.h" +#include "i18n.h" +#include "ifile.h" +#include "para_bundle.h" +#include "sorter.h" + +#define OPT_SILENT 256 + +const char * argp_program_version = "tbl-dctrl (dctrl-tools) " VERSION; +const char * argp_program_bug_address = MAINTAINER; + +static struct argp_option options[] = { + { "delimiter", 'd', N_("DELIM"), 0, N_("Specify a delimiter.") }, + { "column", 'c', N_("SPEC"), 0, N_("Append the specified column.") }, + { "copying", 'C', 0, 0, N_("Print out the copyright license.") }, + { "errorlevel", 'l', N_("LEVEL"), 0, N_("Set debugging level to LEVEL.") }, + { "quiet", 'q', 0, 0, N_("Do no output to stdout.") }, + { "silent", OPT_SILENT, 0, 0, N_("Do no output to stdout.") }, + { 0 } +}; + +#define MAX_FNAMES 4096 +#define MAX_COLUMNS 4096 + +struct arguments { + char *delim; // NULL if not specced + /* True iff some column lengths are unknown and need to be + * calculated. */ + _Bool need_preprocessing; + /* Number of columns specified */ + size_t num_columns; + /* Number of file names seen. */ + size_t num_fnames; + /* Columns specified on the command line. */ + struct column { + char *heading; + size_t field_inx; + size_t column_width; + } columns[MAX_COLUMNS]; + /* File names seen on the command line. */ + struct ifile fname[MAX_FNAMES]; +}; + +#define INSERT(c) do { \ + if (len >= max) { \ + max *= 2; \ + rv = realloc(rv, max); \ + if (rv == NULL) fatal_enomem(NULL); \ + } \ + rv[len++] = (c); \ +} while (0) + +size_t linewrap(char **res, char const *orig, size_t orig_len, + size_t col_width) +{ + assert(col_width > 0); + + size_t max = 16; + char *rv = malloc(max); + size_t len = 0; + + size_t ll = 0; + size_t bpo = 0, bpr = 0; + + size_t num_lines = 1; + + mblen(NULL, 0); + for (size_t i = 0; i < orig_len; /**/) { + if (ll == col_width) { + if (rv[bpr] == '\n') { + // no suitable breakpoint on this line, + // break here + } else { + assert(bpr < len); + len = bpr; + assert(bpo < i); + i = bpo; + } + ll = 0; + INSERT('\n'); + num_lines++; + continue; + } + if (orig[i] == ' ' || orig[i] == '\t') { + // record this breakpoint + bpo = i; + bpr = len; + } + int n = mblen(orig + i, orig_len - i); + if (n <= 0) break; + for (size_t j = 0; j < n; j++) INSERT(orig[i+j]); + i += n; + ll++; + } + INSERT('\0'); + *res = rv; + return num_lines; +} + + +void print_line(struct arguments *args, + struct fsaf_read_rv const columns[/*args->num_columns*/]) +{ + struct print_line_data { + char *wrapped; + size_t wrapped_len; + size_t inx; + } data[args->num_columns]; + size_t num_lines = 0; + for (size_t i = 0; i < args->num_columns; i++) { + size_t n = linewrap(&data[i].wrapped, + columns[i].b, columns[i].len, + args->columns[i].column_width); + if (n > num_lines) num_lines = n; + data[i].inx = 0; + data[i].wrapped_len = strlen(data[i].wrapped); + } + for (size_t i = 0; i < num_lines; i++) { + for (size_t j = 0; j < args->num_columns; j++) { + if (args->delim == NULL) { + fputs("| ", stdout); + } else if (j > 0) { + fputs(args->delim, stdout); + } + mblen(NULL, 0); + size_t k; + size_t m = 0; + for (k = data[j].inx; + k < data[j].wrapped_len; + /**/) { + if (data[j].wrapped[k] == '\n') { + k++; + break; + } + int n = mblen(data[j].wrapped + k, + data[j].wrapped_len - k); + for (int l = 0; l < n; l++) { + putchar(data[j].wrapped[k+l]); + } + if (n <= 0) n = 1; + k += n; + m++; + } + + if (args->delim == NULL) { + while (m < args->columns[j].column_width) { + m++; + putchar(' '); + } + putchar(' '); + } + data[j].inx = k; + } + if (args->delim == NULL) fputs("|", stdout); + putchar('\n'); + } + for (size_t i = 0; i < args->num_columns; i++) free(data[i].wrapped); +} + +void print_head(struct arguments *args) +{ + if (args->delim == NULL) { + for (size_t i = 0; i < args->num_columns; i++) { + putchar('+'); + for (size_t j = 0; + j < args->columns[i].column_width + 2; + j++) { + putchar('='); + } + } + putchar('+'); + putchar('\n'); + } + + struct fsaf_read_rv columns[args->num_columns]; + for (size_t i = 0; i < args->num_columns; i++) { + columns[i].b = args->columns[i].heading; + columns[i].len = strlen(columns[i].b); + } + print_line(args, columns); + + if (args->delim == NULL) { + for (size_t i = 0; i < args->num_columns; i++) { + putchar('+'); + for (size_t j = 0; j < args->columns[i].column_width + 2; j++) { + putchar('-'); + } + } + putchar('+'); + putchar('\n'); + } +} + +void print_foot(struct arguments *args) +{ + if (args->delim != NULL) return; + for (size_t i = 0; i < args->num_columns; i++) { + putchar('+'); + for (size_t j = 0; j < args->columns[i].column_width + 2; j++) { + putchar('='); + } + } + putchar('+'); + putchar('\n'); +} + +void handle_para(struct arguments *args, struct paragraph *para) +{ + struct fsaf_read_rv columns[args->num_columns]; + for (size_t i = 0; i < args->num_columns; i++) { + columns[i] = get_field(para, args->columns[i].field_inx); + } + print_line(args, columns); +} + +static error_t parse_opt (int key, char * arg, struct argp_state * state) +{ + struct arguments * args = state->input; + switch (key) { + case 'C': + if (!to_stdout (COPYING)) fail(); + exit(0); + case 'c': { + char *carg = strdup(arg); + if (carg == NULL) fatal_enomem(0); + char *lens = strrchr(carg, ':'); + if (lens != NULL) *(lens++) = '\0'; else lens = ""; + char *fn = strchr(carg, '='); + if (fn != NULL) *(fn++) = '\0'; + struct column *col = &args->columns[args->num_columns]; + col->heading = carg; + col->field_inx = fieldtrie_insert(fn == NULL ? carg : fn); + size_t n = 0; + _Bool err = 0; + for (char const *p = lens; *p != '\0'; p++) { + if (!('0' <= *p && *p <= '9')) { + err = 1; + continue; + } + n = n * 10 + (*p - '0'); + } + if (err) message(L_IMPORTANT, _("invalid column length"), NULL); + col->column_width = n > 0 ? n : -1; + if (n == 0) args->need_preprocessing = 1; + args->num_columns++; + } + break; + case 'd': + args->delim = strdup(arg); + if (args->delim == NULL) fatal_enomem(NULL); + break; + case 'l': { + int ll = str2loglevel(arg); + if (ll < 0) + { + message(L_FATAL, _("no such log level"), arg); + fail(); + } + set_loglevel(ll); + debug_message("parse_opt: l", 0); + } + break; + case ARGP_KEY_ARG: + debug_message("parse_opt: argument", 0); + { + char const * s; + if (args->num_fnames >= MAX_FNAMES) { + message(L_FATAL, _("too many file names"), 0); + fail(); + } + s = strdup(arg); + if (s == 0) fatal_enomem(0); + args->fname[args->num_fnames++] = + (struct ifile){ .mode = m_read, .s = s }; + } + break; + case ARGP_KEY_END: + case ARGP_KEY_ARGS: case ARGP_KEY_INIT: case ARGP_KEY_SUCCESS: + case ARGP_KEY_ERROR: case ARGP_KEY_FINI: case ARGP_KEY_NO_ARGS: + debug_message("parse_opt: ignored", 0); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static char progdoc [] = +N_("tbl-dctrl -- tabularize Debian control files"); + +static struct argp argp = { options, parse_opt, 0, progdoc }; + +static size_t mbs_len(char const *mbs, size_t n, char const *fname) +{ + if (n == (size_t)(-1)) n = strlen(mbs); + size_t len = 0; + mblen(NULL, 0); + for (size_t k = 0; k < n;/**/) { + if (mbs[k] == '\n') break; + len++; + int delta = mblen(mbs + k, n - k); + if (delta <= 0) { + message(L_IMPORTANT, _("bad multibyte character"), + fname); + k++; + } else { + k += delta; + } + } + return len; +} + +int main(int argc, char * argv[]) +{ + setlocale(LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + fieldtrie_init(); + + static struct arguments args; + + //keys_init(&args.keys); + msg_set_progname(argv[0]); + argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + + if (args.num_fnames == 0) { + args.fname[args.num_fnames++] = (struct ifile){ + .mode = m_read, .s = "-" + }; + } + + if (args.need_preprocessing) { + struct para_bundle pb; + + bundle_init(&pb); + + for (size_t i = 0; i < args.num_fnames; i++) { + bundle_slurp(&pb, args.fname[i]); + } + + size_t n = fieldtrie_count(); + size_t lens[n]; + for (size_t i = 0; i < n; i++) lens[i] = 0; + + for (size_t i = 0; i < pb.num_paras; i++) { + struct paragraph *p = pb.paras[i]; + assert(p->nfields == n); + for (size_t j = 0; j < p->nfields; j++) { + struct fsaf_read_rv r = get_field(p, j); + size_t len = mbs_len(r.b, r.len, + p->common->fp->fname); + if (len > lens[j]) lens[j] = len; + } + } + for (size_t i = 0; i < args.num_columns; i++) { + size_t width = args.columns[i].column_width; + size_t headw = mbs_len(args.columns[i].heading, -1, 0); + if (width == (size_t)(-1)) width = lens[i]; + if (headw > width) width = headw; + args.columns[i].column_width = width; + } + print_head(&args); + for (size_t i = 0; i < pb.num_paras; i++) { + handle_para(&args, pb.paras[i]); + } + print_foot(&args); + } else { + print_head(&args); + for (size_t i = 0; i < args.num_fnames; ++i) { + int fd; + struct ifile fname = args.fname[i]; + + if (fname.mode == m_error) continue; + + fd = open_ifile(fname); + if (fd == -1) break; + + if (!chk_ifile(fname, fd)) break; + + FSAF * fp = fsaf_fdopen(fd, fname.s); + para_parser_t pp; + para_parser_init(&pp, fp, true); + para_t para; + para_init(&pp, ¶); + while (1) { + para_parse_next(¶); + if (para_eof(&pp)) break; + handle_para(&args, ¶); + } + + close_ifile(fname, fd); + } + print_foot(&args); + } + + return 0; +} |