home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / conv123 / part02 / grph123.c < prev   
C/C++ Source or Header  |  1993-09-05  |  30KB  |  1,034 lines

  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5.  
  6. #include "lotus.h"
  7. #include "swapb.h"
  8.  
  9.  
  10. #define MAXHEADLINES 2
  11. #define MAXROWS 8192    /* dependent on 12-bit maximum value */
  12. #define MAXCOLS 53    /* arbitrary */
  13. #define MAXCOLWD 39    /* used only to calculate max input rec length */
  14.             /* and x data value length                     */
  15. #define MAXINRECLEN (MAXCOLS * MAXCOLWD + 5 * MAXCOLS)
  16. #define COLEXTEND 2    /* amount to widen columns for 123 */
  17.  
  18. FILE *infile, *outfile;
  19.  
  20. short current_row, current_graph;
  21. long current_offset;    /* output file offset */
  22.  
  23. short col_width[MAXCOLS], col_pos[MAXCOLS], col_type[MAXCOLS];
  24. short formula_start_row[MAXCOLS], formula_end_row[MAXCOLS];
  25. short formula_start_col, formula_end_col;
  26. short decimals(), dec_pl, col_dec_pl[MAXCOLS], row_dec_pl;
  27.  
  28. int  y_decpl[6];
  29. char *qtstr();
  30.  
  31. /***********************************/
  32. /* declare lotus record structures */
  33. /***********************************/
  34.  
  35. BOF BOFr;
  36.  
  37. RANGE RANGEr;
  38. CALCCOUNT CALCCOUNTr;
  39. CALCMODE CALCMODEr;
  40. CALCORDER CALCORDERr;
  41. SPLIT SPLITr;
  42. SYNC SYNCr;
  43. WINDOW1 WINDOW1r;
  44. COLW1 COLW1r;
  45. NGRAPH NGRAPHr;
  46. TABLE TABLEr;
  47. QRANGE QRANGEr;
  48. PRANGE PRANGEr;
  49. LABEL LABELr;
  50. /*  INTEGER INTEGERr; */
  51. NUMBER NUMBERr;
  52. FORMULA FORMULAr;    
  53. LEOF LEOFr;
  54.  
  55. /* now for the main data structure, which has limits -- this  */
  56. /* monster is (somewhat) necessary in order to allow the      */
  57. /* flexibility of getting all the data (and labels) in before */
  58. /* writing the NGRAPH record...                               */
  59.  
  60. struct {
  61.     char    x_item[MAXCOLWD+1];
  62.     double    y_item[6];
  63.     short    number_of_labels;
  64.     char    y_label[6][20];
  65. } graph_data[MAXCOLS];
  66.  
  67. /*****************************/
  68. /* finally, we begin         */
  69. /*****************************/
  70.  
  71. main(argc,argv)
  72. int argc;
  73. char *argv[];
  74. {
  75.  
  76. /**********************/
  77. /* main declarations  */
  78. /**********************/
  79.  
  80.     int fstat;
  81.     char c;
  82.     char *p, *bp, *cp, *fp, *sp, *sstat;
  83.     char inbuf[MAXINRECLEN + 1], util_buf[MAXINRECLEN + 1], util_buf2[100];
  84.     char infilename[96];
  85.     char outfilename[96];
  86.     char blank_buf[80];
  87.  
  88.     int i, j, k, l, debug, fs, us, type_ind, label_ready;
  89.  
  90.     unsigned short i1, j1, l1;
  91.  
  92.     short number_of_cols, number_of_rows;
  93.     short number_of_graphs, header_lines, max_title;
  94.     char   str_value[6][41];
  95.     double dbl_value[6];
  96.  
  97.     long RANGE_offset;
  98.  
  99. /**************************************/
  100. /* initialize lotus record structures */
  101. /**************************************/
  102.  
  103.     int2s(swapb(BOF_op),BOFr.opcode);
  104.     int2s(swapb(BOF_len),BOFr.record_length);
  105.     int2s(swapb((unsigned short)1030),BOFr.ff_version);
  106.  
  107.     int2s(swapb(RANGE_op),RANGEr.opcode);
  108.     int2s(swapb(RANGE_len),RANGEr.record_length);
  109.     int2s(swapb((unsigned short)0),RANGEr.start_column);
  110.     int2s(swapb((unsigned short)0),RANGEr.start_row);
  111.     int2s(swapb((unsigned short)0),RANGEr.end_column);
  112.     int2s(swapb((unsigned short)0),RANGEr.end_row);
  113.  
  114.     int2s(swapb(CALCCOUNT_op),CALCCOUNTr.opcode);
  115.     int2s(swapb(CALCCOUNT_len),CALCCOUNTr.record_length);
  116.     *CALCCOUNTr.iteration_count = 1;
  117.  
  118.     int2s(swapb(CALCMODE_op),CALCMODEr.opcode);
  119.     int2s(swapb(CALCMODE_len),CALCMODEr.record_length);
  120.     *CALCMODEr.recalculation = 0xFF;    /* automatic recalc */
  121.  
  122.     int2s(swapb(CALCORDER_op),CALCORDERr.opcode);
  123.     int2s(swapb(CALCORDER_len),CALCORDERr.record_length);
  124.     *CALCORDERr.calc_order = 0x00;    /* natural order */
  125.  
  126.     int2s(swapb(SPLIT_op),SPLITr.opcode);
  127.     int2s(swapb(SPLIT_len),SPLITr.record_length);
  128.     *SPLITr.window_split = 0x00;    /* no window split */
  129.  
  130.     int2s(swapb(SYNC_op),SYNCr.opcode);
  131.     int2s(swapb(SYNC_len),SYNCr.record_length);
  132.     *SYNCr.window_sync = 0xFF;        /* window synchronized */
  133.  
  134.     int2s(swapb(WINDOW1_op),WINDOW1r.opcode);
  135.     int2s(swapb(WINDOW1_len),WINDOW1r.record_length);
  136.     int2s(swapb((unsigned short)0),WINDOW1r.cc_column);
  137.     int2s(swapb((unsigned short)0),WINDOW1r.cc_row);
  138.     *WINDOW1r.cell_format = 2;    /* two decimal places */
  139.     *WINDOW1r.unused1 = 0;
  140.     int2s(swapb((unsigned short)9),WINDOW1r.column_width);
  141.     int2s(swapb((unsigned short)8),WINDOW1r.ncol_on_screen);
  142.     int2s(swapb((unsigned short)20),WINDOW1r.nrow_on_screen);
  143.     int2s(swapb((unsigned short)0),WINDOW1r.leftmost_column);
  144.     int2s(swapb((unsigned short)0),WINDOW1r.top_row);
  145.     int2s(swapb((unsigned short)0),WINDOW1r.ntitle_col);
  146.     int2s(swapb((unsigned short)0),WINDOW1r.ntitle_row);
  147.     int2s(swapb((unsigned short)0),WINDOW1r.ltitle_col);
  148.     int2s(swapb((unsigned short)0),WINDOW1r.ttitle_row);
  149.     int2s(swapb((unsigned short)4),WINDOW1r.borderwd_col);
  150.     int2s(swapb((unsigned short)4),WINDOW1r.borderwd_row);
  151.     int2s(swapb((unsigned short)72),WINDOW1r.window_width);
  152.     *WINDOW1r.unused2 = 0;
  153.     *WINDOW1r.unused3 = 0;
  154.  
  155.     /* there are multiple of these, so just init basic elements for now */
  156.     int2s(swapb(COLW1_op),COLW1r.opcode);
  157.     int2s(swapb(COLW1_len),COLW1r.record_length);
  158.  
  159.  
  160.     /* there are multiple of these, so just init basic elements for now */
  161.     int2s(swapb(NGRAPH_op),NGRAPHr.opcode);
  162.     int2s(swapb(NGRAPH_len),NGRAPHr.record_length);
  163.  
  164.  
  165.     int2s(swapb(TABLE_op),TABLEr.opcode);
  166.     int2s(swapb(TABLE_len),TABLEr.record_length);
  167.     *TABLEr.table_ind = 0x00;        /* no table */
  168.     int2s(swapb((unsigned short)0xFFFF),TABLEr.table_start_column);
  169.     int2s(swapb((unsigned short)0),TABLEr.table_start_row);
  170.     int2s(swapb((unsigned short)0xFFFF),TABLEr.table_end_column);
  171.     int2s(swapb((unsigned short)0),TABLEr.table_end_row);
  172.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_start_column);
  173.     int2s(swapb((unsigned short)0),TABLEr.cell1_start_row);
  174.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_end_column);
  175.     int2s(swapb((unsigned short)0),TABLEr.cell1_end_row);
  176.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_start_column);
  177.     int2s(swapb((unsigned short)0),TABLEr.cell2_start_row);
  178.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_end_column);
  179.     int2s(swapb((unsigned short)0),TABLEr.cell2_end_row);
  180.  
  181.  
  182.     int2s(swapb(QRANGE_op),QRANGEr.opcode);
  183.     int2s(swapb(QRANGE_len),QRANGEr.record_length);
  184.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_start_column);
  185.     int2s(swapb((unsigned short)0),QRANGEr.input_start_row);
  186.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_end_column);
  187.     int2s(swapb((unsigned short)0),QRANGEr.input_end_row);
  188.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_start_column);
  189.     int2s(swapb((unsigned short)0),QRANGEr.output_start_row);
  190.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_end_column);
  191.     int2s(swapb((unsigned short)0),QRANGEr.output_end_row);
  192.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_start_column);
  193.     int2s(swapb((unsigned short)0),QRANGEr.criteria_start_row);
  194.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_end_column);
  195.     int2s(swapb((unsigned short)0),QRANGEr.criteria_end_row);
  196.     *QRANGEr.command = 0;        /* no command */
  197.  
  198.     int2s(swapb(PRANGE_op),PRANGEr.opcode);
  199.     int2s(swapb(PRANGE_len),PRANGEr.record_length);
  200.     int2s(swapb((unsigned short)0xFFFF),PRANGEr.start_column);
  201.     int2s(swapb((unsigned short)0),PRANGEr.start_row);
  202.     int2s(swapb((unsigned short)0xFFFF),PRANGEr.end_column);
  203.     int2s(swapb((unsigned short)0),PRANGEr.end_row);
  204.  
  205.     int2s(swapb(LABEL_op),LABELr.opcode);
  206.     *LABELr.format = 0xFF;    /* lotus default */
  207.     *LABELr.position = 0x27;    /* single quote ('), left justified */
  208.  
  209.  
  210.     int2s(swapb(NUMBER_op),NUMBERr.opcode);
  211.     int2s(swapb(NUMBER_len),NUMBERr.record_length);
  212.     *NUMBERr.format = 0xFF;    /* lotus default */
  213.  
  214.     int2s(swapb(FORMULA_op),FORMULAr.opcode);
  215.     *FORMULAr.format = 0xFF;    /* lotus default */
  216.     
  217.  
  218.     int2s(swapb(LEOF_op),LEOFr.opcode);
  219.     int2s(swapb(LEOF_len),LEOFr.record_length);
  220.  
  221. /************************************/
  222. /* Now some ordinary initialization */
  223. /************************************/
  224.  
  225.     current_offset = 0L;
  226.     current_graph = 0;
  227.     type_ind = 0;
  228.  
  229.     number_of_cols = 0;
  230.     number_of_rows = 0;
  231.     label_ready = 0;
  232.     max_title = 18;
  233.  
  234. /*******************************/
  235. /* assign files                */
  236. /*******************************/
  237.  
  238.     infile = stdin;            /* typical input is stdin (filter) */
  239.     outfile = stdout;            /* typical output is stdout (filter) */
  240.  
  241.     debug = 0;                /* don't do it */
  242.  
  243. /* Make sure blank_buf is initialized */
  244.  
  245.     for (i = 0; i < 80; i++)
  246.     blank_buf[i] = ' ';
  247.  
  248. /************************************/
  249. /* if there are input parameters,   */
  250. /* deal with them.                  */
  251. /************************************/
  252.  
  253.     if (argc > 3) {
  254.      fprintf(stderr,"Allowed parameters are input and output filenames.\n");
  255.     return(1);
  256.     }
  257.  
  258. /* open main data input file as a stream (maybe) */
  259.     if (argc > 1) {
  260.         fclose(infile);
  261.     strcpy(infilename,argv[1]);
  262.     if ((infile = fopen(infilename,"r")) == NULL) {
  263.         fprintf(stderr,"Open of input data file %s failed.\n",infilename);
  264.         return(1);
  265.     }
  266.     }
  267.  
  268. /* create and open output file directly (maybe) */
  269.     if (argc > 2) {
  270.         fclose(outfile);
  271.     strcpy(outfilename,argv[2]);
  272.     if ((outfile = fopen(outfilename,"w+")) == NULL) {
  273.         fprintf(stderr,"open of output data file %s failed.\n",outfilename);
  274.         fclose(infile);
  275.         return;
  276.     }
  277.     }
  278.  
  279. /************************************/
  280. /* now get to work translating it   */
  281. /************************************/
  282.  
  283.     if (get_header_info(inbuf,&number_of_graphs,&header_lines))
  284.     return(1);
  285.     if (number_of_graphs < 1) {
  286.     fprintf(stderr,"No graphs were detected...check input file.");
  287.     exit(1);
  288.     }
  289.  
  290.     current_row = number_of_graphs + 6;    /* leave room for titles & stuff */
  291.  
  292. /* fprintf(stderr,"Number of graphs: %d\n",number_of_graphs); */
  293.  
  294. /************************************/
  295. /* we've got SOMETHING, so go ahead */
  296. /* and start the 123 output!        */
  297. /************************************/
  298.  
  299.     p = (char *)(&BOFr);
  300.     fs = output_lotus_record(p);
  301.  
  302.     p = (char *)(&CALCMODEr);
  303.     fs = output_lotus_record(p);
  304.  
  305. #ifdef DEBUG
  306.     fprintf(stderr,"Offset after RANGE: %d\n",current_offset);
  307. #endif
  308.  
  309. /**********************************/
  310. /* create header labels           */
  311. /**********************************/
  312.  
  313.     create_lotus_label("Brooktree Corp. Confidential",0,0);
  314.     *LABELr.format = 0x7F;
  315.     create_lotus_label("Graph Name",0,2);
  316.     create_lotus_label("Graph Title",1,2);
  317.     create_lotus_label("================",0,3);
  318.     create_lotus_label("==============================",1,3);
  319.     *LABELr.format = 0xFF;
  320.  
  321. /**********************************/
  322. /* do the real work, and process  */
  323. /* all lines in the file          */
  324. /**********************************/
  325.  
  326.     while ((fs = getline(inbuf,MAXINRECLEN,infile)) != EOF) {
  327.  
  328. /**    formula_start_col = -1;        /* start out pessimistic */
  329. /**    formula_end_col = -1; **/
  330.     row_dec_pl = 0;
  331.  
  332.       if (trim(inbuf) > 0) {
  333.     type_ind = (int)(*inbuf);
  334. /* fprintf(stderr,"Now doing type: %c\n",*inbuf); */
  335.     switch (type_ind) {
  336.         case 'N':
  337.         case 'n':                /* graph name */
  338. /************************************/
  339. /* initialize named graph structure */
  340. /************************************/
  341.  
  342.     sp = (char *)&NGRAPHr;
  343.     sp = sp + 4;                /* skip over opcode & size */
  344.     for (i = 0; i < (sizeof(NGRAPHr) - 4); i++)
  345.     *sp++ = '\0';
  346.     *NGRAPHr.graph_type = (char)(0x04);        /* line graph */
  347.     *NGRAPHr.x_format = (char)(0x71);
  348.     *NGRAPHr.y_format = (char)(0x71);
  349.     int2s(swapb((unsigned short)(0x01)),NGRAPHr.skip_factor);
  350.     for (i = 0; i < 6; i++) {
  351.     int2s((unsigned short)(0xFFFF),NGRAPHr.yd_range[i].y_start_col);
  352.     int2s((unsigned short)(0xFFFF),NGRAPHr.yd_range[i].y_end_col);
  353.     int2s((unsigned short)(0xFFFF),NGRAPHr.yl_range[i].y_start_col);
  354.     int2s((unsigned short)(0xFFFF),NGRAPHr.yl_range[i].y_end_col);
  355.     NGRAPHr.y_lformat[i] = (char)(0x03);
  356.     y_decpl[i] = 2;
  357.     }
  358.  
  359.         strcpy(util_buf,&inbuf[1]);
  360.         us = trim(util_buf);
  361.         if (us > 0) {
  362.             sp = qtstr(util_buf,util_buf,15);
  363.             strcpy(NGRAPHr.graph_name,util_buf);
  364.         }
  365.         break;
  366.         case 'T':                /* First title */
  367.         strcpy(util_buf,&inbuf[1]);
  368.         us = trim(util_buf);
  369.         if (us > 0) {
  370.             sp = qtstr(util_buf,util_buf,39);
  371.             strcpy(NGRAPHr.first_title,util_buf);
  372.         }
  373.         break;
  374.         case 't':                /* Second title */
  375.         strcpy(util_buf,&inbuf[1]);
  376.         us = trim(util_buf);
  377.         if (us > 0) {
  378.             sp = qtstr(util_buf,util_buf,39);
  379.             strcpy(NGRAPHr.second_title,util_buf);
  380.         }
  381.         break;
  382.         case 'B':
  383.         case 'b':                /* x (bottom) title */
  384.         strcpy(util_buf,&inbuf[1]);
  385.         us = trim(util_buf);
  386.         if (us > 0) {
  387.             sp = qtstr(util_buf,util_buf,39);
  388.             strcpy(NGRAPHr.x_title,util_buf);
  389.             if (max_title < strlen(util_buf))
  390.             max_title = strlen(util_buf);
  391.         }
  392.         break;
  393.         case 'S':
  394.         case 's':                /* y (side) title */
  395.         strcpy(util_buf,&inbuf[1]);
  396.         us = trim(util_buf);
  397.         if (us > 0) {
  398.             sp = qtstr(util_buf,util_buf,39);
  399.             strcpy(NGRAPHr.y_title,util_buf);
  400.         }
  401.         break;
  402.         case 'G':
  403.         case 'g':
  404.         strcpy(util_buf,&inbuf[1]);
  405.         us = trim(util_buf);
  406.         if (us > 0) {
  407.             for (i = 0; i < 4; i++)
  408.             *str_value[i] = '\0';
  409.             us = sscanf(util_buf,"%s%s%s%s",str_value[0],
  410.                             str_value[1],
  411.                             str_value[2],
  412.                             str_value[3]);
  413.             if (us > 0) {
  414.             c = toupper((char)(*str_value[0]));
  415.             if (c == 'L')
  416.               *NGRAPHr.graph_type = (char)(0x04); /* line */
  417.             else
  418.             if (c == 'B')
  419.               *NGRAPHr.graph_type = (char)(0x01); /* bar */
  420.             else
  421.             if (c == 'P')
  422.               *NGRAPHr.graph_type = (char)(0x02); /* pie */
  423.             else
  424.             if (c == 'X')
  425.               *NGRAPHr.graph_type = (char)(0x00); /* xy */
  426.             else
  427.             if (c == 'S')
  428.               *NGRAPHr.graph_type = (char)(0x05); /* stacked bar */
  429.             }
  430.             if (us > 1) {
  431.             c = toupper((char)(*str_value[1]));
  432.             if (c == 'N')
  433.               *NGRAPHr.grid = (char)(0x00); /* none */
  434.             else
  435.             if (c == 'H')
  436.               *NGRAPHr.grid = (char)(0x01); /* horizontal */
  437.             else
  438.             if (c == 'V')
  439.               *NGRAPHr.grid = (char)(0x02); /* vertical */
  440.             else
  441.             if (c == 'B')
  442.               *NGRAPHr.grid = (char)(0x03); /* both horz & vert */
  443.             }
  444.             if (us > 2) {
  445.             c = toupper((char)(*str_value[2]));
  446.             if (c == 'B')
  447.               *NGRAPHr.color = (char)(0x00); /* black & white */
  448.             else
  449.             if (c == 'C')
  450.               *NGRAPHr.color = (char)(0xFF); /* color */
  451.             }
  452.             if (us > 3) {
  453.             sscanf(str_value[3],"%d",&i);
  454.             if (!i)
  455.                 i = 1;
  456.             if (i > 256)
  457.                 i = 256;
  458.             int2s(swapb((unsigned short)i),NGRAPHr.skip_factor);
  459.             }
  460.         }
  461.         break;
  462.         case 'l':                    /* legends */
  463.         strcpy(util_buf,&inbuf[1]);
  464.         us = trim(util_buf);
  465.         if (us > 0) {
  466.             sp = util_buf;
  467.             for (i = 0; *sp && (i < 6); i++) {
  468.             sp = qtstr(sp,util_buf2,19);
  469.             strcpy(NGRAPHr.y_legend[i],util_buf2);
  470.             }
  471.         }
  472.         break;
  473.         case 'P':
  474.         case 'p':
  475.         strcpy(util_buf,&inbuf[1]);
  476.         us = trim(util_buf);
  477.         if (us <= 0)
  478.             break;
  479.         us = sscanf(util_buf,"%d%d%d%d%d%d",&(y_decpl[0]),
  480.                             &(y_decpl[1]),
  481.                             &(y_decpl[2]),
  482.                             &(y_decpl[3]),
  483.                             &(y_decpl[4]),
  484.                             &(y_decpl[5]));
  485.                 for (i = 0; i < us; i++) {
  486.                     if (y_decpl[i] < 0) y_decpl[i] = 0;
  487.                     if (y_decpl[6] > 6) y_decpl[i] = 6;
  488.         }
  489. /* fprintf(stderr,"decpl: %d %d %d %d %d %d\n",y_decpl[0],y_decpl[1],y_decpl[2],
  490.                     y_decpl[3],y_decpl[4],y_decpl[5]); */
  491.         break;
  492.         case 'D':
  493.         case 'd':
  494.         strcpy(util_buf,&inbuf[1]);
  495.         us = trim(util_buf);
  496.         if (us <= 0)
  497.             break;
  498.         sp = util_buf;
  499.         sp = qtstr(sp,util_buf2,39);
  500.         if (strlen(util_buf2) > 0) {
  501.             number_of_rows++;
  502.             if (number_of_rows > MAXCOLS) {
  503.             fprintf(stderr,
  504.                                   "Maximum number of data points exceeded.");
  505.             exit(3);
  506.             }
  507.             i = number_of_rows - 1;
  508.             strcpy(graph_data[i].x_item,util_buf2);
  509.             for (j = 0; j < 6; j++) {
  510.             graph_data[i].y_item[j] = -2000000000.0;
  511.             *(graph_data[i].y_label[j]) = '\0';
  512.             }
  513.             us = sscanf(sp,"%lf%lf%lf%lf%lf%lf",
  514.                 &(graph_data[i].y_item[0]),
  515.                 &(graph_data[i].y_item[1]),
  516.                 &(graph_data[i].y_item[2]),
  517.                 &(graph_data[i].y_item[3]),
  518.                 &(graph_data[i].y_item[4]),
  519.                 &(graph_data[i].y_item[5]));
  520.             number_of_cols = us > number_of_cols ? us : number_of_cols;
  521.             graph_data[i].number_of_labels = 0;
  522.             label_ready = 1;
  523.         }            
  524.         break;
  525.         case 'L':                    /* labels */
  526.         strcpy(util_buf,&inbuf[1]);
  527.         us = trim(util_buf);
  528.         if (us <= 0)
  529.             break;
  530.         if (!label_ready)
  531.             break;
  532.         i = number_of_rows - 1;
  533.         sp = util_buf;
  534.         for (j = 0; *sp && (j < 6); j++) {
  535.             sp = qtstr(sp,util_buf2,19);
  536.             strcpy(graph_data[i].y_label[j],util_buf2);
  537.             (graph_data[i].number_of_labels)++;
  538.         }
  539.         label_ready = 0;
  540.  
  541.         break;
  542.         case 'X':
  543.         case 'x':
  544.         strcpy(util_buf,&inbuf[1]);
  545.         us = trim(util_buf);
  546.         if (us > 0) {
  547.             us = sscanf(util_buf,"%lf%lf",&dbl_value[0],&dbl_value[1]);
  548.             if (us > 0) stdbl(dbl_value[0],NGRAPHr.x_low_limit);
  549.             if (us > 1) stdbl(dbl_value[1],NGRAPHr.x_up_limit);
  550.             *NGRAPHr.x_scale = (char)(0xFF);
  551.         }
  552.         break;
  553.         case 'Y':
  554.         case 'y':
  555.         strcpy(util_buf,&inbuf[1]);
  556.         us = trim(util_buf);
  557.         if (us > 0) {
  558.             us = sscanf(util_buf,"%lf%lf",&dbl_value[0],&dbl_value[1]);
  559.             if (us > 0) stdbl(dbl_value[0],NGRAPHr.y_low_limit);
  560.             if (us > 1) stdbl(dbl_value[1],NGRAPHr.y_up_limit);
  561.             *NGRAPHr.y_scale = (char)(0xFF);
  562.         }
  563.         break;
  564.         case 'F':
  565.         case 'f':
  566.         strcpy(util_buf,&inbuf[1]);
  567.         us = trim(util_buf);
  568.         if (us > 0) {
  569.             us = sscanf(util_buf,"%s%s%s%s%s%s",str_value[0],
  570.                           str_value[1],
  571.                           str_value[2],
  572.                           str_value[3],
  573.                           str_value[4],
  574.                           str_value[5]);
  575.             for (i = 0; i < us; i++) {
  576.             c = toupper((char)(*str_value[i]));
  577.             if (c == 'N')
  578.               NGRAPHr.y_lformat[i] = (char)(0x00); /* none */
  579.             else
  580.             if (c == 'L')
  581.               NGRAPHr.y_lformat[i] = (char)(0x01); /* line */
  582.             else
  583.             if (c == 'S')
  584.               NGRAPHr.y_lformat[i] = (char)(0x02); /* symbol */
  585.             else
  586.             if (c == 'B')
  587.               NGRAPHr.y_lformat[i] = (char)(0x03); /* both l & s */
  588.             }
  589.           }
  590.         break;
  591.         case 'A':
  592.         case 'a':
  593.         strcpy(util_buf,&inbuf[1]);
  594.         us = trim(util_buf);
  595.         if (us > 0) {
  596.             us = sscanf(util_buf,"%s%s%s%s%s%s",str_value[0],
  597.                           str_value[1],
  598.                           str_value[2],
  599.                           str_value[3],
  600.                           str_value[4],
  601.                           str_value[5]);
  602.             for (i = 0; i < us; i++) {
  603.             c = toupper((char)(*str_value[i]));
  604.             if (c == 'C')
  605.               NGRAPHr.y_dlalign[i] = (char)(0x00); /* none */
  606.             else
  607.             if (c == 'R')
  608.               NGRAPHr.y_dlalign[i] = (char)(0x01); /* line */
  609.             else
  610.             if (c == 'B')
  611.               NGRAPHr.y_dlalign[i] = (char)(0x02); /* symbol */
  612.             else
  613.             if (c == 'L')
  614.               NGRAPHr.y_dlalign[i] = (char)(0x03); /* both l & s */
  615.             else
  616.             if (c == 'A')
  617.               NGRAPHr.y_dlalign[i] = (char)(0x04); /* both l & s */
  618.             }
  619.           }
  620.         break;
  621.         case 'E':
  622.         case 'e':
  623.  
  624.         if (number_of_cols <= 0)    /* if there's no y-data, */
  625.             break;            /* just bail out         */
  626.  
  627.         /* how about setting the first (0) column width  */
  628.  
  629.         p = (char *)(&COLW1r);
  630.         int2s(swapb((unsigned short)0),COLW1r.column_number);
  631.         int2s(swapb(max_title),COLW1r.column_width);
  632.         output_lotus_record(p);
  633.  
  634.         /* now let's put out the table of contents info */
  635.         *LABELr.position = 0x27;    /* single quote ('), lj  */
  636.  
  637.         p = (char *)(&LABELr);
  638.         j1 = 0; i1 = ++current_graph + 3;
  639.          create_lotus_label(NGRAPHr.graph_name,j1,i1);
  640.         j1 = 1;
  641.         create_lotus_label(NGRAPHr.first_title,j1,i1);
  642.  
  643.         /* Data values header */
  644.         j1 = 0; i1 = current_row++;
  645.         sprintf(util_buf,"Data for graph: %s (%s)",
  646.                   NGRAPHr.graph_name,NGRAPHr.first_title);
  647.         *LABELr.format = 0x7F;    /* lotus default */
  648.         create_lotus_label(util_buf,j1,i1);
  649.         *LABELr.format = 0xFF;    /* lotus default */
  650.  
  651.  
  652.         /* the x-value and y-value legends and ranges comes next */
  653.         j1 = 0; i1 = current_row;
  654.         create_lotus_label(NGRAPHr.x_title,j1,i1);
  655.  
  656.         int2s(swapb((unsigned short)1),NGRAPHr.x_start_col);
  657.         int2s(swapb(i1),NGRAPHr.x_start_row);
  658.         int2s(swapb(number_of_rows),NGRAPHr.x_end_col);
  659.         int2s(swapb(i1),NGRAPHr.x_end_row);
  660.  
  661.         for (j = 0; j < number_of_cols; j++) {
  662.             i1 = current_row + j + 1;
  663.             create_lotus_label(NGRAPHr.y_legend[j],j1,i1);
  664.         }
  665.  
  666.         for (j = 0; j < number_of_cols; j++) {
  667.             i1 = current_row + j + 1;
  668.  
  669.             int2s(swapb((unsigned short)1),
  670.                           NGRAPHr.yd_range[j].y_start_col);
  671.             int2s(swapb(i1),NGRAPHr.yd_range[j].y_start_row);
  672.             int2s(swapb(number_of_rows),NGRAPHr.yd_range[j].y_end_col);
  673.             int2s(swapb(i1),NGRAPHr.yd_range[j].y_end_row);
  674.  
  675.         /* the data-label range comes next; even if no labels */
  676.         /* note that this limits a graph to 127 data points   */
  677.             int2s(swapb((unsigned short)(number_of_rows + 2)),
  678.                           NGRAPHr.yl_range[j].y_start_col);
  679.             int2s(swapb(i1),NGRAPHr.yl_range[j].y_start_row);
  680.             int2s(swapb((unsigned short)((2 * number_of_rows) + 2)),
  681.                         NGRAPHr.yl_range[j].y_end_col);
  682.             int2s(swapb(i1),NGRAPHr.yl_range[j].y_end_row);
  683.  
  684.         }
  685.  
  686.         /* let's write that graph record! */
  687.         p = (char *)(&NGRAPHr);
  688.         output_lotus_record(p);
  689.  
  690.         /*******************************************************/
  691.         /* now for the data values (at last!)                  */
  692.         /*******************************************************/
  693.         *LABELr.position = 0x22;    /* double quote ("), rj */
  694.  
  695.         for (i = 0; i < number_of_rows; i++) {
  696.             /* set column width, hard-coded for now */
  697.             p = (char *)(&COLW1r);
  698.             j1 = i + 1;
  699.             i1 = 11 + COLEXTEND;
  700.             int2s(swapb(j1),COLW1r.column_number);
  701.             int2s(swapb(i1),COLW1r.column_width);
  702.             output_lotus_record(p);
  703.  
  704.             /* now for the independent data value (x-value) */
  705.             j1 = i + 1; i1 = current_row;
  706.             if (*NGRAPHr.graph_type)
  707.             create_lotus_label(graph_data[i].x_item,j1,i1);
  708.             else {
  709.             us = sscanf(graph_data[i].x_item,"%lf",&dbl_value[0]);
  710.             if (us && (dbl_value[0] > -2000000000.0))
  711.                 create_lotus_number(dbl_value[0],j1,i1,2);
  712.             }
  713.  
  714.             /* now for the dependent data values (y-values) */
  715.             /* put out the numbers, and labels if any       */
  716.             *LABELr.position = 0x27;    /* single quote ('), lj */
  717.             j1 = i + 1;
  718.             for (j = 0; j < number_of_cols; j++) {
  719.             dec_pl = y_decpl[j];
  720.             i1 = current_row + j + 1;
  721.             if (graph_data[i].y_item[j] > -2000000000.0)
  722.               create_lotus_number(graph_data[i].y_item[j],
  723.                                 j1,i1,dec_pl);
  724.             if (graph_data[i].number_of_labels >= j) {
  725.                 l1 = j1 + number_of_rows + 1;
  726.                 create_lotus_label(graph_data[i].y_label[j],l1,i1);
  727.             }
  728.             }
  729.             *LABELr.position = 0x22;    /* double quote ("), rj */
  730.         }
  731.  
  732.         current_row += number_of_cols + 2;
  733.  
  734.         number_of_cols = 0;
  735.         number_of_rows = 0;
  736.         label_ready = 0;
  737. /*        max_title = 18;  */
  738.  
  739.         break;
  740.         case '#':
  741.         break;
  742.         default:
  743.         fprintf(stderr,"Unknown record type!\n");
  744.         break;
  745.     }
  746.       }
  747.     } /* end while */
  748.  
  749. /*********************/
  750. /* end of lotus file */
  751. /*********************/
  752.  
  753.     p = (char *)(&LEOFr);
  754.     output_lotus_record(p);
  755.  
  756. }
  757.  
  758. /*****************************************/
  759. /* scan input file for number of graphs, */
  760. /* column widths, etc.                   */
  761. /*****************************************/
  762.  
  763. int
  764. get_header_info(bufp,graphs,hlines)
  765. char *bufp;
  766. short *graphs, *hlines;
  767. {
  768.     int  i, j, count = -1;
  769.     char c;
  770.  
  771.     *bufp = '\0';
  772.     *graphs = 0;
  773.     while (getline(bufp,MAXINRECLEN,infile) != EOF) {
  774.     j = trim(bufp);
  775.     if ('E' == toupper(*bufp))
  776.         ++(*graphs);
  777.       }
  778.     rewind(infile);
  779.     return(0);
  780. }
  781.  
  782.  
  783. /*****************************************/
  784. /* create and output a lotus label       */
  785. /*****************************************/
  786.  
  787. int
  788. create_lotus_label(label,lcol,lrow)
  789. char *label;
  790. short lcol;
  791. short lrow;
  792. {
  793.     int i,j;
  794.     short c1, r1;
  795.     char *p;
  796.  
  797.     p = (char *)(&LABELr);
  798.     int2s(swapb(lcol),LABELr.column);
  799.     int2s(swapb(lrow),LABELr.row);
  800.     *LABELr.string = '\0';
  801.     strcat(LABELr.string,label);
  802. /* fprintf(stderr,"x: %s\n",LABELr.string); */
  803.     int2s(swapb((unsigned short)(strlen(LABELr.string) + 7)),
  804.                     LABELr.record_length);
  805.     output_lotus_record(p);
  806.     return(0);
  807. }
  808.  
  809. /*****************************************/
  810. /* create and output a lotus number      */
  811. /*****************************************/
  812.  
  813. int
  814. create_lotus_number(number,ncol,nrow,ndp)
  815. double number;
  816. short ncol;
  817. short nrow;
  818. short ndp;
  819. {
  820.     int i,j;
  821.     short c1, r1;
  822.     char *p;
  823.  
  824.     p = (char *)(&NUMBERr);
  825.     int2s(swapb(ncol),NUMBERr.column);
  826.     int2s(swapb(nrow),NUMBERr.row);
  827.     *NUMBERr.format = (char)(0x80 + ndp);
  828.     stdbl(number,NUMBERr.value);
  829.     output_lotus_record(p);
  830.     return(0);
  831. }
  832.  
  833. /*****************************************/
  834. /* output a lotus record -- note that    */
  835. /* the length of the record is contained */
  836. /* in the record itself (bytes 2-3)      */
  837. /* minus the 4 bytes of opcode+length    */
  838. /*****************************************/
  839.  
  840. int
  841. output_lotus_record(record_pointer)
  842. char *record_pointer;
  843. {
  844.     int i, fstatus;
  845.     unsigned short total_length = 0;
  846.  
  847.     total_length = swapb((unsigned short)s2int(record_pointer + 2)) + 4;
  848.  
  849.     for (i = 0; i < total_length; i++)
  850.     fstatus = putc(*record_pointer++,outfile);
  851.  
  852.     current_offset += (long)total_length;
  853.  
  854.     return(fstatus);
  855.  
  856. }
  857.  
  858. /***********************************/
  859. /* our own getline -- like fgets,  */
  860. /* just returns null-term string   */
  861. /* instead of newline, and length  */
  862. /* instead of pointer              */
  863. /***********************************/
  864.  
  865. int
  866. getline(s,lim,stream)
  867. char s[];
  868. int lim;
  869. register FILE *stream;
  870. {
  871.     int c, i;
  872.  
  873.     i = 0;
  874.     while (--lim > 0 && (c = getc(stream)) != EOF && c != '\n')
  875.       s[i++] = c;
  876.  
  877.     if (c == EOF)
  878.     return(c);
  879.  
  880.     s[i] = '\0';
  881. /*    current_row++; */
  882.  
  883.     return(i);
  884.  
  885. }
  886.  
  887. int
  888. stdbl(value,ptr)
  889. double value;
  890. char *ptr;
  891. {
  892.     int i = 7;
  893.     char *dp;
  894.  
  895.     dp = (char *)&value;
  896.     while (i > -1)
  897.     *ptr++ = *(dp + (i--));
  898. }
  899.  
  900. /*****************************************/
  901. /* return a new string, with the first   */
  902. /* character non-whitespace.  Look out;  */
  903. /* it does clobber the passed contents,  */
  904. /* but returns the length of the result .*/
  905. /*****************************************/
  906.  
  907. int
  908. trim(p)
  909. register char *p;
  910. {
  911.     char *hp, *np;
  912.  
  913.     if (*p != ' ' && *p != '\t')
  914.     return(strlen(p));
  915.  
  916.     hp = np = p;
  917.  
  918.     while(*p && (*p == ' ' || *p == '\t'))
  919.     p++;
  920.     while (*p)
  921.     *np++ = *p++;
  922.  
  923.     *np = '\0';
  924.     return((int)(np - hp));
  925. }
  926.  
  927. /*****************************************/
  928. /* fix a string, with the double quotes  */
  929. /* removed, and to a maximum length (not */
  930. /* including eos) NOTE: this routine     */
  931. /* may alter 'instr'.                    */
  932. /*****************************************/
  933.  
  934. char *
  935. qtstr(instr,outstr,maxlen)
  936. char *instr;
  937. char *outstr;
  938. int  maxlen;
  939. {
  940.     int i, q;
  941.     char *isp, *osp;
  942.  
  943.     q = 0;
  944.     i = trim(instr); /* it may be altered right here */
  945.     isp = instr;
  946.     osp = outstr;
  947.     if (*isp == '"') {
  948.     ++isp;
  949.     q++;
  950.     }
  951.     for (i = 0; ((i < maxlen) && *isp && ((q && *isp != '"') || (!q && *isp != ' '))); i++)
  952.         *osp++ = *isp++;
  953.     *osp = '\0';
  954.  
  955.     if (i >= maxlen)
  956.     while (*isp && *isp != ' ' && *isp != '\t' && *isp != '"')
  957.         isp++;
  958.     return(*isp ? ++isp : isp);
  959. }
  960.  
  961. /**********************************************************************/
  962. /* create a lotus formula range...lotus cell addresses are of two     */
  963. /* types, absolute and relative.  Absolute address place 0,0 at the   *
  964. /* upper left corner of the spreadsheet.  Relative address are        */
  965. /* "circular" relative, and are all negative.  The current cell is    */
  966. /* address -32768 (the maximum 16-bit signed negative).  The cell     */
  967. /* position immediately "above" or "left" of the current cell is      */
  968. /* -1, decreasing as you "decrease" your position.  The cell position */
  969. /* immediately "below" or "right" of the current cell is -32767,      */
  970. /* increasing as you "increase" your position.                        */
  971. /*                                                                    */
  972. /* c_col ("current" column) and c_row ("current" row) are actually    */
  973. /* just relative starting points for the addresses that follow them.  */
  974. /* The "type" parameter is simply a flag to indicate whether the      */
  975. /* range is a true range, all four parameters (type = 1), or whether  */
  976. /* it is just a column position (type = 0).  In the latter case, only */
  977. /* the start column and start row are done.                           */
  978. /*                                                                    */
  979. /* Oh, by the way;  don't forget to byte-swap each 16-bits if your    */
  980. /* computer is a big-endian!                                          */
  981. /**********************************************************************/
  982.  
  983. int
  984. create_formula_range(range_ptr,c_col,c_row,s_col,s_row,e_col,e_row,type)
  985. char *range_ptr;
  986. short c_col, c_row, s_col, s_row, e_col, e_row;
  987. int type;
  988. {
  989.     short rel_ptr;
  990.     char *p;
  991.  
  992.     p = range_ptr;
  993.  
  994.     rel_ptr = (s_col < c_col) ? (s_col - c_col - 8192) : (s_col - c_col - 32768);
  995.     int2s(swapb((unsigned short)rel_ptr),p);
  996.     p += 2;
  997.     rel_ptr = (s_row < c_row) ? (s_row - c_row - 8192) : (s_row - c_row - 32768);
  998.     int2s(swapb((unsigned short)rel_ptr),p);
  999.     if (type) {
  1000.     p += 2;
  1001.     rel_ptr = (e_col < c_col) ? (e_col - c_col - 8192) : (e_col - c_col - 32768);
  1002.     int2s(swapb((unsigned short)rel_ptr),p);
  1003.     p += 2;
  1004.     rel_ptr = (e_row < c_row) ? (e_row - c_row - 8192) : (e_row - c_row - 32768);
  1005.     int2s(swapb((unsigned short)rel_ptr),p);
  1006.     }
  1007.  
  1008.     return(0);
  1009.  
  1010. }
  1011.  
  1012.  
  1013. /**********************************************/
  1014. /* Routine to count number of decimal places  */
  1015. /* assumes that numbuf is already "trimmed"   */
  1016. /* (i.e., no leading white space).            */
  1017. /**********************************************/
  1018.  
  1019. short
  1020. decimals(numbuf)
  1021. char    *numbuf;
  1022. {
  1023.     char *c, *p;
  1024.  
  1025.     if ((p = strchr(numbuf,'.')) == NULL)
  1026.         return((short)0);
  1027.  
  1028.     c = ++p;
  1029.     while (*c && isdigit(*c))
  1030.         c++;
  1031.  
  1032.     return((short)(c - p));
  1033. }
  1034.