home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / conv123 / part02 / conv123.c next >
Encoding:
C/C++ Source or Header  |  1993-09-05  |  32.5 KB  |  1,134 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    /* number of header lines allowed above dash line */
  11. #define MAXROWS 8192    /* max rows, dependent on 12-bit maximum value */
  12. #define MAXCOLS 124    /* maximum number of columns in the spreadsheet */
  13. #define MAXCOLWD 36    /* maximum column width */
  14. #define MAXINRECLEN (MAXCOLS * MAXCOLWD + 5 * MAXCOLS)
  15. #define COLEXTEND 1    /* makes cell this much bigger than definition */
  16.  
  17. void int2s();        /* routine to stuff int bits into char representation */
  18.  
  19. FILE *infile, *outfile;
  20.  
  21. short current_row;    /* input file record */
  22. long current_offset;    /* output file offset */
  23.  
  24. short col_width[MAXCOLS], col_pos[MAXCOLS], col_type[MAXCOLS];
  25. short formula_start_row[MAXCOLS], formula_end_row[MAXCOLS];
  26. short formula_start_col, formula_end_col;
  27. short decimals(), dec_pl, col_dec_pl[MAXCOLS], row_dec_pl;
  28.  
  29. /***********************************/
  30. /* declare lotus record structures */
  31. /***********************************/
  32.  
  33. BOF BOFr;
  34.  
  35. RANGE RANGEr;
  36. CALCCOUNT CALCCOUNTr;
  37. CALCMODE CALCMODEr;
  38. CALCORDER CALCORDERr;
  39. SPLIT SPLITr;
  40. SYNC SYNCr;
  41. WINDOW1 WINDOW1r;
  42. COLW1 COLW1r;
  43. TABLE TABLEr;
  44. QRANGE QRANGEr;
  45. PRANGE PRANGEr;
  46. LABEL LABELr;
  47. /*  INTEGER INTEGERr; */
  48. NUMBER NUMBERr;
  49. FORMULA FORMULAr;    
  50. LEOF LEOFr;
  51.  
  52.  
  53.  
  54. main(argc,argv)
  55. int argc;
  56. char *argv[];
  57. {
  58.  
  59. /**********************/
  60. /* main declarations  */
  61. /**********************/
  62.  
  63.     int fstat;
  64.     char *p, *bp, *fp, *sstat;
  65.     char headerbuf[MAXHEADLINES + 1][MAXINRECLEN + 1];
  66.     char inbuf[MAXINRECLEN + 1], util_buf[256];
  67.     char infilename[96];
  68.     char outfilename[96];
  69.     char blank_buf[80];
  70.  
  71.     int i, j, l, debug, fs, us;
  72.  
  73.     unsigned short i1, j1, l1;
  74.  
  75.     short number_of_cols, header_lines;
  76.  
  77.     double dbl_value;
  78.  
  79.     long RANGE_offset;
  80.  
  81. /**************************************/
  82. /* initialize lotus record structures */
  83. /**************************************/
  84.  
  85.     int2s(swapb(BOF_op),BOFr.opcode);
  86.     int2s(swapb(BOF_len),BOFr.record_length);
  87.     int2s(swapb((unsigned short)1030),BOFr.ff_version);
  88.  
  89.     int2s(swapb(RANGE_op),RANGEr.opcode);
  90.     int2s(swapb(RANGE_len),RANGEr.record_length);
  91.     int2s(swapb((unsigned short)0),RANGEr.start_column);
  92.     int2s(swapb((unsigned short)0),RANGEr.start_row);
  93.     int2s(swapb((unsigned short)0),RANGEr.end_column);
  94.     int2s(swapb((unsigned short)0),RANGEr.end_row);
  95.  
  96.     int2s(swapb(CALCCOUNT_op),CALCCOUNTr.opcode);
  97.     int2s(swapb(CALCCOUNT_len),CALCCOUNTr.record_length);
  98.     *CALCCOUNTr.iteration_count = 1;
  99.  
  100.     int2s(swapb(CALCMODE_op),CALCMODEr.opcode);
  101.     int2s(swapb(CALCMODE_len),CALCMODEr.record_length);
  102.     *CALCMODEr.recalculation = 0xFF;    /* automatic recalc */
  103.  
  104.     int2s(swapb(CALCORDER_op),CALCORDERr.opcode);
  105.     int2s(swapb(CALCORDER_len),CALCORDERr.record_length);
  106.     *CALCORDERr.calc_order = 0x00;    /* natural order */
  107.  
  108.     int2s(swapb(SPLIT_op),SPLITr.opcode);
  109.     int2s(swapb(SPLIT_len),SPLITr.record_length);
  110.     *SPLITr.window_split = 0x00;    /* no window split */
  111.  
  112.     int2s(swapb(SYNC_op),SYNCr.opcode);
  113.     int2s(swapb(SYNC_len),SYNCr.record_length);
  114.     *SYNCr.window_sync = 0xFF;        /* window synchronized */
  115.  
  116.     int2s(swapb(WINDOW1_op),WINDOW1r.opcode);
  117.     int2s(swapb(WINDOW1_len),WINDOW1r.record_length);
  118.     int2s(swapb((unsigned short)0),WINDOW1r.cc_column);
  119.     int2s(swapb((unsigned short)0),WINDOW1r.cc_row);
  120.     *WINDOW1r.cell_format = 2;    /* two decimal places */
  121.     *WINDOW1r.unused1 = 0;
  122.     int2s(swapb((unsigned short)9),WINDOW1r.column_width);
  123.     int2s(swapb((unsigned short)8),WINDOW1r.ncol_on_screen);
  124.     int2s(swapb((unsigned short)20),WINDOW1r.nrow_on_screen);
  125.     int2s(swapb((unsigned short)0),WINDOW1r.leftmost_column);
  126.     int2s(swapb((unsigned short)0),WINDOW1r.top_row);
  127.     int2s(swapb((unsigned short)0),WINDOW1r.ntitle_col);
  128.     int2s(swapb((unsigned short)0),WINDOW1r.ntitle_row);
  129.     int2s(swapb((unsigned short)0),WINDOW1r.ltitle_col);
  130.     int2s(swapb((unsigned short)0),WINDOW1r.ttitle_row);
  131.     int2s(swapb((unsigned short)4),WINDOW1r.borderwd_col);
  132.     int2s(swapb((unsigned short)4),WINDOW1r.borderwd_row);
  133.     int2s(swapb((unsigned short)72),WINDOW1r.window_width);
  134.     *WINDOW1r.unused2 = 0;
  135.     *WINDOW1r.unused3 = 0;
  136.  
  137.     /* there are multiple of these, so just init basic elements for now */
  138.     int2s(swapb(COLW1_op),COLW1r.opcode);
  139.     int2s(swapb(COLW1_len),COLW1r.record_length);
  140.  
  141.  
  142.     int2s(swapb(TABLE_op),TABLEr.opcode);
  143.     int2s(swapb(TABLE_len),TABLEr.record_length);
  144.     *TABLEr.table_ind = 0x00;        /* no table */
  145.     int2s(swapb((unsigned short)0xFFFF),TABLEr.table_start_column);
  146.     int2s(swapb((unsigned short)0),TABLEr.table_start_row);
  147.     int2s(swapb((unsigned short)0xFFFF),TABLEr.table_end_column);
  148.     int2s(swapb((unsigned short)0),TABLEr.table_end_row);
  149.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_start_column);
  150.     int2s(swapb((unsigned short)0),TABLEr.cell1_start_row);
  151.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_end_column);
  152.     int2s(swapb((unsigned short)0),TABLEr.cell1_end_row);
  153.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_start_column);
  154.     int2s(swapb((unsigned short)0),TABLEr.cell2_start_row);
  155.     int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_end_column);
  156.     int2s(swapb((unsigned short)0),TABLEr.cell2_end_row);
  157.  
  158.  
  159.     int2s(swapb(QRANGE_op),QRANGEr.opcode);
  160.     int2s(swapb(QRANGE_len),QRANGEr.record_length);
  161.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_start_column);
  162.     int2s(swapb((unsigned short)0),QRANGEr.input_start_row);
  163.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_end_column);
  164.     int2s(swapb((unsigned short)0),QRANGEr.input_end_row);
  165.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_start_column);
  166.     int2s(swapb((unsigned short)0),QRANGEr.output_start_row);
  167.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_end_column);
  168.     int2s(swapb((unsigned short)0),QRANGEr.output_end_row);
  169.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_start_column);
  170.     int2s(swapb((unsigned short)0),QRANGEr.criteria_start_row);
  171.     int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_end_column);
  172.     int2s(swapb((unsigned short)0),QRANGEr.criteria_end_row);
  173.     *QRANGEr.command = 0;        /* no command */
  174.  
  175.     int2s(swapb(PRANGE_op),PRANGEr.opcode);
  176.     int2s(swapb(PRANGE_len),PRANGEr.record_length);
  177.     int2s(swapb((unsigned short)0xFFFF),PRANGEr.start_column);
  178.     int2s(swapb((unsigned short)0),PRANGEr.start_row);
  179.     int2s(swapb((unsigned short)0xFFFF),PRANGEr.end_column);
  180.     int2s(swapb((unsigned short)0),PRANGEr.end_row);
  181.  
  182.     int2s(swapb(LABEL_op),LABELr.opcode);
  183.     *LABELr.format = 0xFF;    /* lotus default */
  184.     *LABELr.position = 0x27;    /* single quote ('), left justified */
  185.  
  186.  
  187.     int2s(swapb(NUMBER_op),NUMBERr.opcode);
  188.     int2s(swapb(NUMBER_len),NUMBERr.record_length);
  189.     *NUMBERr.format = 0xFF;    /* lotus default */
  190.  
  191.     int2s(swapb(FORMULA_op),FORMULAr.opcode);
  192.     *FORMULAr.format = 0xFF;    /* lotus default */
  193.     
  194.  
  195.     int2s(swapb(LEOF_op),LEOFr.opcode);
  196.     int2s(swapb(LEOF_len),LEOFr.record_length);
  197.  
  198. /************************************/
  199. /* Now some ordinary initialization */
  200. /************************************/
  201.  
  202.     current_offset = 0L;
  203.     current_row = -1;
  204.  
  205. /*******************************/
  206. /* assign files                */
  207. /*******************************/
  208.  
  209.     infile = stdin;        /* typical input is stdin */
  210.     outfile = stdout;        /* typical output is stdout */
  211.  
  212.     debug = 0;            /* don't do it */
  213.  
  214. /* Make sure blank_buf is initialized */
  215.  
  216.     for (i = 0; i < 80; i++)
  217.     blank_buf[i] = ' ';
  218.  
  219. /************************************/
  220. /* if there are input parameters,   */
  221. /* deal with them.                  */
  222. /************************************/
  223.  
  224.     if (argc > 3) {
  225.      fprintf(stderr,"Allowed parameters are input and output filenames.\n");
  226.     return(1);
  227.     }
  228.  
  229. /* open main data input file as a stream (maybe) */
  230.     if (argc > 1) {
  231.         fclose(infile);
  232.     strcpy(infilename,argv[1]);
  233.     if ((infile = fopen(infilename,"r")) == NULL) {
  234.         fprintf(stderr,"Open of input data file %s failed.\n",infilename);
  235.         return(1);
  236.     }
  237.     }
  238.  
  239. /* create and open output file directly (maybe) */
  240.     if (argc > 2) {
  241.         fclose(outfile);
  242.     strcpy(outfilename,argv[2]);
  243.     if ((outfile = fopen(outfilename,"w+")) == NULL) {
  244.         fprintf(stderr,"open of output data file %s failed.\n",outfilename);
  245.         fclose(infile);
  246.         return;
  247.     }
  248.     }
  249.  
  250. /************************************/
  251. /* now get to work translating it   */
  252. /************************************/
  253.  
  254.     if (get_header_info(headerbuf,&number_of_cols,&header_lines))
  255.     return(1);
  256.  
  257. #ifdef DEBUG
  258.     for (i = 0; i < number_of_cols; i++)
  259.     fprintf(stderr,"%d %d %d %d\n",i,col_width[i],col_type[i],col_pos[i]);
  260.     fprintf(stderr,"total columns: %d header lines: %d\n",number_of_cols,header_lines);
  261. #endif
  262.  
  263. /************************************/
  264. /* we've got SOMETHING, so go ahead */
  265. /* and start the 123 output!        */
  266. /************************************/
  267.  
  268.     p = (char *)(&BOFr);
  269.     fs = output_lotus_record(p);
  270.  
  271. #ifdef DEBUG
  272.     fprintf(stderr,"Offset after BOF: %d\n",current_offset);
  273. #endif
  274.  
  275. /** might as well set the number of columns now, since we know it **/
  276.     RANGE_offset = current_offset;
  277.     int2s(swapb((unsigned short)(number_of_cols - 1)),RANGEr.end_column);
  278.     p = (char *)(&RANGEr);
  279.     output_lotus_record(p);
  280.  
  281. #ifdef DEBUG
  282.     fprintf(stderr,"Offset after RANGE: %d\n",current_offset);
  283. #endif
  284.  
  285. /************************************/
  286. /* and how about the column widths  */
  287. /************************************/
  288.  
  289.     p = (char *)(&COLW1r);
  290.     for (j = 0; j < number_of_cols; j++) {
  291.     int2s(swapb(j),COLW1r.column_number);
  292.     j1 = col_width[j] + COLEXTEND;
  293.     int2s(swapb(j1),COLW1r.column_width);
  294.     output_lotus_record(p);
  295.     }
  296.  
  297. #ifdef DEBUG
  298.     fprintf(stderr,"Column width records added...\n");
  299. #endif
  300.  
  301. /**********************************/
  302. /* create header labels, if there */
  303. /*  are any to create             */
  304. /**********************************/
  305.  
  306.     if (header_lines) {
  307.     p = (char *)(&LABELr);
  308.  
  309.     current_row = -1;
  310.     for (i = 0; i <= header_lines; i++) {
  311.         current_row++;
  312.         for (j = 0; j < number_of_cols; j++) {
  313.             int2s(swapb(j),LABELr.column);
  314.             int2s(swapb((unsigned short)current_row),LABELr.row);
  315.             *LABELr.string = '\0';
  316.             strncat(LABELr.string,(headerbuf[i] + col_pos[j]),col_width[j]);
  317.             int2s(swapb((unsigned short)(strlen(LABELr.string) + 7)),
  318.                 LABELr.record_length);
  319.             output_lotus_record(p);
  320.         }
  321.  
  322.     }
  323.     }
  324.  
  325. #ifdef DEBUG
  326.     fprintf(stderr,"Offset after LABELS: %d\n",current_offset);
  327. #endif
  328.  
  329. /* end of header processing */
  330.  
  331. /*******************************/
  332. /* process remaining lines     */
  333. /*******************************/
  334.  
  335.  
  336.     while ((fs = getline(inbuf,MAXINRECLEN,infile)) != EOF) {
  337.  
  338.     formula_start_col = -1;        /* start out pessimistic */
  339.     formula_end_col = -1;
  340.     row_dec_pl = 0;
  341.  
  342.     for (j = 0; j < number_of_cols; j++) {
  343.       if (col_pos[j] < fs) {    /* get paranoid about short lines */
  344.         *util_buf = '\0';
  345.         strncat(util_buf,(inbuf + col_pos[j]),col_width[j]);
  346.         us = trim(util_buf);
  347.         if (us > 0) {
  348.         if (sscanf(util_buf," %lf%n",&dbl_value,&l) && (us == l)) {
  349. #ifdef DEBUG
  350.           fprintf(stderr,"%d %d %s|\n",us,l,util_buf);
  351. #endif
  352.         /*** just a number; keep track of start/end values ***/
  353.         if (formula_start_row[j] < 0)
  354.             formula_start_row[j] = current_row;
  355.         formula_end_row[j] = current_row;
  356.         if (formula_start_col < 0)
  357.             formula_start_col = j;
  358.         formula_end_col = j;
  359.  
  360.         if ((dec_pl = decimals(util_buf)) > col_dec_pl[j])
  361.             col_dec_pl[j] = dec_pl;
  362.         if (dec_pl > row_dec_pl)
  363.             row_dec_pl = dec_pl;
  364.  
  365.         p = (char *)(&NUMBERr);
  366.  
  367.         *NUMBERr.format = (char)(0x80 + dec_pl);
  368.         int2s(swapb(j),NUMBERr.column);
  369.         int2s(swapb((unsigned short)current_row),NUMBERr.row);
  370.         stdbl(dbl_value,NUMBERr.value);
  371.         output_lotus_record(p);
  372.  
  373.         } else if (*util_buf == '@') {  /* test for formula */
  374.         if (fstat = create_formula_record(util_buf,j)) {
  375.             fprintf(stderr,"Bad formula at line %d, error %d\n",current_row,fstat);
  376.             return(1);
  377.         }
  378.         if (!strcmp(util_buf,"@NUL")) {    /* it's a placeholder */
  379.             if (formula_start_row[j] < 0)
  380.             formula_start_row[j] = current_row;
  381.             formula_end_row[j] = current_row;
  382.             if (formula_start_col < 0)
  383.             formula_start_col = j;
  384.             formula_end_col = j;
  385.         }
  386.             
  387.           } else {        /* OK, so it's just a plain-old string  */
  388.                 /* check for string override characters */
  389.         if (us > 1 && (*util_buf == '\'' || *util_buf == '"')) {
  390.             *LABELr.position = *util_buf;
  391.             *util_buf = ' ';
  392.             us = trim(util_buf);
  393.         }
  394.         p = (char *)(&LABELr);
  395.         col_type[j] = 0;    /* non_numeric column */
  396.         formula_start_row[j] = formula_end_row[j] = -1;
  397.         formula_start_col = formula_end_col = -1;
  398.         col_dec_pl[j] = row_dec_pl = 0;
  399.         int2s(swapb(j),LABELr.column);
  400.         int2s(swapb((unsigned short)current_row),LABELr.row);
  401.         strcpy(LABELr.string,util_buf);
  402.         int2s(swapb((unsigned short)(strlen(LABELr.string) + 7)),
  403.                 LABELr.record_length);
  404.         output_lotus_record(p);
  405.         *LABELr.position = 0x27; /* single quote, left-justified */
  406.         }
  407.       }
  408.      }
  409.     }
  410.     }
  411.  
  412.  
  413. /*********************/
  414. /* end of lotus file */
  415. /*********************/
  416.  
  417.     p = (char *)(&LEOFr);
  418.     output_lotus_record(p);
  419.  
  420. }
  421.  
  422. /*****************************************/
  423. /* scan input record for column widths   */
  424. /* and return values                     */
  425. /*****************************************/
  426.  
  427. int
  428. get_header_info(bufp,cols,hlines)
  429. char bufp[][MAXINRECLEN + 1];
  430. short *cols, *hlines;
  431. {
  432.     int  i, j, count = -1;
  433.     char c;
  434.  
  435.     for (i = 0; i < MAXHEADLINES; i++)
  436.     bufp[i][0] = '\0';
  437.     *hlines = -1;
  438.  
  439.     do {
  440.     if (++(*hlines) > MAXHEADLINES || !getline(bufp[*hlines],MAXINRECLEN,infile)) {
  441.         fprintf(stderr,"Could not locate column definition within %d lines in input file.\n",MAXHEADLINES);
  442.         return(1);
  443.     }
  444.     } while (bufp[*hlines][0] != '-');
  445.  
  446. /*** now find out the number of columns and their widths ***/
  447.  
  448.     count = j = 0;
  449.     while (bufp[*hlines][j]) {
  450.     i = 0;
  451.     while (bufp[*hlines][j + i] == '-') {
  452.         i++;
  453.     }
  454.     col_width[count] = i;
  455.     col_pos[count] = j;
  456.     col_type[count] = 1;        /* just initialization */
  457.     formula_start_row[count] = -1;    /* just initialization */
  458.     formula_end_row[count] = -1;    /* just initialization */
  459.     col_dec_pl[count] = 0;        /* just initialization */
  460.     count++;
  461.     j += i;
  462.     while (bufp[*hlines][j] && (bufp[*hlines][j] != '-')) {
  463.         j++;
  464.     }
  465.     }
  466.     *cols = count;
  467.  
  468.     return(0);
  469. }
  470.  
  471. /*************************************************/
  472. /* create a lotus formula - uses a couple of     */
  473. /* other routines, returns zero if successful    */
  474. /*************************************************/
  475.  
  476. int
  477. create_formula_record(formbuf,c_col)
  478. char *formbuf;
  479. short c_col;    /* current column; current row is global (Emerson) */
  480. {
  481.     short dec_pl, s_col, s_row, e_col, e_row;
  482.     short s2_col, s2_row, e2_col, e2_row;
  483.     short rvalue, bfunction = 0;
  484.     char *bp, util_buf[256];
  485.     char *bnamebuf = "+-*/%";
  486.     int ichar;
  487.  
  488. /****************************************************/
  489. /* If formbuf is a binary function, normalize the   */
  490. /* formula buffer -- ranges are already normalized, */
  491. /* so just copy                                     */
  492. /****************************************************/
  493.  
  494.     bp = util_buf;
  495.     *bp = '\0';
  496.     if (strchr(bnamebuf,*(formbuf + 2)) != NULL) { /* binary function */
  497.     bfunction++;
  498.     strncat(bp,formbuf,3);
  499.     strcat(bp,"  ");
  500.     strcat(bp,(formbuf + 3));
  501.     } else
  502.     strcat(bp,formbuf);
  503.  
  504. /* now for any trailing number */
  505.  
  506.     rvalue = atoi(bp + 5) - 1;
  507. #ifdef DEBUG
  508.   fprintf(stderr,"range override value: %d\n",rvalue);
  509. #endif
  510.  
  511. /****************************************/
  512. /* Figure out if all the ranges are     */
  513. /* valid in their context, i.e.,        */
  514. /* column-wise or row-wise; then do it, */
  515. /* then reset.                          */
  516. /****************************************/
  517.  
  518.     ichar = *(++bp);
  519.     switch (ichar) {
  520.  
  521.     case 'B':        /* column-wise + one row value formula; uses   */
  522.             /* default ranges for column, override for row */
  523.  
  524. /***********/
  525. /* R stuff -- determine start and end columns; row is known */
  526. /***********/
  527.  
  528.     s2_row = current_row;
  529.     e2_row = current_row;
  530.  
  531. /*************************************************/
  532. /* decide whether to override the default start  */
  533. /* column; note: decimal places are not affected */
  534. /*************************************************/
  535.  
  536.     s2_col = formula_start_col;    /* start out optimistic */
  537.  
  538. /* if it's a binary function, back up one step for start */
  539.  
  540.     if (bfunction)
  541.         s2_col = formula_end_col - 1;
  542.  
  543. /* if there's an override, try to use it */
  544.  
  545.     if ((rvalue > -1) && (rvalue <= formula_end_col))
  546.         s2_col = rvalue;
  547.     else
  548.         rvalue = -1;
  549.  
  550. /* if all has failed, just use current location for start AND end */
  551.  
  552.     if (s2_col < 0) {
  553.         s2_col = c_col;
  554.         e2_col = c_col;
  555.     } else
  556.     e2_col = formula_end_col;
  557.  
  558. /***********/
  559. /* C stuff -- determine start and end rows; column is known */
  560. /***********/
  561.  
  562.     if ((s_row = formula_start_row[c_col]) < 0) {
  563.         s_row = current_row;
  564.         e_row = current_row;
  565.     } else
  566.         e_row = formula_end_row[c_col];
  567.  
  568. /* B stuff -- number of decimal places */
  569.  
  570.     dec_pl = (row_dec_pl > col_dec_pl[c_col]) ? row_dec_pl : col_dec_pl[c_col];
  571.  
  572.     if (create_lotus_multiple(bp,dec_pl,c_col,c_col,s_row,c_col,e_row,s2_col,s2_row,e2_col,e2_row,rvalue))
  573.         return(3);
  574.  
  575.     /* reset default row range and dec, set default column range, end */
  576.     formula_start_col = -1;
  577.     formula_end_col = -1;
  578.     row_dec_pl = 0;
  579.  
  580.     if (formula_start_row[c_col] < 0)
  581.         formula_start_row[c_col] = current_row;
  582.     formula_end_row[c_col] = current_row;
  583.     if (dec_pl > col_dec_pl[c_col])
  584.         col_dec_pl[c_col] = dec_pl;
  585.  
  586.     /* reset default column range and dec, set row default range, end */
  587.     formula_start_row[c_col] = -1;
  588.     formula_end_row[c_col] = -1;
  589.     col_dec_pl[c_col] = 0;
  590.  
  591.     if (formula_start_col < 0)
  592.         formula_start_col = c_col;
  593.     formula_end_col = c_col;
  594.     if (dec_pl > row_dec_pl)
  595.         row_dec_pl = dec_pl;
  596.  
  597.     break;
  598.  
  599.     case 'C':        /* column-wise formulae; just uses default ranges */
  600.  
  601.     dec_pl = col_dec_pl[c_col];
  602.  
  603.     if ((s_row = formula_start_row[c_col]) < 0) {
  604.         s_row = current_row;
  605.         e_row = current_row;
  606.     } else
  607.         e_row = formula_end_row[c_col];
  608.  
  609.     /* if it's a binary function, force the back up one step */
  610.     if (bfunction && (current_row > 2)) {
  611.       s_row = current_row - 2;
  612.       e_row = current_row - 1;
  613.     }
  614.  
  615.     if (create_lotus_formula(bp,dec_pl,c_col,c_col,s_row,c_col,e_row,rvalue))
  616.         return(3);
  617.  
  618.     /* reset default column range and dec, set row default range, end */
  619.     formula_start_row[c_col] = -1;
  620.     formula_end_row[c_col] = -1;
  621.     col_dec_pl[c_col] = 0;
  622.  
  623.     if (formula_start_col < 0)
  624.         formula_start_col = c_col;
  625.     formula_end_col = c_col;
  626.     if (dec_pl > row_dec_pl)
  627.         row_dec_pl = dec_pl;
  628.  
  629.     break;
  630.  
  631.     case 'R':        /* row-wise formula - check also for specified range */
  632.  
  633.     s_row = current_row;
  634.     e_row = current_row;
  635.     dec_pl = row_dec_pl;
  636.  
  637. /*************************************************/
  638. /* decide whether to override the default start  */
  639. /* column; note: decimal places are not affected */
  640. /*************************************************/
  641.  
  642.     s_col = formula_start_col;    /* start out optimistic */
  643.  
  644. /* if it's a binary function, back up one step for start */
  645.  
  646.     if (bfunction)
  647.         s_col = formula_end_col - 1;
  648.  
  649. /* if there's an override, try to use it */
  650.  
  651.     if ((rvalue > -1) && (rvalue <= formula_end_col))
  652.         s_col = rvalue;
  653.     else
  654.         rvalue = -1;
  655.  
  656. /* if all has failed, just use current location for start AND end */
  657.  
  658.     if (s_col < 0) {
  659.         s_col = c_col;
  660.         e_col = c_col;
  661.     } else
  662.     e_col = formula_end_col;
  663.  
  664.     if (create_lotus_formula(bp,dec_pl,c_col,s_col,s_row,e_col,e_row,rvalue))
  665.         return(3);
  666.  
  667.     /* reset default row range and dec, set default column range, end */
  668.     formula_start_col = -1;
  669.     formula_end_col = -1;
  670.     row_dec_pl = 0;
  671.  
  672.     if (formula_start_row[c_col] < 0)
  673.         formula_start_row[c_col] = current_row;
  674.     formula_end_row[c_col] = current_row;
  675.     if (dec_pl > col_dec_pl[c_col])
  676.         col_dec_pl[c_col] = dec_pl;
  677.     break;
  678.  
  679.     case 'N':        /* null function; just return, increment counters */
  680.     break;
  681.  
  682.     default:
  683.     return(4);
  684.     break;
  685.     }
  686.  
  687.     return(0);
  688. }
  689.  
  690. /*****************************************************/
  691. /* The decisions made in create_formula_record       */
  692. /* are carried out here, or in create_lotus_multiple */
  693. /*****************************************************/
  694.  
  695. int
  696. create_lotus_formula(formbuf,dec_pl,c_col,s_col,s_row,e_col,e_row,rvalue)
  697. char *formbuf;
  698. short dec_pl, c_col, s_col, s_row, e_col, e_row;
  699. short rvalue;
  700. {
  701.     int i;
  702.     char *fc, *fp, *findex, *lrp, util_buf[256];
  703.     double mult = 0.0;
  704.  
  705.     char *namebuf = "~~~SUMAVGCNTMINMAXVARSTD+  -  *  /  %  NUL";
  706.     unsigned short opcodes[14];/* = { 0xFF, 0x50, 0x51, 0x52, 0x53, 0x54, 0x57,
  707.                  0x58, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0xFF }; */
  708.  
  709.     opcodes[0] = 0xFF; opcodes[1] = 0x50; opcodes[2] = 0x51; opcodes[3] = 0x52;
  710.     opcodes[4] = 0x53; opcodes[5] = 0x54; opcodes[6] = 0x57; opcodes[7] = 0x58;
  711.     opcodes[8] = 0x09; opcodes[9] = 0x0A; opcodes[10] = 0x0B;
  712.     opcodes[11] = 0x0C; opcodes[12] = 0x0C; opcodes[13] = 0xFF;
  713.  
  714.     /*** find which formula ***/
  715.     fp = ++formbuf;
  716.     *util_buf = '\0';
  717.     strncat(util_buf,fp,3);
  718. #ifdef DEBUG
  719.  
  720.     fprintf(stderr,"util_buf holds formula string |%s|\n",util_buf);
  721. #endif
  722.     if ((findex = strstr(namebuf,util_buf)) == NULL) {
  723. #ifdef DEBUG
  724.       fprintf(stderr,"findex returns null!\n");
  725. #endif
  726.     return(4);
  727.     }
  728.  
  729.     lrp = (char *)(&FORMULAr);
  730.  
  731.     *FORMULAr.format = (char)(0x80 + dec_pl);
  732.     int2s(swapb(c_col),FORMULAr.column);
  733.     int2s(swapb((unsigned short)current_row),FORMULAr.row);
  734.     fc = FORMULAr.formula_code;
  735.  
  736.     /** fill in the actual lotus formula **/
  737.  
  738.     i = findex - namebuf;
  739.     i = i / 3;
  740.  
  741.     switch (i) {
  742.  
  743.     case 1:        /* summation */
  744.     case 2:        /* average */
  745.     case 3:        /* count */
  746.     case 4:        /* minimum */
  747.     case 5:        /* maximum */
  748.     case 6:        /* variance */
  749.     case 7:        /* standard deviation */
  750.  
  751.         *(fc++) = 0x02;        /* range */
  752.         create_formula_range(fc,c_col,s_col,s_row,e_col,e_row,1);
  753.         fc += 8;
  754.         *(fc++) = opcodes[i];    /* lotus opcode */
  755.         *(fc++) = 0x01;        /* make it a variable? */
  756.         *(fc++) = 0x03;        /* end of formula - return */
  757.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  758.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  759.         output_lotus_record(lrp);
  760.         break;
  761.  
  762.     case 8:        /* addition */
  763.     case 10:        /* multiplication */
  764.  
  765.         *(fc++) = 0x01;        /* variable */
  766.         create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  767.         fc += 4;
  768.         *(fc++) = 0x01;        /* variable */
  769.         create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  770.         fc += 4;
  771.         *(fc++) = opcodes[i];    /* lotus opcode */
  772.         *(fc++) = 0x04;        /* parentheses? */
  773.         *(fc++) = 0x03;        /* end of formula - return */
  774.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  775.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  776.         output_lotus_record(lrp);
  777.         break;
  778.  
  779.     case 12:        /* percent (not a lotus function) */
  780.         mult = 100.00;
  781.         if (dec_pl < 1)
  782.         *FORMULAr.format = (char)(0x80 + 2);
  783.     case 9:        /* subtraction */
  784.     case 11:        /* division */
  785.  
  786.         *(fc++) = 0x01;        /* variable */
  787.         if (rvalue > -1)
  788.         create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  789.         else
  790.         create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  791.         fc += 4;
  792.         *(fc++) = 0x01;        /* variable */
  793.         if (rvalue > -1)
  794.         create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  795.         else
  796.         create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  797.         fc += 4;
  798.         *(fc++) = opcodes[i];    /* lotus opcode */
  799.         if (mult != 0.0) {
  800.         *(fc++) = 0x00;        /* constant */
  801.         stdbl(mult,fc);
  802.         fc += 8;
  803.         *(fc++) = 0x0B;        /* multiply */
  804.         }
  805.         *(fc++) = 0x04;        /* parentheses? */
  806.         *(fc++) = 0x03;        /* end of formula - return */
  807.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  808.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  809.         output_lotus_record(lrp);
  810.         break;
  811.     case 13:        /* null - do nothing */
  812.         ;
  813.         break;
  814.  
  815.     default:
  816.         return(1);
  817.         break;
  818.     }
  819.  
  820.     return(0);
  821. }
  822.  
  823. /*************************************************/
  824. /* create a multiple formula (addition of two    */
  825. /* formulae, row and column)                     */
  826. /*************************************************/
  827.  
  828. int
  829. create_lotus_multiple(formbuf,dec_pl,c_col,s_col,s_row,e_col,e_row,
  830.                                  s2_col,s2_row,e2_col,e2_row,rvalue)
  831. char *formbuf;
  832. short dec_pl, c_col, s_col, s_row, e_col, e_row;
  833. short s2_col, s2_row, e2_col, e2_row;
  834. short rvalue;
  835. {
  836.     int i;
  837.     char *fc, *fp, *findex, *lrp, util_buf[256];
  838.     double mult = 0.0;
  839.  
  840.     char *namebuf = "~~~SUMAVGCNTMINMAXVARSTD+  -  *  /  %  NUL";
  841.     unsigned short opcodes[14];/* = { 0xFF, 0x50, 0x51, 0x52, 0x53, 0x54, 0x57,
  842.                  0x58, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0xFF }; */
  843.  
  844.     opcodes[0] = 0xFF; opcodes[1] = 0x50; opcodes[2] = 0x51; opcodes[3] = 0x52;
  845.     opcodes[4] = 0x53; opcodes[5] = 0x54; opcodes[6] = 0x57; opcodes[7] = 0x58;
  846.     opcodes[8] = 0x09; opcodes[9] = 0x0A; opcodes[10] = 0x0B;
  847.     opcodes[11] = 0x0C; opcodes[12] = 0x0C; opcodes[13] = 0xFF;
  848.  
  849.     /*** find which formula ***/
  850.     fp = ++formbuf;
  851.     *util_buf = '\0';
  852.     strncat(util_buf,fp,3);
  853. #ifdef DEBUG
  854.     fprintf(stderr,"util_buf holds formula string |%s|\n",util_buf);
  855. #endif
  856.     if ((findex = strstr(namebuf,util_buf)) == NULL) {
  857. #ifdef DEBUG
  858.       fprintf(stderr,"findex returns null!\n");
  859. #endif
  860.     return(4);
  861.     }
  862.  
  863.     lrp = (char *)(&FORMULAr);
  864.  
  865.     *FORMULAr.format = (char)(0x80 + dec_pl);
  866.     int2s(swapb(c_col),FORMULAr.column);
  867.     int2s(swapb((unsigned short)current_row),FORMULAr.row);
  868.     fc = FORMULAr.formula_code;
  869.  
  870.     /** fill in the actual lotus formula **/
  871.  
  872.     i = findex - namebuf;
  873.     i = i / 3;
  874.  
  875.     switch (i) {
  876.  
  877.     case 1:        /* summation */
  878.     case 2:        /* average */
  879.     case 3:        /* count */
  880.     case 4:        /* minimum */
  881.     case 5:        /* maximum */
  882.     case 6:        /* variance */
  883.     case 7:        /* standard deviation */
  884.  
  885.         *(fc++) = 0x02;        /* range */
  886.         create_formula_range(fc,c_col,s_col,s_row,e_col,e_row,1);
  887.         fc += 8;
  888.         *(fc++) = opcodes[i];    /* lotus opcode */
  889.         *(fc++) = 0x01;        /* make it a variable? */
  890.         *(fc++) = 0x02;        /* range */
  891.         create_formula_range(fc,c_col,s2_col,s2_row,e2_col,e2_row,1);
  892.         fc += 8;
  893.         *(fc++) = opcodes[i];    /* lotus opcode */
  894.         *(fc++) = 0x01;        /* make it another variable? */
  895.         *(fc++) = 0x09;        /* addition of two ranges */
  896.         *(fc++) = 0x04;        /* parentheses? */
  897.         *(fc++) = 0x03;        /* end of formula - return */
  898.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  899.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  900.         output_lotus_record(lrp);
  901.         break;
  902.  
  903.     case 8:        /* addition */
  904.     case 10:        /* multiplication */
  905.  
  906.         *(fc++) = 0x01;        /* variable */
  907.         create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  908.         fc += 4;
  909.         *(fc++) = 0x01;        /* variable */
  910.         create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  911.         fc += 4;
  912.         *(fc++) = opcodes[i];    /* lotus opcode */
  913.         *(fc++) = 0x04;        /* parentheses? */
  914.         *(fc++) = 0x03;        /* end of formula - return */
  915.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  916.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  917.         output_lotus_record(lrp);
  918.         break;
  919.  
  920.     case 12:        /* percent (not a lotus function) */
  921.         mult = 100.00;
  922.         if (dec_pl < 1)
  923.         *FORMULAr.format = (char)(0x80 + 2);
  924.     case 9:        /* subtraction */
  925.     case 11:        /* division */
  926.  
  927.         *(fc++) = 0x01;        /* variable */
  928.         if (rvalue > -1)
  929.         create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  930.         else
  931.         create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  932.         fc += 4;
  933.         *(fc++) = 0x01;        /* variable */
  934.         if (rvalue > -1)
  935.         create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  936.         else
  937.         create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  938.         fc += 4;
  939.         *(fc++) = opcodes[i];    /* lotus opcode */
  940.         if (mult != 0.0) {
  941.         *(fc++) = 0x00;        /* constant */
  942.         stdbl(mult,fc);
  943.         fc += 8;
  944.         *(fc++) = 0x0B;        /* multiply */
  945.         }
  946.         *(fc++) = 0x04;        /* parentheses? */
  947.         *(fc++) = 0x03;        /* end of formula - return */
  948.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  949.         int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  950.         output_lotus_record(lrp);
  951.         break;
  952.     case 13:        /* null - do nothing */
  953.         ;
  954.         break;
  955.  
  956.     default:
  957.         return(1);
  958.         break;
  959.     }
  960.  
  961.     return(0);
  962. }
  963.  
  964. /*****************************************/
  965. /* output a lotus record -- note that    */
  966. /* the length of the record is contained */
  967. /* in the record itself (bytes 2-3)      */
  968. /* minus the 4 bytes of opcode+length    */
  969. /*****************************************/
  970.  
  971. int
  972. output_lotus_record(record_pointer)
  973. char *record_pointer;
  974. {
  975.     int i, fstatus;
  976.     unsigned short total_length = 0;
  977.  
  978.     total_length = swapb((unsigned short)s2int(record_pointer + 2)) + 4;
  979.  
  980.     for (i = 0; i < total_length; i++)
  981.     fstatus = putc(*record_pointer++,outfile);
  982.  
  983.     current_offset += (long)total_length;
  984.  
  985.     return(fstatus);
  986.  
  987. }
  988.  
  989. /***********************************/
  990. /* our own getline -- like fgets,  */
  991. /* just returns null-term string   */
  992. /* instead of newline, and length  */
  993. /* instead of pointer              */
  994. /***********************************/
  995.  
  996. int
  997. getline(s,lim,stream)
  998. char s[];
  999. int lim;
  1000. register FILE *stream;
  1001. {
  1002.     int c, i;
  1003.  
  1004.     i = 0;
  1005.     while (--lim > 0 && (c = getc(stream)) != EOF && c != '\n')
  1006.       s[i++] = c;
  1007.  
  1008.     if (c == EOF)
  1009.     return(c);
  1010.  
  1011.     s[i] = '\0';
  1012.     current_row++;
  1013.  
  1014.     return(i);
  1015.  
  1016. }
  1017.  
  1018. /******************************/
  1019. /* machine dependent routines */
  1020. /******************************/
  1021.  
  1022. int
  1023. stdbl(value,ptr)
  1024. double value;
  1025. char *ptr;
  1026. {
  1027.     int i = 7;
  1028.     char *dp;
  1029.  
  1030.     dp = (char *)&value;
  1031.     while (i > -1)
  1032.     *ptr++ = *(dp + (i--));
  1033. }
  1034.  
  1035. /*****************************************/
  1036. /* return a new string, with the first   */
  1037. /* character non-whitespace.  Look out;  */
  1038. /* it does clobber the passed contents,  */
  1039. /* but returns the length of the result .*/
  1040. /*****************************************/
  1041.  
  1042. int
  1043. trim(p)
  1044. register char *p;
  1045. {
  1046.     int i;
  1047.     char *hp, *np;
  1048.  
  1049.     hp = np = p;
  1050.  
  1051.     while(*p && (*p == ' ' || *p == '\t'))
  1052.     p++;
  1053.     while (*p)
  1054.     *np++ = *p++;
  1055.  
  1056.     *np = '\0';
  1057.     for (i = strlen(hp) - 1; (i > 0) && (*(hp+i) == ' '); i--)
  1058.     *(--np) = '\0';
  1059.  
  1060.     return((int)(np - hp));
  1061. }
  1062.  
  1063. /**********************************************************************/
  1064. /* create a lotus formula range...lotus cell addresses are of two     */
  1065. /* types, absolute and relative.  Absolute address place 0,0 at the   *
  1066. /* upper left corner of the spreadsheet.  Relative address are        */
  1067. /* "circular" relative, and are all negative.  The current cell is    */
  1068. /* address -32768 (the maximum 16-bit signed negative).  The cell     */
  1069. /* position immediately "above" or "left" of the current cell is      */
  1070. /* -1, decreasing as you "decrease" your position.  The cell position */
  1071. /* immediately "below" or "right" of the current cell is -32767,      */
  1072. /* increasing as you "increase" your position.                        */
  1073. /*                                                                    */
  1074. /* The "type" parameter is simply a flag to indicate whether the      */
  1075. /* range is a true range, all four parameters (type = 1), or whether  */
  1076. /* it is just a column position (type = 0).  In the latter case, only */
  1077. /* the start column and start row are done.                           */
  1078. /*                                                                    */
  1079. /* Oh, by the way;  don't forget to byte-swap each 16-bits if your    */
  1080. /* computer is a big-endian!                                          */
  1081. /**********************************************************************/
  1082.  
  1083. int
  1084. create_formula_range(range_ptr,c_col,s_col,s_row,e_col,e_row,type)
  1085. char *range_ptr;
  1086. short c_col, s_col, s_row, e_col, e_row;
  1087. int type;
  1088. {
  1089.     short rel_ptr;
  1090.     char *p;
  1091.  
  1092.     p = range_ptr;
  1093.  
  1094.     rel_ptr = (s_col < c_col) ? (s_col - c_col - 8192) : (s_col - c_col - 32768);
  1095.     int2s(swapb((unsigned short)rel_ptr),p);
  1096.     p += 2;
  1097.     rel_ptr = (s_row < current_row) ? (s_row - current_row - 8192) : (s_row - current_row - 32768);
  1098.     int2s(swapb((unsigned short)rel_ptr),p);
  1099.     if (type) {
  1100.     p += 2;
  1101.     rel_ptr = (e_col < c_col) ? (e_col - c_col - 8192) : (e_col - c_col - 32768);
  1102.     int2s(swapb((unsigned short)rel_ptr),p);
  1103.     p += 2;
  1104.     rel_ptr = (e_row < current_row) ? (e_row - current_row - 8192) : (e_row - current_row - 32768);
  1105.     int2s(swapb((unsigned short)rel_ptr),p);
  1106.     }
  1107.  
  1108.     return(0);
  1109.  
  1110. }
  1111.  
  1112.  
  1113. /**********************************************/
  1114. /* Routine to count number of decimal places  */
  1115. /* assumes that numbuf is already "trimmed"   */
  1116. /* (i.e., no leading white space).            */
  1117. /**********************************************/
  1118.  
  1119. short
  1120. decimals(numbuf)
  1121. char    *numbuf;
  1122. {
  1123.     char *c, *p;
  1124.  
  1125.     if ((p = strchr(numbuf,'.')) == NULL)
  1126.         return((short)0);
  1127.  
  1128.     c = ++p;
  1129.     while (*c && isdigit(*c))
  1130.         c++;
  1131.  
  1132.     return((short)(c - p));
  1133. }
  1134.