/******************************************************************** This file is part of the abs 0.907 distribution. abs is a spreadsheet with graphical user interface. Copyright (C) 1998-2001 André Bertin (Andre.Bertin@ping.be) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version if in the same spirit as version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Concact: abs@pi.be http://home.pi.be/bertin/abs.shtml *********************************************************************/ #include "cell_vb.h" #include "formula_interpret.h" #include "libfct.h" #include "application.h" #include "worksheet.h" #include "node.h" #include "border_vb.h" #include "memory.h" #include "util.h" #include "print.h" obj vb_absnewcell (narg, arg) int narg; obj *arg; { obj o; Cell *cell = NULL; if (arg[0].type == INTEGER && arg[1].type == INTEGER && arg[2].type == STRING_CONSTANT) { cell = applicationcell (obj2int (arg[0]), obj2int (arg[1]), 1); cell_setformula (cell, obj2string (arg[2])); } o.rec.s = (char *) cell; o.type = CELL; o.label = arrayclass[CELL].name; return o; } obj vb_getcell (narg, arg) int narg; obj *arg; { obj o; Cell *cell; o.rec.s = (char *) applicationcell (obj2int (arg[0]), obj2int (arg[1]), 1); cell = (Cell *) o.rec.s; o.type = CELL; o.label = arrayclass[CELL].name; return o; } obj vb_getrange1 (narg, arg) int narg; obj *arg; { obj o; if (narg == 1) { if (arg[0].type == RANGE) return arg[0]; o.rec.s = obj2string (arg[0]); o.type = RANGE; o.label = NULL; return o; } return o; } obj vb_get_ActiveCell () { obj o; o.rec.s = (char *) ActiveCell; o.type = CELL; o.label = NULL; return o; } extern int getselection (int *i1, int *j1, int *i2, int *j2); obj vb_get_Selection () { obj o; int i1, i2, j1, j2; getselection (&i1, &j1, &i2, &j2); if (i1 == i2 && j1 == j2) { o.rec.s = (char *) applicationcell (i1, j1, 1); o.type = CELL; } else { } o.label = NULL; return o; } obj vb_cell_setobj (narg, arg) int narg; obj *arg; { obj o; int r, c; tmpRange *ran; if (arg[0].type == CELL) { cell_setobj ((Cell *) arg[0].rec.s, arg[1]); return o; } if (arg[0].type == RANGE) { ran = (tmpRange *) arg[0].rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) cell_setobj (applicationcell (r, c, 1), arg[1]); } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) cell_setobj (worksheet_getcell (ran->wks, r, c, 1), arg[1]); } } return o; } obj vb_cell_getobj (narg, arg) int narg; obj *arg; { obj o; o = cell_getobj ((Cell *) arg[0].rec.s); return o; } obj vb_cell_setvalue (narg, arg) int narg; obj *arg; { obj o; int r, c; tmpRange *ran; obj *cellORrange = (obj *) arg[0].rec.s; if (cellORrange->type == CELL) { cell_setobj ((Cell *) cellORrange->rec.s, arg[1]); return o; } if (cellORrange->type == RANGE) { ran = (tmpRange *) cellORrange->rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) cell_setobj (applicationcell (r, c, 1), arg[1]); } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) cell_setobj (worksheet_getcell (ran->wks, r, c, 1), arg[1]); } } return o; } obj vb_cell_getvalue (narg, arg) int narg; obj *arg; { obj o; obj *cell = (obj *) arg[0].rec.s; o = cell_getobj ((Cell *) cell->rec.s); return o; } obj vb_cell_setformula (narg, arg) int narg; obj *arg; { obj o; obj *cell = (obj *) arg[0].rec.s; if (arg[1].type == STRING_CONSTANT) { cell_setformula ((Cell *) cell->rec.s, obj2string (arg[1])); } return o; } obj vb_cell_getformula (narg, arg) int narg; obj *arg; { obj o; o.rec.d = cell_getvalue ((Cell *) arg[0].rec.s); o.type = DOUBLE; return o; } obj vb_cell_sethalign (narg, arg) int narg; obj *arg; { obj o; obj *cell = (obj *) arg[0].rec.s; cell_setjust ((Cell *) cell->rec.s, obj2int (arg[1])); return o; } obj vb_cell_gethalign (narg, arg) int narg; obj *arg; { obj o; o.rec.d = cell_getvalue ((Cell *) arg[0].rec.s); o.type = DOUBLE; return o; } obj vb_cell_setnumform (narg, arg) int narg; obj *arg; { obj o; obj *cell = (obj *) arg[0].rec.s; cell_setnumberformat ((Cell *) cell->rec.s, obj2string (arg[1])); return o; } obj vb_cell_getnumform (narg, arg) int narg; obj *arg; { obj o; o.rec.d = cell_getvalue ((Cell *) arg[0].rec.s); o.type = DOUBLE; return o; } obj vb_cell_setinterior (narg, arg) int narg; obj *arg; { obj o; obj *cell = (obj *) arg[0].rec.s; cell_setbg ((Cell *) cell->rec.s, obj2int (arg[1])); return o; } obj vb_cell_getinterior (narg, arg) int narg; obj *arg; { obj o; o.rec.d = cell_getvalue ((Cell *) arg[0].rec.s); o.type = DOUBLE; return o; } static Border bord; obj vb_cell_getborder (narg, arg) int narg; obj *arg; { obj o; bord.which = obj2int (arg[1]); bord.object = arg[0]; o.type = BORDER; o.label = NULL; o.rec.s = (char *) &bord; return o; } obj vb_cell_getborders (narg, arg) int narg; obj *arg; { obj o; bord.which = 0; bord.object = arg[0]; o.type = BORDER; o.label = NULL; o.rec.s = (char *) &bord; return o; } obj vb_cell_setborders (narg, arg) int narg; obj *arg; { obj o; bord.which = 0; bord.object = arg[0]; o.type = BORDER; o.label = NULL; o.rec.s = (char *) &bord; return o; } obj vb_cell_assign (narg, arg) int narg; obj *arg; { obj o; if (arg[0].type != CELL) return o; if (arg[1].type == CELL) { obj val = cell_getobj ((Cell *) arg[1].rec.s); cell_setobj ((Cell *) arg[0].rec.s, val); } else { cell_setobj ((Cell *) arg[0].rec.s, arg[1]); } return o; } obj vb_cell_print (narg, arg) int narg; obj *arg; { obj o = arg[0]; if (arg[0].type == CELL) { printparam.print2file = 1; printparam.language = "ps"; printparam.print2file = PORTRAIT; printparam.center = FLUSH_TOP_LEFT; printparam.magnification = 1.0; printparam.copies = 1; printparam.papertype = "A4"; printparam.xshift = 0; printparam.yshift = 0; printparam.multiplepage = 0; printparam.filename = "output.ps"; printfile (printparam); return o; } o.type = INTEGER; return o; } extern int setselection (int i1, int j1, int i2, int j2); obj vb_cell_select (narg, arg) int narg; obj *arg; { obj o = arg[0]; if (arg[0].type == CELL) { Cell *cell = (Cell *) arg[0].rec.s; setselection (cell->r, cell->c, cell->r, cell->c); return o; } if (arg[0].type == RANGE) { char *valuerange = arg[0].rec.s; char *i1j1; char *i2j2; char *separ; int r1, c1, r2, c2; if (valuerange == NULL) return o; separ = strchr (valuerange, ':'); if (separ == NULL) return o; i1j1 = valuerange; i2j2 = separ + 1; separ[0] = '\0'; alphatonum (i1j1, &r1, &c1); alphatonum (i2j2, &r2, &c2); setselection (r1, c1, r2, c2); } return o; } static int rrr, ccc; static nodeType *wksname = NULL; static int dr = 0; static int dc = 0; static int sr = -1; static int sc = -1; int get_id2row () { return rrr; } int get_id2col () { return ccc; } int setdi (int i) { dr = i; return 0; } int setdj (int j) { dc = j; return 0; } int setsi (int i) { sr = i; return 0; } int setsj (int j) { sc = j; return 0; } char * newformula (str) char *str; { char tok; char token[32]; char newstr[512]; int letter, number; int lval, nval, v; int found; int i, j, k, spc, newj; int dollet, dolnum; j = 0; newj = 0; while (j < strlen (str)) { found = 0; dolnum = dollet = 0; lval = nval = 0; if (str[j] == '\"') { do { newstr[newj] = str[j]; j++; newj++; } while (str[j] != '\"' && j < strlen (str)); if (str[j] == '\"') { newstr[newj] = str[j]; j++; newj++; } } i = j; tok = str[i]; if (tok == '$') { dollet = 1; i++; } letter = 0; do { tok = str[i]; v = isletter (tok); if (v) { lval = lval * 26 + v; letter = 1; i++; } else { letter = 0; } } while (letter); if (lval > 0) { if (tok == '$') { dolnum = 1; i++; } do { tok = str[i]; v = isnumber (tok); if (v >= 0) { nval = nval * 10 + v; number = 1; i++; } else { number = 0; } } while (number); if (nval > 0) { spc = 0; while (tok == ' ') { i++; spc++; tok = str[i]; } if (tok != '!' && tok != '(') { found = 1; if (!dollet && lval > sc) lval += dc; if (!dolnum && nval > sr) nval += dr; if (nval < 1) nval = 1; if (lval < 1) lval = 1; if (nval > ActiveWorksheet->nblin - 1) nval = ActiveWorksheet->nblin - 1; if (lval > ActiveWorksheet->nbcol - 1) nval = ActiveWorksheet->nbcol - 1; numtoalpha2 (token, nval, lval, dolnum, dollet); for (k = 0; k < strlen (token); k++) { newstr[newj] = token[k]; newj++; } for (k = 0; k < spc; k++) { newstr[newj] = ' '; newj++; } j = i; } } } if (!found) { for (k = j; k <= i; k++) { newstr[newj] = str[k]; newj++; } j = i + 1; } } newstr[newj] = '\0'; str = (char *) absrealloc (str, strlen (newstr) + 5, "newformula"); strcpy (str, newstr); return str; } int check_if_id_is_cell (o) obj o; { int v; int i; char tok; char *str = o.label; int dollet = 0; int dolnum = 0; int letter, number; int nval = 0; int lval = 0; i = 0; tok = str[i]; if (tok == '$') { dollet = 1; i++; } letter = 0; do { tok = str[i]; v = isletter (tok); if (v) { lval = lval * 26 + v; letter = 1; i++; } else { letter = 0; } } while (letter); if (lval > 0 && lval <= NB_COLUMN) { if (tok == '$') { dolnum = 1; i++; } do { tok = str[i]; v = isnumber (tok); if (v >= 0) { nval = nval * 10 + v; number = 1; i++; } else { number = 0; } } while (number); if (nval > 0) { if (!dolnum) rrr = nval + dr; else rrr = nval; if (!dollet) ccc = lval + dc; else ccc = lval; return 1; } } return 0; } static int rangeopr = 0; static nodeType *sheet1 = NULL; static int r1 = -1; static int c1 = -1; static nodeType *sheet2 = NULL; static int r2 = -1; static int c2 = -1; obj modcelltree (nodeType ** p) { int i, nops; obj o; nodeType *wks; if (!*p) return o; switch ((*p)->type) { case typeCon: { return o; } case typeId: { if (check_if_id_is_cell ((*p)->id.id)) { obj r, c; nodeType *argu; c.type = r.type = INTEGER; c.label = r.label = NULL; r.rec.i = get_id2row (); c.rec.i = get_id2col (); if (rangeopr == 1) { r1 = get_id2row (); c1 = get_id2col (); sheet1 = wksname; } if (rangeopr == 2) { r2 = get_id2row (); c2 = get_id2col (); sheet2 = wksname; } if (ActiveWorksheet != NULL && wksname == NULL) wks = id (createidentifier (ActiveWorksheet->Name)); else wks = wksname; if (wks == NULL) { cell1isfcell2 (ActiveCell, applicationcell (r.rec.i, c.rec.i, 1)); (*p)->id.id.label = "cells"; (*p)->id.id.type = BUILTINFUNCTION; (*p)->id.id.rec.i = 0; argu = opr (ARG, "Arg", 1, con (r)); argu = opr (ARG, "Arg", 2, argu, con (c)); } else { cell1isfcell2 (ActiveCell, applicationwkscell (wks->id.id.label, r.rec.i, c.rec.i, 1)); (*p)->id.id.label = "wkscells"; (*p)->id.id.type = BUILTINFUNCTION; (*p)->id.id.rec.i = 1; argu = opr (ARG, "Arg", 1, wks); argu = opr (ARG, "Arg", 2, argu, con (r)); argu = opr (ARG, "Arg", 2, argu, con (c)); } (*p) = opr (BUILTINFUNCTION, "call", 2, *p, argu); return o; } return o; } case typeOpr1: { o = modcelltree (&((*p)->opr1.op1)); return o; } case typeOpr2: { o = modcelltree (&((*p)->opr2.op1)); o = modcelltree (&((*p)->opr2.op2)); return o; } case typeOpr: switch ((*p)->opr.oper.rec.i) { case '!': { wksname = ((*p)->opr.op[0]); modcelltree (&(*p)->opr.op[1]); *p = (*p)->opr.op[1]; wksname = NULL; return o; } case ':': { int rr, cc; obj tmp; nodeType *argu; nodeType *ranfct = id (o); tmpRange *ran; ranfct->id.id.label = "range_old"; ranfct->id.id.type = BUILTINFUNCTION; ranfct->id.id.rec.i = 2; rangeopr = 1; modcelltree (&(*p)->opr.op[0]); rangeopr = 2; modcelltree (&(*p)->opr.op[1]); rangeopr = 0; if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0) return o; if (r2 < r1) { rr = r2; r2 = r1; r1 = rr; } if (c2 < c1) { cc = c2; c2 = c1; c1 = cc; } for (rr = r1; rr <= r2; rr++) for (cc = c1; cc <= c2; cc++) if (sheet1 != NULL) cell1isfcell2 (ActiveCell, applicationwkscell (sheet1->id.id.label, rr, cc, 1)); else cell1isfcell2 (ActiveCell, applicationcell (rr, cc, 1)); ran = (tmpRange *) absmalloc (sizeof (tmpRange), "cell_range:tmpRange"); if (sheet1 != NULL) ran->wks = (Worksheet *) workbook_getsheet (ActiveWorkbook, sheet1->id.id.label); else ran->wks = ActiveCell->worksheet; ran->r1 = r1; ran->c1 = c1; ran->r2 = r2; ran->c2 = c2; tmp.type = RANGE; tmp.rec.s = (char *) ran; tmp.label = NULL; argu = opr (ARG, "Arg", 1, con (tmp)); (*p) = opr (BUILTINFUNCTION, "call", 2, ranfct, argu); sheet1 = NULL; sheet2 = NULL; r1 = c1 = r2 = c2 = -1; return o; } default: { nops = (*p)->opr.nops; for (i = 0; i < nops; i++) { o = modcelltree (&((*p)->opr.op[i])); } } return o; } default: break; } return o; } int cell_is_constant (Cell * cell) { nodeType *p; if (cell == NULL) return 0; if (cell->tree == NULL) return 0; p = cell->tree; switch (p->type) { case typeCon: { if (p->con.value.type == INTEGER) { cell->val = p->con.value; return 1; } if (p->con.value.type == DOUBLE) { cell->val = p->con.value; return 1; } } case typeOpr1: { if (p->opr1.op1->type == typeCon) { if (p->con.value.type == INTEGER) { cell->val = p->con.value; cell->val.rec.i = -cell->val.rec.i; return 1; } if (p->con.value.type == DOUBLE) { cell->val = p->con.value; cell->val.rec.d = -cell->val.rec.d; return 1; } } } default: return 0; } return 0; } int setcelltree (tree) nodeType *tree; { modcelltree (&tree); ActiveCell->tree = tree; if (dr || dc) ActiveCell->formula = newformula (ActiveCell->formula); return 0; } int execcelltree (cell) Cell *cell; { obj o2; o2 = exform (cell->tree); if (o2.type == IDENTIFIER) o2 = id2val (o2); if (o2.type == CELL) cell_setresval (cell, ((Cell *) o2.rec.s)->val); else cell_setresval (cell, o2); freenocstobj (o2); return 0; } static double *arraydouble = NULL; static int dimarraydouble = 0; double * getarraydouble () { return arraydouble; } int freearraydouble () { if (arraydouble != NULL) absfree (arraydouble, "freearraydouble"); arraydouble = NULL; return 0; } int sortarraydouble () { int i, k; if (arraydouble == NULL) { return -1; } for (i = 0; i < dimarraydouble; i++) { for (k = i; k < dimarraydouble; k++) if (arraydouble[k] < arraydouble[i]) { double l = arraydouble[k]; arraydouble[k] = arraydouble[i]; arraydouble[i] = l; } } return 0; } int arg2arraydouble (int narg, obj * arg) { int dim = 0; int pos = 0; int i, r, c; for (i = 0; i < narg; i++) { if (arg[i].type == RANGE) { tmpRange *ran = (tmpRange *) arg[i].rec.s; dim += (ran->r2 - ran->r1 + 1) * (ran->c2 - ran->c1 + 1); if (dim != 0); arraydouble = (double *) absrealloc (arraydouble, dim * sizeof (double), "arg2arraydouble"); if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { arraydouble[pos] = get_value (r, c); pos++; } } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { arraydouble[pos] = get_value_wks (ran->wks, r, c); pos++; } } } else { dim++; arraydouble = (double *) absrealloc (arraydouble, dim * sizeof (double), "arg2arraydouble"); arraydouble[pos] = obj2double (arg[i]); pos++; } } dimarraydouble = dim; return dim; }