home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / YellowBox / Kits / MiscTableScroll-138.1 / Palettes / MiscTableScroll / Framework / MiscExporterASCII.M < prev    next >
Encoding:
Text File  |  1998-03-31  |  16.1 KB  |  623 lines

  1. //=============================================================================
  2. //
  3. //    Copyright (C) 1996,1997,1998 by Paul S. McCarthy and Eric Sunshine.
  4. //        Written by Paul S. McCarthy and Eric Sunshine.
  5. //                All Rights Reserved.
  6. //
  7. //    This notice may not be removed from this source code.
  8. //
  9. //    This object is included in the MiscKit by permission from the authors
  10. //    and its use is governed by the MiscKit license, found in the file
  11. //    "License.rtf" in the MiscKit distribution.  Please refer to that file
  12. //    for a list of all applicable permissions and restrictions.
  13. //
  14. //=============================================================================
  15. //-----------------------------------------------------------------------------
  16. // MiscExporterASCII.M
  17. //
  18. //    Routines that export the contents of an MiscTableScroll to
  19. //    various ASCII text formats.
  20. //
  21. // TODO:
  22. //    * Genericize for use with Matrix, DBTableView.
  23. //    * Maybe provide option for <CR><LF> line terminators.
  24. //-----------------------------------------------------------------------------
  25. //-----------------------------------------------------------------------------
  26. // $Id: MiscExporterASCII.M,v 1.4 98/03/29 23:44:11 sunshine Exp $
  27. // $Log:    MiscExporterASCII.M,v $
  28. // Revision 1.4  98/03/29  23:44:11  sunshine
  29. // v138.1: #import was missing "MiscTableScroll/" for public header.
  30. // 
  31. // Revision 1.3  97/03/11  05:33:04  sunshine
  32. // v114.1: colGrid --> columnGrid, colTitleMode --> columnTitleMode
  33. // 
  34. // Revision 1.2  97/02/07  13:53:28  sunshine
  35. // v108: Ported to OPENSTEP 4.1 (gamma).
  36. //-----------------------------------------------------------------------------
  37. #import "MiscExporterPrivate.h"
  38. #import    <MiscTableScroll/MiscTableScroll.h>
  39. #import    "bool.h"
  40. extern "Objective-C" {
  41. #import    <AppKit/NSCell.h>
  42. #import    <AppKit/NSText.h>
  43. }
  44. extern "C" {
  45. #import    <stdio.h>
  46. }
  47.  
  48.  
  49. //=============================================================================
  50. // UTILITY ROUTINES
  51. //=============================================================================
  52. //-----------------------------------------------------------------------------
  53. // colgrid
  54. //-----------------------------------------------------------------------------
  55. inline static void colgrid( MiscExportGridMode grid, FILE* fp, char ch = '|' )
  56.     {
  57.     if (grid == MISC_EXPORT_GRID_LINE)
  58.     fputc( ch, fp );
  59.     else if (grid == MISC_EXPORT_GRID_SPACE)
  60.     fputc( ' ', fp );
  61.     }
  62.  
  63.  
  64. //-----------------------------------------------------------------------------
  65. // endline
  66. //-----------------------------------------------------------------------------
  67. inline static void endline( MiscExportGridMode grid, FILE* fp, char ch = '|' )
  68.     {
  69.     colgrid( grid, fp, ch );
  70.     fputc( '\n', fp );
  71.     }
  72.  
  73.  
  74. //-----------------------------------------------------------------------------
  75. // rowTitleHeader
  76. //-----------------------------------------------------------------------------
  77. inline static void rowTitleHeader( int len, MiscExportGridMode grid, FILE* fp )
  78.     {
  79.     if (len > 0)
  80.     {
  81.     colgrid( grid, fp );
  82.     pad( len, fp );
  83.     }
  84.     }
  85.  
  86.  
  87. //-----------------------------------------------------------------------------
  88. // rowgrid
  89. //-----------------------------------------------------------------------------
  90. static void rowgrid( MiscExportGridMode row_grid, MiscExportGridMode col_grid,
  91.             int row_title_width,
  92.             int ncols, int const* widths, FILE* fp )
  93.     {
  94.     if (row_grid != MISC_EXPORT_GRID_OFF)
  95.     {
  96.     char row_grid_ch = ' ';
  97.     char col_grid_ch = ' ';
  98.  
  99.     if (row_grid == MISC_EXPORT_GRID_LINE)
  100.         {
  101.         row_grid_ch = '-';
  102.         if (col_grid == MISC_EXPORT_GRID_LINE)
  103.         col_grid_ch = '+';
  104.         }
  105.     else if (col_grid == MISC_EXPORT_GRID_LINE)
  106.         col_grid_ch = '|';
  107.  
  108.     if (row_title_width > 0)
  109.         {
  110.         colgrid( col_grid, fp, col_grid_ch );
  111.         repchar( row_title_width, row_grid_ch, fp );
  112.         }
  113.  
  114.     int const* w = widths;
  115.     for (int c = 0; c < ncols; c++,w++)
  116.         {
  117.         colgrid( col_grid, fp, col_grid_ch );
  118.         repchar( *w, row_grid_ch, fp );
  119.         }
  120.  
  121.     endline( col_grid, fp, col_grid_ch );
  122.     }
  123.     }
  124.  
  125.  
  126. //-----------------------------------------------------------------------------
  127. // cell_alignment
  128. //-----------------------------------------------------------------------------
  129. static int cell_alignment( id cell )
  130.     {
  131.     int rc = NSLeftTextAlignment;
  132.     if (cell != 0 && [cell respondsToSelector:@selector(alignment)])
  133.     rc = [cell alignment];
  134.     return rc;
  135.     }
  136.  
  137.  
  138. //-----------------------------------------------------------------------------
  139. // cell_str
  140. //-----------------------------------------------------------------------------
  141. static NSString* cell_str( id cell )
  142.     {
  143.     NSString* s = @"";
  144.     if (cell != 0 && [cell respondsToSelector:@selector(stringValue)])
  145.     s = [cell stringValue];
  146.     return s;
  147.     }
  148.  
  149.  
  150.  
  151. //=============================================================================
  152. // CHAR FILTER
  153. //=============================================================================
  154.  
  155. //-----------------------------------------------------------------------------
  156. // MiscCharFilter
  157. //    Base class for the output character filters.
  158. //    Base class is unfiltered.
  159. //-----------------------------------------------------------------------------
  160. class MiscCharFilter
  161.     {
  162. protected:
  163.     FILE* fp;
  164.     char const* s;
  165.     int len;
  166.     int pos;
  167. public:
  168.     MiscCharFilter( FILE* f ): fp(f), s(0), len(0), pos(0) {}
  169. virtual    ~MiscCharFilter();
  170. virtual    char nextChar();
  171.     void reset( char const* t, int n ) { s = t; len = n; pos = 0; }
  172.     void reset( char const* t ) { s = t; len = safe_strlen(s); pos = 0; }
  173.     void reset( NSString* t ) { reset( [t lossyCString] ); }
  174.     void reset()            { pos = 0; }
  175.     int length() const        { return len; }
  176.     bool done() const        { return pos >= len; }
  177.     bool more() const        { return pos < len; }
  178. virtual    void write();
  179.     void write( int field_width );
  180.     void left( int field_width );
  181.     void center( int field_width );
  182.     void right( int field_width );
  183. static    void pad( int n, FILE* f, char ch=' ' );
  184.     void pad( int n, char ch=' ' )    { pad( n, fp, ch ); }
  185.     };
  186.  
  187. MiscCharFilter::~MiscCharFilter() {}
  188. char MiscCharFilter::nextChar()
  189.     {
  190.     char c = '\0';
  191.     if (pos < len)
  192.         c = s[pos++];
  193.     return c;
  194.     }
  195.  
  196.  
  197. void MiscCharFilter::pad( int n, FILE* fp, char ch )
  198.     {
  199.     while (n-- > 0)
  200.     fputc( ch, fp );
  201.     }
  202.  
  203.  
  204. void MiscCharFilter::write()
  205.     {
  206.     while (more())
  207.     fputc( nextChar(), fp );
  208.     }
  209.  
  210.  
  211. void MiscCharFilter::write( int w )
  212.     {
  213.     while (w-- > 0)
  214.     fputc( nextChar(), fp );
  215.     }
  216.  
  217.  
  218. void MiscCharFilter::left( int w )
  219.     {
  220.     int const delta = w - length();
  221.     if (delta <= 0)
  222.     write( w );
  223.     else
  224.     {
  225.     write();
  226.     pad( delta );
  227.     }
  228.     }
  229.  
  230.  
  231. void MiscCharFilter::center( int w )
  232.     {
  233.     int const delta = w - length();
  234.     if (delta <= 0)
  235.     write( w );
  236.     else
  237.     {
  238.     int const left_pad = (delta >> 1);
  239.     int const right_pad = delta - left_pad;
  240.     pad( left_pad );
  241.     write();
  242.     pad( right_pad );
  243.     }
  244.     }
  245.  
  246.  
  247. void MiscCharFilter::right( int w )
  248.     {
  249.     int const delta = w - length();
  250.     if (delta <= 0)
  251.     write( w );
  252.     else
  253.     {
  254.     pad( delta );
  255.     write();
  256.     }
  257.     }
  258.  
  259.  
  260. //-----------------------------------------------------------------------------
  261. // MiscTabFilter
  262. //    Output character filter for the ASCII fixed and tab-separated formats
  263. //    Converts tabs, carriage-returns and newlines into space characters.
  264. //-----------------------------------------------------------------------------
  265. class MiscTabFilter : public MiscCharFilter
  266.     {
  267. public:
  268.     MiscTabFilter( FILE* f ): MiscCharFilter(f) {}
  269. virtual    char nextChar();
  270.     };
  271.  
  272. char MiscTabFilter::nextChar()
  273.     {
  274.     char c = '\0';
  275.     if (pos < len)
  276.         {
  277.         c = s[pos++];
  278.         if (c == '\t' || c == '\n' || c == '\r')
  279.         c = ' ';
  280.         }
  281.     return c;
  282.     }
  283.  
  284.  
  285.  
  286. //-----------------------------------------------------------------------------
  287. // MiscDelimFilter
  288. //    Output character filter for the ASCII delimited format.
  289. //    Converts carriage-returns and newlines into space characters.
  290. //    Converts double-quote characters into single quote characters.
  291. //-----------------------------------------------------------------------------
  292. class MiscDelimFilter : public MiscCharFilter
  293.     {
  294. public:
  295.     MiscDelimFilter( FILE* f ): MiscCharFilter(f) {}
  296. virtual    char nextChar();
  297. virtual    void write();
  298.     };
  299.  
  300. char MiscDelimFilter::nextChar()
  301.     {
  302.     char c = '\0';
  303.     if (pos < len)
  304.         {
  305.         c = s[pos++];
  306.         if (c == '\n' || c == '\r')
  307.         c = ' ';
  308.         else if (c == '"')
  309.         c = '\'';
  310.         }
  311.     return c;
  312.     }
  313.  
  314. void MiscDelimFilter::write()
  315.     {
  316.     if (s != 0)
  317.         {
  318.         fputc( '"', fp );
  319.         MiscCharFilter::write();
  320.         fputc( '"', fp );
  321.         }
  322.     }
  323.  
  324.  
  325.  
  326.  
  327. //=============================================================================
  328. // MiscExporter(ASCII)
  329. //=============================================================================
  330. @implementation MiscExporter(ASCII)
  331.  
  332. //-----------------------------------------------------------------------------
  333. // fixedWidths:::
  334. //-----------------------------------------------------------------------------
  335. - (int*)fixedWidths:(int)nrows :(int)ncols :(int const*)map
  336.     {
  337.     int* const widths = (int*) calloc( ncols, sizeof(*widths) );
  338.  
  339.     for (int r = 0; r < nrows; r++)
  340.     {
  341.     int* w = widths;
  342.     for (int c = 0; c < ncols; c++,w++)
  343.         {
  344.         int const len = safe_strlen( str_at(r, map[c], tableScroll) );
  345.         if (*w < len)
  346.         *w = len;
  347.         }
  348.     }
  349.  
  350.     return widths;
  351.     }
  352.  
  353.  
  354. //-----------------------------------------------------------------------------
  355. // fixedHeadersOn:::::
  356. //-----------------------------------------------------------------------------
  357. - (void)fixedHeadersOn:(int)row_title_width :(int)ncols
  358.             :(int const*)map :(int*)widths :(FILE*)fp
  359.     {
  360.     int c;
  361.     int* wp = widths;
  362.     for (c = 0; c < ncols; c++,wp++)
  363.     {
  364.     int const len = safe_strlen( col_title(map[c], tableScroll) );
  365.     if (*wp < len)
  366.         *wp = len;
  367.     }
  368.  
  369.     rowgrid( rowGrid, columnGrid, row_title_width, ncols, widths, fp );
  370.  
  371.     rowTitleHeader( row_title_width, columnGrid, fp );
  372.  
  373.     MiscTabFilter filt( fp );
  374.     int const* w = widths;
  375.     for (c = 0; c < ncols; c++,w++)
  376.     {
  377.     colgrid( columnGrid, fp );
  378.     filt.reset( col_title( map[c], tableScroll ) );
  379.     filt.center( *w );
  380.     }
  381.  
  382.     endline( columnGrid, fp );
  383.     }
  384.  
  385.  
  386.  
  387. //-----------------------------------------------------------------------------
  388. // fixedHeadersWrap:::::
  389. //-----------------------------------------------------------------------------
  390. - (void)fixedHeadersWrap:(int)row_title_width :(int)ncols
  391.             :(int const*)map :(int*)widths :(FILE*)fp
  392.     {
  393.     int c;
  394.     int max_lines = 1;
  395.  
  396.     int* wp = widths;
  397.     for (c = 0; c < ncols; c++,wp++)
  398.     {
  399.     int const len = safe_strlen( col_title(map[c], tableScroll) );
  400.     if (len > *wp)
  401.         {
  402.         if (*wp == 0)
  403.         *wp = 1;
  404.         int const num_lines = (len + (*wp - 1)) / *wp;
  405.         if (max_lines < num_lines)
  406.         max_lines = num_lines;
  407.         }
  408.     }
  409.  
  410.     rowgrid( rowGrid, columnGrid, row_title_width, ncols, widths, fp );
  411.  
  412.     MiscTabFilter filt( fp );
  413.     for (int i = 0; i < max_lines; i++)
  414.     {
  415.     rowTitleHeader( row_title_width, columnGrid, fp );
  416.     int const* w = widths;
  417.     for (c = 0; c < ncols; c++,w++)
  418.         {
  419.         colgrid( columnGrid, fp );
  420.         NSString* const s = col_title( map[c], tableScroll );
  421.         char const* const cs = [s lossyCString];
  422.         int const len = safe_strlen( cs );
  423.         bool skip = true;
  424.         if (len > 0)
  425.         {
  426.         int const num_lines = (len + (*w - 1)) / *w;
  427.         int const first_line = max_lines - num_lines;
  428.         if (i >= first_line)
  429.             {
  430.             skip = false;
  431.             if (len < *w)
  432.             {
  433.             filt.reset( cs, len );
  434.             filt.center( *w );
  435.             }
  436.             else
  437.             {
  438.             int const start_pos = (i - first_line) * *w;
  439.             filt.reset( cs + start_pos, len - start_pos );
  440.             filt.left( *w );
  441.             }
  442.             }
  443.         }
  444.         if (skip)
  445.         filt.pad( *w );
  446.         }
  447.     endline( columnGrid, fp );
  448.     }
  449.     }
  450.  
  451.  
  452.  
  453. //-----------------------------------------------------------------------------
  454. // fixedHeadersTrunc:::::
  455. //-----------------------------------------------------------------------------
  456. - (void)fixedHeadersTrunc:(int)row_title_width :(int)ncols 
  457.             :(int const*)map :(int const*)widths :(FILE*)fp
  458.     {
  459.     rowgrid( rowGrid, columnGrid, row_title_width, ncols, widths, fp );
  460.  
  461.     rowTitleHeader( row_title_width, columnGrid, fp );
  462.  
  463.     MiscTabFilter filt(fp);
  464.     int const* w = widths;
  465.     for (int c = 0; c < ncols; c++,w++)
  466.     {
  467.     colgrid( columnGrid, fp );
  468.     filt.reset( col_title( map[c], tableScroll ) );
  469.     filt.center( *w );
  470.     }
  471.  
  472.     endline( columnGrid, fp );
  473.     }
  474.  
  475.  
  476.  
  477. //-----------------------------------------------------------------------------
  478. // fixedHeaders:::::
  479. //-----------------------------------------------------------------------------
  480. - (void)fixedHeaders:(int)row_title_width
  481.             :(int)ncols :(int const*)map :(int*)widths :(FILE*)fp
  482.     {
  483.     switch (columnTitleMode)
  484.     {
  485.     default:
  486.     case MISC_EXPORT_TITLES_ON:
  487.         [self fixedHeadersOn:row_title_width:ncols:map:widths:fp];
  488.         break;
  489.     case MISC_EXPORT_TITLES_WRAP:
  490.         [self fixedHeadersWrap:row_title_width:ncols:map:widths:fp];
  491.         break;
  492.     case MISC_EXPORT_TITLES_TRUNCATE:
  493.         [self fixedHeadersTrunc:row_title_width:ncols:map:widths:fp];
  494.         break;
  495.     case MISC_EXPORT_TITLES_OFF:
  496.         break;
  497.     }
  498.     if (columnTitleMode != MISC_EXPORT_TITLES_OFF)
  499.     rowgrid( MISC_EXPORT_GRID_LINE,
  500.         columnGrid, row_title_width, ncols, widths, fp );
  501.     }
  502.  
  503.  
  504. //-----------------------------------------------------------------------------
  505. // exportFixed: [public]
  506. //-----------------------------------------------------------------------------
  507. - (void)exportFixed:(FILE*)fp
  508.     {
  509.     int const nrows = [tableScroll numberOfRows];
  510.     int const ncols = [tableScroll numberOfColumns];
  511.     int* col_map = [self makeColMap:ncols];
  512.     int* widths = [self fixedWidths:nrows:ncols:col_map];
  513.     int const row_title_width = [self rowTitleCharWidth:nrows];
  514.  
  515.     [self fixedHeaders:row_title_width:ncols:col_map:widths:fp];
  516.  
  517.     MiscTabFilter filt(fp);
  518.     for (int r = 0; r < nrows; r++)
  519.     {
  520.     int const pr = row_at( r, tableScroll );
  521.     if (row_title_width > 0)
  522.         {
  523.         colgrid( columnGrid, fp );
  524.         filt.reset( row_title( pr, tableScroll ) );
  525.         filt.center( row_title_width );
  526.         }
  527.     int const* w = widths;
  528.     for (int c = 0; c < ncols; c++,w++)
  529.         {
  530.         colgrid( columnGrid, fp );
  531.         id cell = cell_at( pr, col_map[c], tableScroll );
  532.         filt.reset( cell_str( cell ) );
  533.         switch (cell_alignment( cell ))
  534.         {
  535.         default:
  536.         case NSLeftTextAlignment:   filt.left( *w );    break;
  537.         case NSRightTextAlignment:  filt.right( *w );    break;
  538.         case NSCenterTextAlignment: filt.center( *w );    break;
  539.         }
  540.         }
  541.     endline( columnGrid, fp );
  542.     rowgrid( rowGrid, columnGrid, row_title_width, ncols, widths, fp );
  543.     }
  544.  
  545.     free( widths );
  546.     free( col_map );
  547.     }
  548.  
  549.  
  550. //-----------------------------------------------------------------------------
  551. // exportDelimited:
  552. //-----------------------------------------------------------------------------
  553. - (void)exportDelimited:(FILE*)fp :(MiscCharFilter*)filt :(char) separator
  554.     {
  555.     int const nrows = [tableScroll numberOfRows];
  556.     int const ncols = [tableScroll numberOfColumns];
  557.     BOOL const row_titles = (rowTitleMode != MISC_EXPORT_TITLES_OFF);
  558.  
  559.     int* col_map = [self makeColMap:ncols];
  560.  
  561.     if (columnTitleMode != MISC_EXPORT_TITLES_OFF)
  562.     {
  563.     if (row_titles)
  564.         {
  565.         NSString* rt = @"Row Titles";
  566.         filt->reset( rt );
  567.         filt->write();
  568.         fputc( separator, fp );
  569.         }
  570.     for (int c = 0; c < ncols; c++)
  571.         {
  572.         if (c > 0)
  573.         fputc( separator, fp );
  574.         filt->reset( col_title( col_map[c], tableScroll ) );
  575.         filt->write();
  576.         }
  577.     fputc( '\n', fp );
  578.     }
  579.  
  580.     for (int r = 0; r < nrows; r++)
  581.     {
  582.     int const pr = row_at( r, tableScroll );
  583.     if (row_titles)
  584.         {
  585.         filt->reset( row_title( pr, tableScroll ) );
  586.         filt->write();
  587.         fputc( separator, fp );
  588.         }
  589.     for (int c = 0; c < ncols; c++)
  590.         {
  591.         if (c > 0)
  592.         fputc( separator, fp );
  593.         filt->reset( str_at( pr, col_map[c], tableScroll ) );
  594.         filt->write();
  595.         }
  596.     fputc( '\n', fp );
  597.     }
  598.  
  599.     free( col_map );
  600.     }
  601.  
  602.  
  603. //-----------------------------------------------------------------------------
  604. // exportTab: [public]
  605. //-----------------------------------------------------------------------------
  606. - (void)exportTab:(FILE*)fp
  607.     {
  608.     MiscTabFilter filt( fp );
  609.     [self exportDelimited:fp:&filt:'\t'];
  610.     }
  611.  
  612.  
  613. //-----------------------------------------------------------------------------
  614. // exportDelimited: [public]
  615. //-----------------------------------------------------------------------------
  616. - (void)exportDelimited:(FILE*)fp
  617.     {
  618.     MiscDelimFilter filt( fp );
  619.     [self exportDelimited:fp:&filt:','];
  620.     }
  621.  
  622. @end
  623.