home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / word2x0a.zip / source / text-table.cc < prev    next >
C/C++ Source or Header  |  1997-04-12  |  7KB  |  327 lines

  1. /* $Id: text-table.cc,v 1.14 1997/04/13 04:26:42 dps Exp $ */
  2. /* Ascii table layout */
  3. #ifdef __GNUC__
  4. #define alloca __builtin_alloca
  5. #else
  6. #if HAVE_ALLOCA_H
  7. #include <alloca.h>
  8. #else /* Do not have alloca.h */
  9. #ifdef _AIX
  10.  #pragma alloca
  11. #else /* not _AIX */
  12. char *alloca();
  13. #endif /* _AIX */
  14. #endif /* HAVE_ALLOCA_H */
  15. #endif /* __GNUC__ */
  16.  
  17. #include <iostream.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include "tblock.h"
  23. #include "text-table.h"
  24. #include "lib.h"
  25.  
  26. struct rdata
  27. {
  28.     struct wd_info w;
  29.     const char *data;
  30. };
  31.  
  32.  
  33. /* Print out a number of spaces */
  34. static inline void p_sp(int n, FILE *out)
  35. {
  36.     int i;
  37.  
  38.     for (i=0; i<n; i++)
  39.     fputc(' ', out);
  40. }
  41.  
  42. /* Print row after folding of columns has been done */
  43. static void basic_print_row(int ncols,
  44.                 const struct rdata *cols,
  45.                 char sep, FILE *out)
  46. {    
  47.     const char **lptr, *s, *t;
  48.     int i, flg, nsp;
  49.     align_t al;
  50.     num_info n;
  51.  
  52.     /* Alloca line position pointers */
  53.     if ((lptr=(const char **) alloca(ncols*sizeof(const char *)))==NULL)
  54.     {
  55.     fprintf(stderr, "basic_print_row: fatal alloca failure\n");
  56.     exit(1);
  57.     }
  58.  
  59.     for (i=0; i<ncols; i++)
  60.     lptr[i]=cols[i].data;
  61.     
  62.     while (1)
  63.     {
  64.     /* Check for some content */
  65.     flg=0;
  66.     for (i=0; i<ncols; i++)
  67.         if (*lptr[i]!='\0')
  68.         flg=1;
  69.     if (!flg) break;
  70.  
  71.     /* Print the content */
  72.     for (i=0; i<ncols; i++)
  73.     {
  74.         s=lptr[i];
  75.  
  76.         /* Find the extent and decimal point pos of current item */
  77.         for (t=s, nsp=cols[i].w.width; *t!='\0'; nsp--, t++)
  78.         {
  79.         if (*t=='\n')
  80.             break;
  81.         }
  82.  
  83.         if (s==t)
  84.         {
  85.         p_sp(nsp, out);
  86.         }
  87.         else
  88.         {
  89.         /* There is some content, print it */
  90.         al=cols[i].w.align;
  91.         if (cols[i].w.dp_col>=0)
  92.         {
  93.             n=scan_num(s);
  94.             if (n.dot_pos!=-1)
  95.             {
  96.             p_sp(cols[i].w.dp_col-n.dot_pos, out);
  97.             fwrite((void *) s, sizeof(char), t-s, out);
  98.             p_sp(nsp-cols[i].w.dp_col+n.dot_pos, out);
  99.             al=ALIGN_DP;
  100.             }
  101.         }
  102.  
  103.         switch(al)
  104.         {
  105.         case ALIGN_DP:
  106.             break;
  107.  
  108.         case ALIGN_LEFT:
  109.             fwrite((void *) s, sizeof(char), t-s, out);
  110.             p_sp(nsp, out);
  111.             break;
  112.  
  113.         case ALIGN_CENTER:
  114.             p_sp(nsp/2, out);
  115.             fwrite((void *) s, sizeof(char), t-s, out);
  116.             p_sp(nsp-(nsp/2), out); // Avoid rounding related problems
  117.             break;
  118.  
  119.         case ALIGN_RIGHT:
  120.             p_sp(nsp, out);
  121.             fwrite((void *) s, sizeof(char), t-s, out);
  122.             break;
  123.  
  124.         default:
  125.             fprintf(stderr,"basic_print_row: Invalid alignment\n");
  126.             break;
  127.         }
  128.         }
  129.         fputc(sep, out);    // Seperate columns by a space
  130.  
  131.         /* Update lptr[i] */
  132.         if (*t=='\n')
  133.         t++;        // Advance past newlines;
  134.         lptr[i]=t;
  135.     }
  136.     fputc('\n', out);    // Print out a newline
  137.     }
  138. }
  139.  
  140. /* Split the elements of a row */
  141. static void print_row(int ncols, const struct rdata *dp, FILE *out)
  142. {
  143.     static const char null_string[]={'\0'};
  144.     struct rdata *rd; 
  145.     tblock *d;
  146.     char *s, *t;
  147.     int i;
  148.  
  149.     /* Allocate structures */
  150.     if ((rd=(struct rdata *) alloca(ncols*sizeof(rdata)))==NULL)
  151.     {
  152.     fprintf(stderr, "print_row: fatal alloca failure\n");
  153.     exit(1);
  154.     }
  155.     
  156.     /* Fold lines */
  157.     for (i=0; i<ncols; i++)
  158.     {
  159.     rd[i].w=dp[i].w;
  160.     if (dp[i].data==NULL)
  161.     {
  162.         rd[i].data=null_string; // Avoid complication of null in
  163.                     // basic_print_row
  164.         continue;            // Move on to next item
  165.     }
  166.  
  167.     d=word_wrap(dp[i].data, "\n", "\n", dp[i].w.width, 0);
  168.     if ((rd[i].data=strdup(*d))==NULL)
  169.     {
  170.         fprintf(stderr, "text_table::print_row: fatal alloca failure\n");
  171.         exit(1);
  172.     }
  173.     else
  174.     {
  175.         /* Filter out CH_SUSPECT */
  176.         for(s=t=(char *) rd[i].data; *s!='\0'; s++)
  177.         {
  178.         if (*s==CH_SUSPECT)
  179.             continue;
  180.         *(t++)=*s;
  181.         }
  182.         *t='\0';
  183.     }        
  184.     delete(d);
  185.     }
  186.     basic_print_row(ncols, rd, ' ', out); // Printing the rows is actually
  187.                       // quite complex.
  188.     for (i=0; i<ncols; i++)
  189.     {
  190.     if (rd[i].data!=null_string)
  191.         free((void *) rd[i].data);    // Free data
  192.     }
  193. }
  194.  
  195.  
  196. /* O(n^2) table width reduction algorithm, n is small in almost all cases */
  197. static void shrink_widths(int ncols, struct rdata *cols, int mtw)
  198. {
  199.     int i, j, tw, maxw;
  200.  
  201.     for (tw=0, i=0; i<ncols; i++)
  202.     tw+=cols[i].w.width;
  203.  
  204.     mtw-=ncols;            // Take account of column seperators
  205.  
  206.     /* Simply reduce the maximum width column width by one until
  207.        enougn has been trimed */
  208.     while (tw>mtw)
  209.     {
  210.     maxw=0; j=-1;
  211.     for (i=0; i<ncols; i++)
  212.     {
  213.         if (maxw<cols[i].w.width && cols[i].w.align!=ALIGN_DP)
  214.         {
  215.         j=i;
  216.         maxw=cols[i].w.width;
  217.         }
  218.     }
  219.  
  220.     if (j==-1)
  221.     {
  222.         fprintf(stderr, "Can not shrink overwidth table\n");
  223.         continue;
  224.     }
  225.     cols[j].w.width--;
  226.     tw--;
  227.     }
  228. }
  229.         
  230. /* Returns NULL or text message */
  231. const char *text_table::print_table(int wd, FILE *out)
  232. {
  233.     int i,j;
  234.     struct rdata *d;
  235.     const struct col_info *col;
  236.  
  237.     if ((d=(struct rdata *) alloca(cols*sizeof(struct rdata)))==NULL)
  238.     {
  239.     cerr<<"text_table::print_table alloca failute (fatal)\n";
  240.     return "[Table omitted due to lack of memory]";
  241.     }
  242.     if (cols==0 || rows==0)
  243.     {
  244.     fputs("[empty tabel ignored]\n", out);
  245.     return "[Ignored empty table]";
  246.     }
  247.  
  248.     for (i=0, col=cdata; col!=NULL; i++, col=col->next)
  249.     d[i].w=find_width(rows, col->data);
  250.     shrink_widths(cols, d, wd);
  251.  
  252.     for (i=0; i<rows; i++)
  253.     {
  254.     for (j=0, col=cdata; col!=NULL; j++, col=col->next)
  255.         d[j].data=(col->data)[i];
  256.     print_row(cols, d, out);
  257.     }
  258.     return NULL;
  259. }
  260.  
  261. /* Set */
  262. int text_table::set(int c, int r, const char *s)
  263. {
  264.     struct col_info *col;
  265.     int i;
  266.  
  267.     if (c<0 || c>=cols || r<0 || r>=rows)
  268.     {
  269.     cerr<<"Invalid request to set "<<c<<','<<r<<" in "
  270.         <<cols<<'x'<<rows<<" table (value "<<s<<")\n";
  271.     return 0;
  272.     }
  273.  
  274.     for (col=cdata, i=0; i<c && col!=NULL; i++, col=col->next) ;   
  275.     if (col!=NULL)
  276.     {
  277.     if (col->data[r]!=NULL)
  278.         free((void *) col->data[r]);
  279.     col->data[r]=strdup(s);
  280.     }
  281.     return 1;
  282. }
  283.  
  284.     
  285. /* Constructor */
  286. text_table::text_table(int c, int r)
  287. {
  288.     int i, j;
  289.     struct col_info *col, **nptr;
  290.  
  291.     cols=c;
  292.     rows=r;
  293.     cdata=NULL;            // Hardenning against cols=0
  294.     for (nptr=&cdata, i=0; i<cols; i++)
  295.     {
  296.     col=new(struct col_info);
  297.     *nptr=col;
  298.     col->next=NULL;
  299.     nptr=&(col->next);
  300.     if ((col->data=
  301.          (const char **) malloc(rows*(sizeof(const char *))))==NULL)
  302.     {
  303.         cerr<<"text_table::constructor: malloc failure (fatal)\n";
  304.         exit(1);
  305.     }
  306.     for (j=0; j<rows; j++)
  307.         (col->data)[j]=NULL;
  308.     }
  309. }
  310.  
  311. /* Destructor */
  312. text_table::~text_table(int c, int r)
  313. {
  314.     int i;
  315.     struct col_info *col, *nxt;
  316.     
  317.     for (col=cdata; col!=NULL;)
  318.     {
  319.     for (i=0; i<rows; i++)
  320.         if (col->data[i]==NULL)
  321.         free((void *) col->data[i]);
  322.     nxt=col->next;
  323.     free(col);
  324.     col=nxt;
  325.     }
  326. }
  327.