// $Id: sheet_io.cc,v 1.31 1998/09/29 01:22:25 cthulhu Exp $ #include #include #include "sheet.hh" #define LOAD_SHORT(var,address) { \ memcpy(&(var),address,sizeof(short));\ } #define LOAD_DOUBLE(var,address) { \ memcpy(&(var),address,sizeof(double));\ } int Sheet::load(char *filename) { int flin; int n_read; short record_code; short record_length; int done = FALSE; unsigned char buf[512]; short row,col; char format; short fsize; Cell *cell; Sheet_format fmr; int cell_cnt=0; int format_cnt=0; int colrow_format=0; empty = FALSE; flin = open(filename,O_RDONLY,0); if (flin == -1) return(XXL_BAD_FILE); for(;!done;) { cell = NULL; n_read = read(flin,&record_code,2); if (n_read != 2) return(XXL_BAD_RECORD); n_read = read(flin,&record_length,2); if (n_read != 2) return(XXL_BAD_RECORD); n_read = read(flin,buf,record_length); if (n_read != record_length) return(XXL_BAD_RECORD); switch(record_code) { case CODE_BOF: break; case CODE_RECALC: automatic_recalc = *buf; break; case CODE_EOF: done = TRUE; break; case CODE_BLANK: break; case CODE_INTEGER: LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); if (*buf != DEFAULT_FORMAT) { cell->format.form = *buf; } LOAD_SHORT(cell->ivalue,buf+5); cell->type = CODE_INTEGER; cell_cnt++; break; case CODE_NUMBER : LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); if (*buf != DEFAULT_FORMAT) { cell->format.form = *buf; } LOAD_DOUBLE(cell->value,buf+5); cell->type = CODE_NUMBER; cell_cnt++; break; case CODE_LABEL: LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); if (*buf != DEFAULT_FORMAT) { cell->format.form = *buf; } cell->label = strsave((char*)(buf+5)); cell->type = CODE_LABEL; cell_cnt++; break; case CODE_CELL_FONT: LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); if (cell == NULL) { cerr << "Cell font without cell being specified\n"; exit(0); } memcpy((char*)&(cell->format.font),buf+5,4); format_cnt++; break; case CODE_CELL_FORMAT: LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); if (cell == NULL) { cerr << "Cell format without cell being specified\n"; exit(0); } cell->format.alignment = *buf; memcpy((char*)&(cell->format.bg),buf+5,4); memcpy((char*)&(cell->format.borders),buf+9,4); format_cnt++; break; case CODE_STRING_VAL: LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); if (cell == NULL || cell->type != CODE_FORMULA) { cerr << "String value found without formula was specified\n"; exit(0); } cell->formula->st_value = strsave((char*)(buf+5)); cell->formula->typ = FORM_STRING; cell_cnt++; break; case CODE_FORMULA: LOAD_SHORT(col,buf+1); LOAD_SHORT(row,buf+3); cell = cellFind(col,row); LOAD_DOUBLE(cell->value,buf+5); LOAD_SHORT(fsize,buf+13); if (*buf != DEFAULT_FORMAT) { cell->format.form = *buf; } cell->formula = new Formula(fsize,(char*)(buf+15)); cell->type = CODE_FORMULA; manipulateReferences(cell,0); cell_cnt++; break; case CODE_COLW1: fmr.sh_val1 = *(short*)(buf); fmr.c_val1 = *(unsigned char *)(buf+2); set_col_width(fmr.sh_val1,fmr.c_val1*DEFAULT_FONT_WIDTH); colrow_format++; break; case CODE_COLW2: fmr.sh_val1 = *(short*)(buf); fmr.c_val1 = *(unsigned char *)(buf+2); set_col_width(fmr.sh_val1,fmr.c_val1); colrow_format++; break; case CODE_COLW3: fmr.sh_val1 = *(short*)(buf); fmr.sh_val2 = *(short*)(buf+2); set_col_width(fmr.sh_val1,fmr.sh_val2); colrow_format++; break; case CODE_ROWH1: fmr.sh_val1 = *(short*)(buf); fmr.c_val1 = *(unsigned char *)(buf+2); set_row_height(fmr.sh_val1,fmr.c_val1); colrow_format++; break; case CODE_PRANGE: memcpy(&print_range,buf,8); break; case CODE_PSETTINGS: memcpy(&psettings,buf,sizeof(Print_Settings)); break; case CODE_GRAPH: { Graph *grp = new Graph; grp->number = graphs_cnt; grp->iter = -1; graphs[graphs_cnt] = grp; memcpy(grp,buf,sizeof(Graph)); add_graph_deps(grp); graphs_cnt++; } break; case CODE_NOCELLBORDERS: display_cell_borders = FALSE; break; default: break; } } close(flin); modified_after_save = FALSE; return(XXL_OK); } /* #define WRITE_SHORT(address,val) { \ fp_short = (short*)(address);\ *fp_short = val;\ } #define WRITE_DOUBLE(address,val) { \ fp_double = (double*)(address);\ *fp_double = val;\ } */ #define WRITE_SHORT(address,val) { \ memcpy(address,&(val),sizeof(short));\ } #define WRITE_DOUBLE(address,val) { \ memcpy(address,&(val),sizeof(double));\ } int Sheet::save(char *filename,short query) { int flout; int n_read; short record_code; short record_length; int done = FALSE; unsigned char buf[256]; short row,col; char format; short fsize; Cell *cell; Tcl_HashSearch pt; Tcl_HashEntry *entry; int i; int need_to_write_value_record = FALSE; int leng; short cst; int code; short *fp_short; double *fp_double; mode_t mode; /* First, recalculate spreadsheet */ if (recalculate_before_saving && automatic_recalc == 0) { unsigned char prev_mode = automatic_recalc; automatic_recalc = 255; recalculate_list_of_cells(); automatic_recalc = prev_mode; } flout = open(filename,O_RDONLY,0); if (query&&(flout != -1)) { sprintf((char*)buf,"queryUser {File %s exists.\nDo you want to overwrite it ? } {Yes Cancel}", filename); code = Tcl_Eval(interp,(char*)buf); if (code == TCL_OK) { if (interp->result[0] == '0') ; else if (interp->result[0] == '1') { sprintf((char*)buf,"warnUser {Sheet %s not saved ! }", (char*)name); code = Tcl_Eval(interp,(char*)buf); return(XXL_ABORT); } } else internal_error(); } mode = 0644; flout = creat(filename,mode); if (flout == -1) return(XXL_BAD_FILE); record_code = CODE_BOF; record_length = 2; buf[0] = 6; buf[1] = 4; code = write_record(flout,record_code,record_length,(char*)buf); if (code != XXL_OK) return(code); record_code = CODE_RECALC; record_length = 1; buf[0] = automatic_recalc; code = write_record(flout,record_code,record_length,(char*)buf); if (code != XXL_OK) return(code); /* Now, lets write the cells */ for(entry = Tcl_FirstHashEntry(&cells,&pt); entry ; entry = Tcl_NextHashEntry(&pt)) { cell = (Cell*)Tcl_GetHashValue(entry); record_code = cell->type; switch(cell->type) { case CODE_BLANK: break; case CODE_INTEGER: record_length = 7; *buf = cell->format.form; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); WRITE_SHORT(buf+5,cell->ivalue); write_record(flout,record_code,record_length,(char*)buf); break; case CODE_NUMBER : record_length = 13; *buf = cell->format.form; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); WRITE_DOUBLE(buf+5,cell->value); write_record(flout,record_code,record_length,(char*)buf); break; case CODE_LABEL: record_length = strlen(cell->label)+1+5; *buf = cell->format.form; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); memcpy(buf+5,cell->label,record_length-5); write_record(flout,record_code,record_length,(char*)buf); break; case CODE_FORMULA: record_length = 15+cell->formula->size; *buf = cell->format.form; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); WRITE_DOUBLE(buf+5,cell->value); WRITE_SHORT(buf+13,cell->formula->size); memcpy(buf+15,cell->formula->formula,cell->formula->size); write_record(flout,record_code,record_length,(char*)buf); if (cell->formula->typ == FORM_STRING){ record_code = CODE_STRING_VAL; leng = strlen(cell->formula->st_value)+1; record_length = 5+leng; *buf = cell->format.form; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); memcpy(buf+5,cell->formula->st_value,leng); write_record(flout,record_code,record_length,(char*)buf); } break; default: break; } if (!cell->format.font.isdefault()) { record_code = CODE_CELL_FONT; record_length = 9; *buf = cell->format.form; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); memcpy(buf+5,(char*)&(cell->format.font),4); write_record(flout,record_code,record_length,(char*)buf); } if (!cell->format.bg.isdefault() || !cell->format.borders.isdefault() || cell->format.alignment != DEFAULT_ALIGNMENT) { record_code = CODE_CELL_FORMAT; record_length = 13; *buf = cell->format.alignment; WRITE_SHORT(buf+1,cell->col); WRITE_SHORT(buf+3,cell->row); memcpy(buf+5,(char*)&(cell->format.bg),4); memcpy(buf+9,(char*)&(cell->format.borders),4); write_record(flout,record_code,record_length,(char*)buf); } } /* Now, let's write down special formats */ for (cst=0; cst 0){ n_b = write(fp,data,length); if (n_b != length) return(XXL_ERROR_WRIT); } modified_after_save = FALSE; return(XXL_OK); } /* $Log: sheet_io.cc,v $ Revision 1.31 1998/09/29 01:22:25 cthulhu Added query option to save so it can work silently (autosave). Revision 1.30 1998/08/06 21:08:37 aml Released alpha version of Abacus. // Revision 1.29 1997/03/27 10:00:42 aml // Started implementing graphs. // Fixed bug in tkCanvasPs.c // Created bindings for composite characters in Portuguese. // Revision 1.28 1997/02/10 15:10:53 aml TODO: Improve print setup. Save it in the sheet. DONE V0.8.22 // Revision 1.27 1997/01/02 16:15:33 aml // Fixed unsufficient range of colunm width. // First cut of vlookup and hlookup functions. // Fixed bug in display routines. // Revision 1.26 1996/12/31 17:38:39 aml On-demand calculation improved. Loops are detected. Automatic recalculation can now be disabled. Printing was improved. Revision 1.25 1996/12/11 21:40:01 aml Sumif implemented. Diverse time functions implemented. Fixed needtoscroll2 to avoid out of control scroll. // Revision 1.24 1996/11/22 16:29:15 aml // First cut at transforming canvas into a true cell widget. // Text, lines and rectangles are now relative to row and colunm numbers. // It still has a bug with wrong estimation of column widths. // Revision 1.23 1996/09/15 19:24:29 aml Rulling and shading. Optionally hide cell borders. Works well, but is very slow for large spreadsheets. // Revision 1.22 1996/09/14 23:55:58 aml // Created cell shading. // // Revision 1.21 1996/09/04 14:29:57 aml // Fixed double redrawing of sheets that was taking place. // Fixed a item reference problem when the sheet is redrawn. // Fixed misplacement of row labels. // Created first version of format toolbar. // Revision 1.20 1996/09/02 10:51:20 aml Cell fonts created, loaded and saved. Row height created. // Revision 1.19 1996/08/28 17:17:51 aml // Load and save now accept string_value for formula cells. // This fixes previous thought problem of formula values not // being stored. // Functions upper,lower and proper created. // Function if can now return labels. // Fixed problem with function count. // Reasonably stable version, very used to manipulate notas.wk1. // Revision 1.18 1996/08/26 12:08:46 aml Fixed problem with several sheets. Each canvas now has its own canvas info. Fixed scroll up and down. Implemented max_row and max_col. Fairly stable version. // Revision 1.17 1996/07/18 10:19:26 aml // Created formats for cells. // Load cell now makes copy of old file. // // Revision 1.16 1996/04/23 09:42:53 aml // Data structures for ordered scans of rows and columns are in place. // Cell overlap is working. // Forward cell dependences inserted. Automatic recalculation created. // Uniformizaed label entry procedure. // Revision 1.15 1996/04/19 10:46:36 aml First cut at speeding up canvas critical functions. CanvasWidgetCommand is now called directly from draw_sheet. Fixed bug in reading values from datafiles. Also works for Suns now. Created canvas directory, replacing builtin command canvas. Revision 1.14 1996/03/29 21:45:40 aml Changed key based scrolls to be synchronous. Work fine, but are somewhat slow. Fixed abnormaly in state machine after range defition causing canvas scroll. Solid, working version. // Revision 1.13 1996/03/11 15:47:48 aml // Made redraw more efficient by removing at once all cells before redrawing. // Fixed problem with unsufficient difinition of logical expressions. // Added >=, <=, <>, @and and @or functions. // Revision 1.12 1996/03/07 20:33:04 aml Created print range ability. Set in gray non-working menus. Created RangeKill command. Created round function and macros for single argument functions. Revision 1.11 1996/03/06 20:25:25 aml Improved user waiting times during redraw and loads by calling update. Revision 1.10 1996/03/01 13:08:48 aml Stack references are now pushed instead of double value. Fixed problem with integers too large on formulas. Scroll with cursors now works better. Revision 1.9 1996/02/16 18:04:08 aml Fixed a memory bug in formula copy with purify. Fixed a few minor bugs. Functional, stable version. Revision 1.8 1996/02/13 12:03:46 aml Fixed bug with range definition via mouse. Fixed bug in range iterators. // Revision 1.7 1996/01/30 16:05:39 aml // User interface for cell and range copy created. // Improved user interface state machine when entering and viewing cells. // Fixed unaligned accesses during formula parsing and io operations. // // Revision 1.6 1996/01/11 22:48:50 aml // Range iterators created. // Functions sum, max and min now work properly. // Negative numbers now allowed by flex (oops :-) // // Revision 1.5 1996/01/10 18:54:33 aml // Removed fixed format for cells when writing. // // Revision 1.4 1996/01/10 18:53:41 aml // Fixed limited integer range of cells. // Fixed incorrect code in spreadsheet type. // Users interface improved. Cursors and mouse clicks // now work in the most basic modes. // // Revision 1.3 1996/01/09 18:34:52 aml // Load, save, open, close and exit now work properly (hopefuly). // Sheet utility functions also work : SheetExists, SheetEmpty, SheetModified // // Revision 1.2 1996/01/07 09:07:38 aml // Sheet::save and Sheet::load created. // Program can now write and read wk1 files. // Slight changes made to relative references. Bit 14 is now always 0. // // Revision 1.1 1996/01/06 20:44:35 aml // Initial revision // */