diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/word2x/text-table.cc |
Initial commit
Diffstat (limited to 'support/word2x/text-table.cc')
-rw-r--r-- | support/word2x/text-table.cc | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/support/word2x/text-table.cc b/support/word2x/text-table.cc new file mode 100644 index 0000000000..cd2c9887c9 --- /dev/null +++ b/support/word2x/text-table.cc @@ -0,0 +1,337 @@ +/* $Id: text-table.cc,v 1.14 1997/04/13 04:26:42 dps Exp $ */ +/* Ascii table layout */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#if HAVE_ALLOCA_H +#include <alloca.h> +#else /* Do not have alloca.h */ +#ifdef _AIX + #pragma alloca +#else /* not _AIX */ +extern "C" char *alloca(int); +#endif /* _AIX */ +#endif /* HAVE_ALLOCA_H */ +#endif /* __GNUC__ */ + +#include <iostream.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif /* HAVE_CTYPE_H */ +#include "tblock.h" +#include "text-table.h" +#include "lib.h" + +struct rdata +{ + struct wd_info w; + const char *data; +}; + + +/* Print out a number of spaces */ +static inline void p_sp(int n, FILE *out) +{ + int i; + + for (i=0; i<n; i++) + fputc(' ', out); +} + +/* Print row after folding of columns has been done */ +static void basic_print_row(int ncols, + const struct rdata *cols, + char sep, FILE *out) +{ + const char **lptr, *s, *t; + int i, flg, nsp; + align_t al; + num_info n; + + /* Alloca line position pointers */ + if ((lptr=(const char **) alloca(ncols*sizeof(const char *)))==NULL) + { + fprintf(stderr, "basic_print_row: fatal alloca failure\n"); + exit(1); + } + + for (i=0; i<ncols; i++) + lptr[i]=cols[i].data; + + while (1) + { + /* Check for some content */ + flg=0; + for (i=0; i<ncols; i++) + if (*lptr[i]!='\0') + flg=1; + if (!flg) break; + + /* Print the content */ + for (i=0; i<ncols; i++) + { + s=lptr[i]; + + /* Find the extent and decimal point pos of current item */ + for (t=s, nsp=cols[i].w.width; *t!='\0'; nsp--, t++) + { + if (*t=='\n') + break; + } + + if (s==t) + { + p_sp(nsp, out); + } + else + { + /* There is some content, print it */ + al=cols[i].w.align; + if (cols[i].w.dp_col>=0) + { + n=scan_num(s); + if (n.dot_pos!=-1) + { + p_sp(cols[i].w.dp_col-n.dot_pos, out); + fwrite((void *) s, sizeof(char), t-s, out); + p_sp(nsp-cols[i].w.dp_col+n.dot_pos, out); + al=ALIGN_DP; + } + } + + switch(al) + { + case ALIGN_DP: + break; + + case ALIGN_LEFT: + fwrite((void *) s, sizeof(char), t-s, out); + p_sp(nsp, out); + break; + + case ALIGN_CENTER: + p_sp(nsp/2, out); + fwrite((void *) s, sizeof(char), t-s, out); + p_sp(nsp-(nsp/2), out); // Avoid rounding related problems + break; + + case ALIGN_RIGHT: + p_sp(nsp, out); + fwrite((void *) s, sizeof(char), t-s, out); + break; + + default: + fprintf(stderr,"basic_print_row: Invalid alignment\n"); + break; + } + } + fputc(sep, out); // Seperate columns by a space + + /* Update lptr[i] */ + if (*t=='\n') + t++; // Advance past newlines; + lptr[i]=t; + } + fputc('\n', out); // Print out a newline + } +} + +/* Split the elements of a row */ +static void print_row(int ncols, const struct rdata *dp, FILE *out) +{ + static const char null_string[]={'\0'}; + struct rdata *rd; + tblock *d; + char *s, *t; + int i; + + /* Allocate structures */ + if ((rd=(struct rdata *) alloca(ncols*sizeof(rdata)))==NULL) + { + fprintf(stderr, "print_row: fatal alloca failure\n"); + exit(1); + } + + /* Fold lines */ + for (i=0; i<ncols; i++) + { + rd[i].w=dp[i].w; + if (dp[i].data==NULL) + { + rd[i].data=null_string; // Avoid complication of null in + // basic_print_row + continue; // Move on to next item + } + + d=word_wrap(dp[i].data, "\n", "\n", dp[i].w.width, 0); + if ((rd[i].data=strdup(*d))==NULL) + { + fprintf(stderr, "text_table::print_row: fatal alloca failure\n"); + exit(1); + } + else + { + /* Filter out CH_SUSPECT */ + for(s=t=(char *) rd[i].data; *s!='\0'; s++) + { + if (*s==CH_SUSPECT) + continue; + *(t++)=*s; + } + *t='\0'; + } + delete(d); + } + basic_print_row(ncols, rd, ' ', out); // Printing the rows is actually + // quite complex. + for (i=0; i<ncols; i++) + { + if (rd[i].data!=null_string) + free((void *) rd[i].data); // Free data + } +} + + +/* O(n^2) table width reduction algorithm, n is small in almost all cases */ +static void shrink_widths(int ncols, struct rdata *cols, int mtw) +{ + int i, j, tw, maxw; + + for (tw=0, i=0; i<ncols; i++) + tw+=cols[i].w.width; + + mtw-=ncols; // Take account of column seperators + + /* Simply reduce the maximum width column width by one until + enougn has been trimed */ + while (tw>mtw) + { + maxw=0; j=-1; + for (i=0; i<ncols; i++) + { + if (maxw<cols[i].w.width && cols[i].w.align!=ALIGN_DP) + { + j=i; + maxw=cols[i].w.width; + } + } + + if (j==-1) + { + fprintf(stderr, "Can not shrink overwidth table\n"); + continue; + } + cols[j].w.width--; + tw--; + } +} + +/* Returns NULL or text message */ +const char *text_table::print_table(int wd, FILE *out) +{ + int i,j; + struct rdata *d; + const struct col_info *col; + + if ((d=(struct rdata *) alloca(cols*sizeof(struct rdata)))==NULL) + { + cerr<<"text_table::print_table alloca failute (fatal)\n"; + return "[Table omitted due to lack of memory]"; + } + if (cols==0 || rows==0) + { + fputs("[empty tabel ignored]\n", out); + return "[Ignored empty table]"; + } + + for (i=0, col=cdata; col!=NULL; i++, col=col->next) + d[i].w=find_width(rows, col->data); + shrink_widths(cols, d, wd); + + for (i=0; i<rows; i++) + { + for (j=0, col=cdata; col!=NULL; j++, col=col->next) + d[j].data=(col->data)[i]; + print_row(cols, d, out); + } + return NULL; +} + +/* Set */ +int text_table::set(int c, int r, const char *s) +{ + struct col_info *col; + int i; + + if (c<0 || c>=cols || r<0 || r>=rows) + { + cerr<<"Invalid request to set "<<c<<','<<r<<" in " + <<cols<<'x'<<rows<<" table (value "<<s<<")\n"; + return 0; + } + + for (col=cdata, i=0; i<c && col!=NULL; i++, col=col->next) ; + if (col!=NULL) + { + if (col->data[r]!=NULL) + free((void *) col->data[r]); + col->data[r]=strdup(s); + } + return 1; +} + + +/* Constructor */ +text_table::text_table(int c, int r) +{ + int i, j; + struct col_info *col, **nptr; + + cols=c; + rows=r; + cdata=NULL; // Hardenning against cols=0 + for (nptr=&cdata, i=0; i<cols; i++) + { + col=new(struct col_info); + *nptr=col; + col->next=NULL; + nptr=&(col->next); + if ((col->data= + (const char **) malloc(rows*(sizeof(const char *))))==NULL) + { + cerr<<"text_table::constructor: malloc failure (fatal)\n"; + exit(1); + } + for (j=0; j<rows; j++) + (col->data)[j]=NULL; + } +} + +/* Destructor */ +text_table::~text_table() +{ + int i; + struct col_info *col, *nxt; + + for (col=cdata; col!=NULL;) + { + for (i=0; i<rows; i++) + if (col->data[i]==NULL) + free((void *) col->data[i]); + nxt=col->next; + free(col); + col=nxt; + } +} |