summaryrefslogtreecommitdiff
path: root/support/word2x/text-table.cc
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/word2x/text-table.cc
Initial commit
Diffstat (limited to 'support/word2x/text-table.cc')
-rw-r--r--support/word2x/text-table.cc337
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;
+ }
+}