home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / oleo_src.lha / src / sylk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-14  |  15.1 KB  |  778 lines

  1. /*    Copyright (C) 1990 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "funcdef.h"
  20. #include <stdio.h>
  21. #include "sysdef.h"
  22.  
  23. #ifdef TEST
  24. extern void panic EXT1N(const char *);
  25. #endif
  26.  
  27. #include "global.h"
  28. #include "cell.h"
  29.  
  30. extern long astol EXT1(char **);
  31.  
  32. extern void set_width EXT2(CELLREF, unsigned short);
  33. extern unsigned short next_widths EXT2(CELLREF *,CELLREF *);
  34.  
  35. extern CELLREF highest_row EXT0();
  36. extern CELLREF highest_col EXT0();
  37.  
  38. extern void write_mp_usr_fmt EXT1(FILE *);
  39.  
  40. extern void read_mp_options EXT1(char *);
  41. extern void write_mp_options EXT1(FILE *);
  42.  
  43. extern void read_mp_windows EXT1(char *);
  44. extern void write_mp_windows EXT1(FILE *);
  45.  
  46. extern void clear_spreadsheet EXT0();
  47.  
  48. extern char *new_var_value EXT3(char *, int, char *);
  49.  
  50. extern char *read_new_value EXT4(CELLREF, CELLREF, char *, char *);
  51.  
  52. extern void push_cell EXT2(CELLREF, CELLREF);
  53.  
  54. extern char *flt_to_str EXT1(double);
  55.  
  56. extern char *cell_name EXT2(CELLREF, CELLREF);
  57. extern char *range_name EXT1(struct rng *);
  58.  
  59. extern char *bname[];
  60. extern default_jst;
  61. extern default_fmt;
  62. extern default_lock;
  63. extern unsigned short default_width;
  64.  
  65. extern struct rng all_rng;
  66.  
  67. static void read_mp_usr_fmt EXT1(char *);
  68.  
  69. /* These functions read and write Microsoft Multiplan SYLK style files.
  70.    They documented their file format, and I just happened to have a file or two
  71.    in that format floating around, so. . .
  72.  
  73.    Unfortunatly, it is quite slow to read/write.
  74.  */
  75. void
  76. sylk_read_file FUN2(FILE *, fp, int,ismerge)
  77. {
  78.     char *ptr;
  79.     CELLREF crow=0,ccol=0,czrow=0,czcol=0;
  80.     int lineno;
  81.     char cbuf[1024];
  82.     char expbuf[1024];
  83.     char *vname,*vval;
  84.     int vlen = 0;
  85.     int cprot;
  86.     char *cexp,*cval;
  87.     CELL *cp;
  88.     struct rng rng;
  89.     int fmt = 0;
  90.     int jst = 0;
  91.     long mx_row =MAX_ROW, mx_col = MAX_COL;
  92.  
  93.     lineno=0;
  94.     if(!ismerge)
  95.         clear_spreadsheet();
  96.     while(fgets(cbuf,sizeof(cbuf),fp)) {
  97.         lineno++;
  98.         if(lineno%50==0)
  99.             info_msg("Line %d",lineno);
  100.         if(ptr=index(cbuf,'\n'))
  101.             *ptr='\0';
  102.         ptr=cbuf;
  103.         switch(*ptr) {
  104.         case 'I':    /* ID field, ignored */
  105.             if(ptr[1]!='D' || ptr[2]!=';')
  106.                 goto bad_field;
  107.             break;
  108.         case 'F':    /* Format field */
  109.             vlen=0;
  110.             ptr++;
  111.             while(*ptr) {
  112.                 if(*ptr!=';')
  113.                     goto bad_field;
  114.                 ptr++;
  115.                 switch(*ptr++) {
  116.                     int clo,chi,cwid;
  117.                 case 'C':    /* Column from rows 1 to 255 */
  118.                     czcol=astol(&ptr);
  119.                     vlen=2;
  120.                     break;
  121.  
  122.                 case 'D':    /* Default format */
  123.                     switch(*ptr++) {
  124.                     case 'G':
  125.                         default_fmt=FMT_GEN-PRC_FLT;
  126.                         break;
  127.                     case 'E':
  128.                         default_fmt=FMT_EXP-PRC_FLT;
  129.                         break;
  130.                     case 'F':
  131.                         default_fmt=FMT_FXT-PRC_FLT;
  132.                         break;
  133.                     case '$':
  134.                         default_fmt=FMT_DOL-PRC_FLT;
  135.                         break;
  136.                     case '*':    /* * format implemented as +- format */
  137.                         default_fmt=FMT_GPH;
  138.                         break;
  139.                     case ',':    /* JF */
  140.                         default_fmt=FMT_CMA-PRC_FLT;
  141.                         break;
  142.                     case 'U':
  143.                         default_fmt=FMT_USR-PRC_FLT;
  144.                         break;
  145.                     case '%':
  146.                         default_fmt=FMT_PCT-PRC_FLT;
  147.                         break;
  148.                     case 'H':
  149.                         default_fmt=FMT_HID;
  150.                         break;
  151.                         /* End of JF */
  152.                     case 'C':    /* Continuous not supported */
  153.                     default:
  154.                         error_msg("Line %d: format %c not supported",lineno,ptr[-1]);
  155.                         break;
  156.                     }
  157.                     if(*ptr=='F') {
  158.                         default_fmt+=PRC_FLT;
  159.                         ptr++;
  160.                     } else
  161.                         default_fmt+=astol(&ptr);
  162.                     switch(*ptr++) {
  163.                     case 'C':
  164.                         default_jst=JST_CNT;
  165.                         break;
  166.                     case 'L':
  167.                         default_jst=JST_LFT;
  168.                         break;
  169.                     case 'R':
  170.                         default_jst=JST_RGT;
  171.                         break;
  172.                     case 'G':    /* General format not supported */
  173.                     default:
  174.                         error_msg("Line %d: Alignment %c not supported",lineno,ptr[-1]);
  175.                         break;
  176.                     }
  177.                     default_width=astol(&ptr);
  178.                     break;
  179.  
  180.                 case 'F':
  181.                     switch(*ptr++) {
  182.                     case 'D':
  183.                         fmt=FMT_DEF;
  184.                         break;
  185.                     case 'G':
  186.                         fmt=FMT_GEN-PRC_FLT;
  187.                         break;
  188.                     case 'E':
  189.                         fmt=FMT_EXP-PRC_FLT;
  190.                         break;
  191.                     case 'F':
  192.                         fmt=FMT_FXT-PRC_FLT;
  193.                         break;
  194.                     case '$':
  195.                         fmt=FMT_DOL-PRC_FLT;
  196.                         break;
  197.                     case '*':    /* JF implemented as +- format */
  198.                         fmt=FMT_GPH;
  199.                         break;
  200.                     case ',':    /* JF */
  201.                         fmt=FMT_CMA-PRC_FLT;
  202.                         break;
  203.                     case 'U':
  204.                         fmt=FMT_USR-PRC_FLT;
  205.                         break;
  206.                     case '%':
  207.                         fmt=FMT_PCT-PRC_FLT;
  208.                         break;
  209.                     case 'H':
  210.                         fmt=FMT_HID;
  211.                         break;    /* END of JF */
  212.                     case 'C':
  213.                     default:
  214.                         error_msg("Line %d: format %c not supported",lineno,ptr[-1]);
  215.                         fmt=FMT_DEF;
  216.                         break;
  217.                     }
  218.                     if(*ptr=='F') {
  219.                         fmt+=PRC_FLT;
  220.                         ptr++;
  221.                     } else
  222.                         fmt+=astol(&ptr);
  223.                     switch(*ptr++) {
  224.                     case 'C':
  225.                         jst=JST_CNT;
  226.                         break;
  227.                     case 'L':
  228.                         jst=JST_LFT;
  229.                         break;
  230.                     case 'R':
  231.                         jst=JST_RGT;
  232.                         break;
  233.                     case 'D':
  234.                         jst=JST_DEF;
  235.                         break;
  236.                     default:
  237.                         error_msg("Line %d: Alignment %c not supported",lineno,ptr[-1]);
  238.                         jst=JST_DEF;
  239.                         break;
  240.                     }
  241.                     vlen=1;
  242.                     break;
  243.                 case 'R':    /* Row from cols 1 to 63 */
  244.                     czrow=astol(&ptr);
  245.                     vlen=4;
  246.                     break;
  247.  
  248.                 case 'W':    /* Width of clo to chi is cwid */
  249.                     clo=astol(&ptr);
  250.                     chi=astol(&ptr);
  251.                     cwid=astol(&ptr)+1;
  252.                     for(;clo<=chi;clo++)
  253.                         set_width(clo,cwid);
  254.                     break;
  255.                 case 'X':
  256.                     ccol=astol(&ptr);
  257.                     break;
  258.                 case 'Y':
  259.                     crow=astol(&ptr);
  260.                     break;
  261.  
  262.                 default:
  263.                     goto bad_field;
  264.                 }
  265.             }
  266.             switch(vlen) {
  267.             case 1:
  268.                 cp=find_or_make_cell(crow,ccol);
  269.                 SET_FMT(cp,fmt);
  270.                 SET_JST(cp,jst);
  271.                 break;
  272.             case 2:
  273.                 rng.lr=MIN_ROW;
  274.                 rng.lc=czcol;
  275.                 rng.hr=mx_row;
  276.                 rng.hc=czcol;
  277.                 make_cells_in_range(&rng);
  278.                 while(cp=next_cell_in_range()) {
  279.                     SET_FMT(cp,fmt);
  280.                     SET_JST(cp,jst);
  281.                 }
  282.                 break;
  283.             case 4:
  284.                 rng.lr=czrow;
  285.                 rng.lc=MIN_COL;
  286.                 rng.hr=czrow;
  287.                 rng.hc=mx_col;
  288.                 make_cells_in_range(&rng);
  289.                 while(cp=next_cell_in_range()) {
  290.                     SET_FMT(cp,fmt);
  291.                     SET_JST(cp,jst);
  292.                 }
  293.                 break;
  294.             default:
  295.                 break;
  296.             }
  297.             break;
  298.  
  299.         case 'B':    /* Boundry field, ignored */
  300.             ptr++;
  301.             while(*ptr) {
  302.                 if(*ptr!=';')
  303. /*                if(*ptr+=';')  -- used to be this pass travis*/
  304.                     goto bad_field;
  305.                 ptr++;
  306.                 switch(*ptr++) {
  307.                 case 'X':
  308.                     mx_col=astol(&ptr);
  309.                     if(mx_col>MAX_COL) {
  310.                         error_msg("Boundry column %lu too large!",mx_col);
  311.                         mx_col=MAX_COL;
  312.                     }
  313.                     break;
  314.                 case 'Y':
  315.                     mx_row=astol(&ptr);
  316.                     if(mx_row>MAX_ROW) {
  317.                         error_msg("Boundry row %lu too large!",mx_row);
  318.                         mx_row=MAX_ROW;
  319.                     }
  320.                     break;
  321.                 default:
  322.                     goto bad_field;
  323.                 }
  324.             }
  325.             break;
  326.  
  327.         case 'N':    /* A Name field */
  328.             if(ptr[1]!='N')
  329.                 goto bad_field;
  330.             ptr+=2;
  331.             vname=0;
  332.             vval=0;
  333.             while(*ptr) {
  334.                 if(*ptr!=';')
  335.                     goto bad_field;
  336.                 *ptr++='\0';
  337.                 switch(*ptr++) {
  338.                 case 'N': /* Name is */
  339.                     vname=ptr;
  340.                     while(*ptr && *ptr!=';')
  341.                         ptr++;
  342.                     vlen=ptr-vname;
  343.                     break;
  344.                 case 'E': /* Expression is */
  345.                     vval=ptr;
  346.                     while(*ptr && *ptr!=';')
  347.                         ptr++;
  348.                     break;
  349.                 default:
  350.                     --ptr;
  351.                     goto bad_field;
  352.                 }
  353.             }
  354.             if(!vname || !vval)
  355.                 goto bad_field;
  356.             *ptr='\0';
  357.             ptr=new_var_value(vname,vlen,vval);
  358.             if(ptr)
  359.                 error_msg("Line %d: Couldn't set %.*s to %s: %s",lineno,vlen,vname,vval,ptr);
  360.             break;
  361.  
  362.         case 'C':    /* A Cell entry */
  363.             cprot=0;
  364.             cval=0;
  365.             cexp=0;
  366.             cval=0;
  367.             ptr++;
  368.             while(*ptr) {
  369.                 int quotes;
  370.  
  371.                 if(*ptr!=';')
  372.                     goto bad_field;
  373.                 *ptr++='\0';
  374.                 switch(*ptr++) {
  375.                 case 'X':
  376.                     ccol=astol(&ptr);
  377.                     break;
  378.                 case 'Y':
  379.                     crow=astol(&ptr);
  380.                     break;
  381.                 case 'R':
  382.                     czrow=astol(&ptr);
  383.                     break;
  384.                 case 'C':
  385.                     czcol=astol(&ptr);
  386.                     break;
  387.                 case 'P':    /* This cell is Protected */
  388.                     cprot++;
  389.                     break;
  390.                 case 'K':    /* This cell's Konstant value */
  391.                     cval=ptr;
  392.                     quotes=0;
  393.                     while(*ptr && (*ptr!=';' || quotes>0))
  394.                         if(*ptr++=='"')
  395.                             quotes= !quotes;
  396.                     break;
  397.                 case 'E':    /* This cell's Expression */
  398.                     cexp=ptr;
  399.                     quotes=0;
  400.                     while(*ptr && (*ptr!=';' || quotes>0))
  401.                         if(*ptr++=='"')
  402.                             quotes= !quotes;
  403.  
  404.                     break;
  405.                 case 'G':
  406.                     strcpy(expbuf,cval);
  407.                     break;
  408.                 case 'D':
  409.                     strcpy(expbuf,cexp);
  410.                     break;
  411.                 case 'S':
  412.                     cexp=expbuf;
  413.                     break;
  414.                 default:
  415.                     --ptr;
  416.                     goto bad_field;
  417.                 }
  418.             }
  419.             *ptr='\0';
  420.             if(cexp && cval && strcmp(cexp,cval)) {
  421.                 ptr=read_new_value(crow,ccol,cexp,cval);
  422.                 if(ptr) {
  423.                     error_msg("Line %d: %d,%d: Read '%s' %s",lineno,crow,ccol,cexp,ptr);
  424.                     break;
  425.                 }
  426.             } else if(cval) {
  427.                 ptr=read_new_value(crow,ccol,0,cval);
  428.                 if(ptr) {
  429.                     error_msg("Line %d: %d,%d: Val '%s' %s",lineno,crow,ccol,cexp,ptr);
  430.                     break;
  431.                 }
  432.             } else if(cexp) {
  433.                 ptr=read_new_value(crow,ccol,cexp,0);
  434.                 if(ptr) {
  435.                     error_msg("Line %d: %d,%d: Exp '%s' %s",lineno,crow,ccol,cexp,ptr);
  436.                     break;
  437.                 }
  438.             }
  439.             if(ismerge)
  440.                 push_cell(crow,ccol);
  441.             /* ... */
  442.             break;
  443.         case 'E':
  444.             break;
  445.         case 'W':
  446.             read_mp_windows(ptr+2);
  447.             break;
  448.         case 'U':
  449.             /* JF extension:  read user-defined formats */
  450.             read_mp_usr_fmt(ptr+1);
  451.             break;
  452.             /* JF extension: read uset-settable options */
  453.         case 'O':
  454.             read_mp_options(ptr+2);
  455.             break;
  456.         default:
  457.  bad_field:
  458.             error_msg("Line %d: Unknown SYLK line \"%s\"",lineno,cbuf);
  459.             break;
  460.         }
  461.     }
  462.     recenter_all_win();
  463. }
  464.  
  465.  
  466. static void
  467. read_mp_usr_fmt FUN1(char *,ptr)
  468. {
  469.     int usr_n = -1;
  470.     int n_chrs = 0;
  471.     char *p;
  472.     char *buf[9];
  473.     int i;
  474.  
  475.     for(i=0;i<9;i++)
  476.         buf[i]="";
  477.     p=ptr;
  478.     while(*p==';') {
  479.         *p++='\0';
  480.         switch(*p++) {
  481.         case 'N':
  482.             usr_n=astol(&p)-1;
  483.             break;
  484.         case 'H':
  485.             switch(*p++) {
  486.             case 'P':  i=0; break;
  487.             case 'N':  i=1;  break;
  488.             default:  goto badline;
  489.             }
  490.             goto count_chars;
  491.         case 'T':
  492.             switch(*p++) {
  493.             case 'P':  i=2;  break;
  494.             case 'N':  i=3;  break;
  495.             default: goto badline;
  496.             }
  497.             goto count_chars;
  498.  
  499.         case 'Z':
  500.             i=4;
  501.             goto count_chars;
  502.  
  503.         case 'C':
  504.             i=5;
  505.             goto count_chars;
  506.  
  507.         case 'D':
  508.             i=6;
  509.             goto count_chars;
  510.  
  511.         case 'P':
  512.             i=7;
  513.             goto count_chars;
  514.  
  515.         case 'S':
  516.             i=8;
  517.             goto count_chars;
  518.  
  519.         count_chars:
  520.             buf[i]=p;
  521.             n_chrs++;
  522.             while(*p && *p!=';') {
  523.                 p++;
  524.                 n_chrs++;
  525.             }
  526.             break;
  527.  
  528.         default:
  529.         badline:
  530.             error_msg("Unknown SYLK line %s",ptr);
  531.             return;
  532.         }
  533.     }
  534.     if(*p || usr_n<0 || usr_n>15)
  535.         goto badline;
  536.  
  537.     set_usr_stats(usr_n,buf);
  538. }
  539.  
  540. static char *
  541. fmt_to_str FUN1(int, f1)
  542. {
  543.     static char p_buf[40];
  544.     int p1;
  545.  
  546.     p_buf[1]='\0';
  547.     switch(f1) {
  548.     case FMT_DEF:
  549.         p_buf[0]='D';
  550.         break;
  551.     case FMT_HID:
  552.         p_buf[0]='H';
  553.         break;
  554.     case FMT_GPH:
  555.         p_buf[0]='*';
  556.         break;
  557.     default:
  558.         p1=GET_PRC(f1);
  559.         if(p1==PRC_FLT) {
  560.             p_buf[1]='F';
  561.             p_buf[2]='\0';
  562.         } else
  563.             sprintf(&p_buf[1],"%d",p1);
  564.         switch(f1|PRC_FLT) {
  565.         case FMT_USR:    p_buf[0]='U';    break;
  566.         case FMT_GEN:    p_buf[0]='G';    break;
  567.         case FMT_DOL:    p_buf[0]='$';    break;
  568.         case FMT_PCT:    p_buf[0]='%';    break;
  569.         case FMT_FXT:    p_buf[0]='F';    break;
  570.         case FMT_CMA:    p_buf[0]=',';    break;
  571.         case FMT_EXP:    p_buf[0]='E';    break;
  572.         default:    p_buf[0]='?';    break;
  573.         }
  574.         break;
  575.     }
  576.     return p_buf;
  577. }
  578.  
  579. static char
  580. jst_to_chr FUN1(int,just)
  581. {
  582.     switch(just) {
  583.     case JST_DEF:    return 'D';
  584.     case JST_LFT:    return 'L';
  585.     case JST_RGT:    return 'R';
  586.     case JST_CNT:    return 'C';
  587.     default:    return '?';
  588.     }
  589. }
  590.  
  591. static FILE *sylk_fp;
  592. static struct rng *sylk_rng;
  593.  
  594. static void
  595. sylk_write_var FUN2(char *,name, struct var *,var)
  596. {
  597.     if(var->var_flags==VAR_UNDEF && (!var->var_ref_fm || var->var_ref_fm->refs_used==0))
  598.         return;
  599.     switch(var->var_flags) {
  600.     case VAR_UNDEF:
  601.         break;
  602.     case VAR_CELL:
  603.         if(var->v_rng.lr>=sylk_rng->lr && var->v_rng.lr<=sylk_rng->hr && var->v_rng.lc>=sylk_rng->lc && var->v_rng.lc<=sylk_rng->hc)
  604.             (void)fprintf(sylk_fp,"NN;N%s;E%s\n",var->var_name,cell_name(var->v_rng.lr,var->v_rng.lc));
  605.         break;
  606.     case VAR_RANGE:
  607.         if(var->v_rng.lr<sylk_rng->lr || var->v_rng.hr>sylk_rng->hr || var->v_rng.lc<sylk_rng->lc || var->v_rng.hc>sylk_rng->hc)
  608.             break;
  609.  
  610.         (void)fprintf(sylk_fp,"NN;N%s;E%s\n",var->var_name,range_name(&(var->v_rng)));
  611.         break;
  612. #ifdef TEST
  613.     default:
  614.         panic("Unknown var type %d",var->var_flags);
  615. #endif
  616.     }
  617. }
  618.  
  619. void
  620. sylk_write_file FUN2(FILE *,fp, struct rng *,rng)
  621. {
  622.     CELLREF r,c;
  623.     CELL *cp;
  624.     CELLREF crow=0,ccol=0;
  625.     unsigned short w;
  626.     extern void for_all_vars();
  627.     /* struct var *var; */
  628.  
  629.     (void)fprintf(fp,"ID;POLEO\n");
  630.  
  631.         /* If no range given, write the entire file */
  632.     if(!rng) {
  633.         int n;
  634.         int fmts;
  635.         char *data[9];
  636.  
  637.         rng= &all_rng;
  638.  
  639.         (void)fprintf(fp,"F;D%s%c%u\n",fmt_to_str(default_fmt),jst_to_chr(default_jst),default_width);
  640.  
  641.         fmts=usr_set_fmts();
  642.         for(n=0;n<16;n++) {
  643.             if(fmts&(1<<n)) {
  644.                 get_usr_stats(n,data);
  645.                 fprintf(fp,"U;N%u;P%s;S%s",n+1,data[7],data[8]);
  646.                 if(data[0][0])
  647.                     fprintf(fp,";HP%s",data[0]);
  648.                 if(data[1][0])
  649.                     fprintf(fp,";HN%s",data[1]);
  650.                 if(data[2][0])
  651.                     fprintf(fp,";TP%s",data[2]);
  652.                 if(data[3][0])
  653.                     fprintf(fp,";TN%s",data[3]);
  654.                 if(data[4][0])
  655.                     fprintf(fp,";Z%s",data[4]);
  656.                 if(data[5][0])
  657.                     fprintf(fp,";C%s",data[5]);
  658.                 if(data[6])
  659.                     fprintf(fp,";D%s",data[6]);
  660.                 putc('\n',fp);
  661.             }
  662.         }
  663.         write_mp_options(fp);
  664.  
  665.         (void)fprintf(fp,"B;Y%u;X%u\n",highest_row(),highest_col());
  666.  
  667.     }
  668.  
  669.     (void)next_widths((CELLREF *)0,(CELLREF *)0);
  670.     while(w=next_widths(&r,&c)) {
  671.         if(r>rng->hc || c<rng->lc)
  672.             continue;
  673.         if(r<rng->lc)
  674.             r=rng->lc;
  675.         if(c>rng->hc)
  676.             c=rng->hc;
  677.         (void)fprintf(fp,"F;W%u %u %u\n",r,c,w-1);
  678.     }
  679.  
  680.     sylk_fp=fp;
  681.     sylk_rng=rng;
  682.     for_all_vars(sylk_write_var);
  683.     find_cells_in_range(rng);
  684.     while(cp=next_row_col_in_range(&r,&c)) {
  685.         char *ptr;
  686.         int f1,j1;
  687.         char p_buf[40];
  688.  
  689.         f1=GET_FMT(cp);
  690.         j1=GET_JST(cp);
  691.         if(f1!=FMT_DEF || j1!=JST_DEF) {
  692.             (void)fprintf(fp,"F;");
  693.             if(c!=ccol) {
  694.                 (void)fprintf(fp,"X%u;",c);
  695.                 ccol=c;
  696.             }
  697.             if(r!=crow) {
  698.                 (void)fprintf(fp,"Y%u;",r);
  699.                 crow=r;
  700.             }
  701.             (void)fprintf(fp,"F%s%c\n",fmt_to_str(f1),jst_to_chr(j1));
  702.         }
  703.     
  704.         if(!GET_TYP(cp) && !cp->cell_formula)
  705.             continue;
  706.  
  707.         (void)fprintf(fp,"C;");
  708.         if(c!=ccol) {
  709.             (void)fprintf(fp,"X%u;",c);
  710.             ccol=c;
  711.         }
  712.         if(r!=crow) {
  713.             (void)fprintf(fp,"Y%u;",r);
  714.             crow=r;
  715.         }
  716.  
  717.         if(cp->cell_formula) {
  718.             (void)fprintf(fp,"E%s",decomp(r,c,cp));
  719.             decomp_free();
  720.         }
  721.  
  722.         switch(GET_TYP(cp)) {
  723.         case 0:
  724.             ptr=0;
  725.             break;
  726.         case TYP_STR:
  727.             ptr=0;
  728.             if(cp->cell_formula)
  729.                 putc(';',fp);
  730.             (void)fprintf(fp,"K\"%s\"",cp->cell_str);
  731.             break;
  732.         case TYP_FLT:
  733.             ptr=flt_to_str(cp->cell_flt);
  734.             break;
  735.         case TYP_INT:
  736.             sprintf(p_buf,"%ld",cp->cell_int);
  737.             ptr=p_buf;
  738.             break;
  739.         case TYP_BOL:
  740.             ptr=bname[cp->cell_bol];
  741.             break;
  742.         case TYP_ERR:
  743.             ptr=ename[cp->cell_err];
  744.             break;
  745. #ifdef TEST
  746.         default:
  747.             ptr=0;
  748.             panic("What cell type %d",GET_TYP(cp));
  749. #endif
  750.         }
  751.  
  752.         if(ptr) {
  753.             if(cp->cell_formula)
  754.                 putc(';',fp);
  755.             (void)fprintf(fp,"K%s",ptr);
  756.         }
  757.  
  758.         putc('\n',fp);
  759.     }
  760.  
  761.     if(rng== &all_rng)
  762.         write_mp_windows(fp);
  763.  
  764.     (void)fprintf(fp,"E\n");
  765. }
  766.  
  767. int
  768. sylk_set_options FUN2(int,set_opt, char *,option)
  769. {
  770.     return -1;
  771. }
  772.  
  773. void
  774. sylk_show_options FUN0()
  775. {
  776.     text_line("File format: sylk  (Microsoft Multiplan interchange format)");
  777. }
  778.