/* Turbo C - (C) Copyright 1987,1988 by Borland International */ #include #include #include #include #include #include #include #include #include "mcalc.h" int alloctext(int col, int row, char *s) /* Allocates space for a text cell */ { int size; CELLPTR cellptr; if (memleft < (size = textcellsize(s))) return(FALSE); memleft -= size; cellptr = (CELLPTR)(malloc(strlen(s) + 2)); cellptr->attrib = TEXT; strcpy(cellptr->v.text, s); cell[col][row] = cellptr; return(TRUE); } /* alloctext */ int allocvalue(int col, int row, double amt) /* Allocates space for a value cell */ { CELLPTR cellptr; if (memleft < valuecellsize) return(FALSE); memleft -= valuecellsize; cellptr = (CELLPTR)(malloc(sizeof(double) + 1)); cellptr->attrib = VALUE; cellptr->v.value = amt; cell[col][row] = cellptr; return(TRUE); } /* allocvalue */ int allocformula(int col, int row, char *s, double amt) /* Allocates space for a formula cell */ { int size; CELLPTR cellptr; if (memleft < (size = formulacellsize(s))) return(FALSE); memleft -= size; cellptr = (CELLPTR)(malloc(strlen(s) + sizeof(double) + 2)); cellptr->attrib = FORMULA; strcpy(cellptr->v.f.formula, s); cellptr->v.f.fvalue = amt; cell[col][row] = cellptr; return(TRUE); } /* allocformula */ void deletecell(int col, int row, int display) /* Deletes a cell */ { CELLPTR cellptr = cell[col][row]; if (cellptr == NULL) return; switch (cellptr->attrib) { case TEXT : memleft += textcellsize(cellptr->v.text); clearoflags(col + 1, row, display); break; case VALUE : memleft += valuecellsize; break; case FORMULA : memleft += formulacellsize(cellptr->v.f.formula); break; } /* switch */ format[col][row] &= ~OVERWRITE; free(cell[col][row]); cell[col][row] = NULL; if (col == lastcol) setlastcol(); if (row == lastrow) setlastrow(); updateoflags(col, row, display); changed = TRUE; } /* deletecell */ void printfreemem(void) /* Prints the amount of free memory */ { writef(strlen(MSGMEMORY) + 2, 1, MEMORYCOLOR, 6, "%6ld", memleft); } /* printfreemem */ int rowwidth(int row) /* Returns the width in spaces of row */ { return((row == 0) ? 1 : (int)log10(row + 1) + 1); } /* rowwidth */ int formulastart(char **input, int *col, int *row) /* Returns TRUE if the string is the start of a formula, FALSE otherwise. Also returns the column and row of the formula. */ { int len, maxlen = rowwidth(MAXROWS); char *start, numstring[10]; if (!isalpha(**input)) return(FALSE); *col = *((*input)++) - 'A'; if (isalpha(**input)) { *col *= 26; *col += *((*input)++) - 'A' + 26; } if (*col >= MAXCOLS) return(FALSE); start = *input; for (len = 0; len < maxlen; len++) { if (!isdigit(*((*input)++))) { (*input)--; break; } } if (len == 0) return(FALSE); strncpy(numstring, start, len); numstring[len] = 0; *row = atoi(numstring) - 1; if ((*row >= MAXROWS) || (*row == -1)) return(FALSE); return(TRUE); } /* formulastart */ void errormsg(char *s) /* Prints an error message at the bottom of the screen */ { printf("%c", 7); /* Beeps the speaker */ writef(1, 25, ERRORCOLOR, 79, "%s %s", s, MSGKEYPRESS); gotoxy(strlen(s) + strlen(MSGKEYPRESS) + 3, 25); getkey(); gotoxy(1, 25); writef(1, 25, WHITE, 79, ""); } /* errormsg */ void fixformula(int col, int row, int action, int place) /* Modifies a formula when its column or row designations need to change. */ { char *colstart, *rowstart, s[6], newformula[MAXINPUT + 1], *curpos = newformula; int fcol, frow; CELLPTR cellptr = cell[col][row]; double value; strcpy(newformula, cellptr->v.f.formula); while (*curpos != 0) { if (formulastart(&curpos, &fcol, &frow)) { rowstart = curpos - rowwidth(frow); colstart = rowstart - ((fcol > 25) ? 2 : 1); switch (action) { case COLADD : if (fcol < place) break; if (fcol == 25) { if (strlen(newformula) == MAXINPUT) { deletecell(col, row, NOUPDATE); alloctext(col, row, newformula); return; } movmem(colstart, colstart + 1, strlen(colstart) + 1); } colstring(fcol + 1, s); movmem(s, colstart, strlen(s)); break; case ROWADD : if (frow < place) break; if (rowwidth(frow + 1) != rowwidth(frow)) { if (strlen(newformula) == MAXINPUT) { deletecell(col, row, NOUPDATE); alloctext(col, row, newformula); return; } movmem(rowstart, rowstart + 1, strlen(rowstart) + 1); } sprintf(s, "%d", frow + 2); movmem(s, rowstart, strlen(s)); break; case COLDEL : if (fcol <= place) break; if (fcol == 26) movmem(colstart + 1, colstart, strlen(colstart) + 1); colstring(fcol - 1, s); movmem(s, colstart, strlen(s)); break; case ROWDEL : if (frow <= place) break; if (rowwidth(frow) != rowwidth(frow - 1)) movmem(rowstart + 1, rowstart, strlen(rowstart) + 1); sprintf(s, "%d", frow); movmem(s, rowstart, strlen(s)); break; } /* switch */ } else curpos++; } if (strlen(newformula) != strlen(cellptr->v.f.formula)) { value = cellptr->v.f.fvalue; deletecell(col, row, NOUPDATE); allocformula(col, row, newformula, value); } else strcpy(cellptr->v.f.formula, newformula); } /* fixformula */ void colstring(int col, char *colstr) /* Changes a column number to a string */ { setmem(colstr, 3, 0); if (col < 26) colstr[0] = col + 'A'; else { colstr[0] = (col / 26) - 1 + 'A'; colstr[1] = (col % 26) + 'A'; } } /* colstring */ void centercolstring(int col, char *colstr) /* Changes a column to a centered string */ { char s[3]; int spaces1, spaces2; colstring(col, s); spaces1 = (colwidth[col] - strlen(s)) >> 1; spaces2 = colwidth[col] - strlen(s) - spaces1; sprintf(colstr, "%*s%s%*s", spaces1, "", s, spaces2, ""); } /* centercolstring */ void setleftcol(void) /* Sets the value of leftcol based on the value of rightcol */ { int total = 80, col = 0; while ((total >= LEFTMARGIN) && (rightcol - col >= 0)) { colstart[SCREENCOLS - col - 1] = total - colwidth[rightcol - col]; total -= colwidth[rightcol - col++]; } if (total >= LEFTMARGIN) col++; movmem(&colstart[SCREENCOLS - col + 1], colstart, col - 1); leftcol = rightcol - col + 2; total = colstart[0] - LEFTMARGIN; if (total != 0) { for (col = leftcol; col <= rightcol; col++) colstart[col - leftcol] -= total; } printcol(); } /* setleftcol */ void setrightcol(void) /* Sets the value of rightcol based on the value of leftcol */ { int total = LEFTMARGIN, col = 0; do { colstart[col] = total; total += colwidth[leftcol + col++]; } while ((total <= 80) && (leftcol + col <= MAXCOLS)); rightcol = leftcol + col - 2; printcol(); } /* setrightcol */ void settoprow(void) /* Figures out the value of toprow based on the value of bottomrow */ { if (bottomrow - SCREENROWS < -1) bottomrow = 19; toprow = bottomrow - 19; printrow(); } /* settoprow */ void setbottomrow(void) /* Figures out the value of bottomrow based on the value of toprow */ { if (toprow + SCREENROWS > MAXROWS) toprow = MAXROWS - 20; bottomrow = toprow + 19; printrow(); } /* setbottomrow */ void setlastcol(void) /* Sets the value of lastcol based on the current value */ { register int row, col; for (col = lastcol; col >= 0; col--) { for (row = 0; row <= lastrow; row++) { if (cell[col][row] != NULL) { lastcol = col; return; } } } lastcol = 0; } /* setlastcol */ void setlastrow(void) /* Sets the value of lastrow based on the current value */ { register int row, col; for (row = lastrow; row >= 0; row--) { for (col = 0; col <= lastcol; col++) { if (cell[col][row] != NULL) { lastrow = row; return; } } } lastrow = 0; } /* setlastrow */ void act(char *s) /* Acts on a particular input */ { int attrib, allocated; double value; deletecell(curcol, currow, UPDATE); value = parse(s, &attrib); switch(attrib) { case TEXT : allocated = alloctext(curcol, currow, s); if (allocated) displaycell(curcol, currow, NOHIGHLIGHT, NOUPDATE); break; case VALUE : allocated = allocvalue(curcol, currow, value); break; case FORMULA : allocated = allocformula(curcol, currow, s, value); break; } /* switch */ if (allocated) { format[curcol][currow] &= ~OVERWRITE; clearoflags(curcol + 1, currow, UPDATE); if (attrib == TEXT) setoflags(curcol, currow, UPDATE); if (curcol > lastcol) lastcol = curcol; if (currow > lastrow) lastrow = currow; if (autocalc) recalc(); } else errormsg(MSGLOMEM); printfreemem(); } /* act */ int setoflags(int col, int row, int display) /* Sets the overwrite flag on cells starting at (col + 1, row) - returns the number of the column after the last column set. */ { int len; len = strlen(cell[col][row]->v.text) - colwidth[col]; while ((++col < MAXCOLS) && (len > 0) && (cell[col][row] == NULL)) { format[col][row] |= OVERWRITE; len -= colwidth[col]; if (display && (col >= leftcol) && (col <= rightcol)) displaycell(col, row, NOHIGHLIGHT, NOUPDATE); } return(col); } /* setoflags */ void clearoflags(int col, int row, int display) /* Clears the overwrite flag on cells starting at (col, row) */ { while ((format[col][row] >= OVERWRITE) && (col < MAXCOLS) && (cell[col][row] == NULL)) { format[col][row] &= ~OVERWRITE; if (display && (col >= leftcol) && (col <= rightcol)) displaycell(col, row, NOHIGHLIGHT, NOUPDATE); col++; } } /* clearoflags */ void updateoflags(int col, int row, int display) /* Starting in col, moves back to the last TEXT cell and updates all flags */ { while ((cell[col][row] == NULL) && (col-- > 0)); if ((cell[col][row] != NULL) && (cell[col][row]->attrib == TEXT) && (col >= 0)) setoflags(col, row, display); } /* updateoflags */ void textstring(char *instring, char *outstring, int col, int fvalue, int formatting) /* Sets the string representation of text */ { char *just, *ljust = "%-*s", *rjust = "%*s"; if ((fvalue & RJUSTIFY) && (formatting)) just = rjust; else just = ljust; sprintf(outstring, just, colwidth[col], instring); if (formatting) outstring[colwidth[col]] = 0; } /* textstring */ void valuestring(CELLPTR cellptr, double value, char *vstring, int col, int fvalue, int *color, int formatting) /* Sets the string representation of a value */ { char s[81]; char *fstring; int width, pos; if (value == HUGE_VAL) { strcpy(vstring, MSGERROR); *color = ERRORCOLOR; } else { if (formatting) { sprintf(vstring, "%1.*f", fvalue & 15, cellptr->v.value); if (fvalue & COMMAS) { pos = strcspn(vstring, "."); while (pos > 3) { pos -= 3; if (vstring[pos - 1] != '-') { movmem(&vstring[pos], &vstring[pos + 1], strlen(vstring) - pos + 1); vstring[pos] = ','; } } } if (fvalue & DOLLAR) { if (vstring[0] == '-') { fstring = " $"; width = colwidth[col] - 2; } else { fstring = " $ "; width = colwidth[col] - 3; } } else { fstring = ""; width = colwidth[col]; } strcpy(s, vstring); if (fvalue & RJUSTIFY) { if (strlen(vstring) > width) vstring[width] = 0; else sprintf(vstring, "%*s", width, s); } else sprintf(vstring, "%-*s", width, s); movmem(vstring, &vstring[strlen(fstring)], strlen(vstring) + 1); strncpy(vstring, fstring, strlen(fstring)); } else sprintf(vstring, "%.*f", MAXPLACES, value); *color = VALUECOLOR; } } /* valuestring */ char *cellstring(int col, int row, int *color, int formatting) /* Creates an output string for the data in the cell in (col, row), and also returns the color of the cell */ { CELLPTR cellptr = cell[col][row]; int newcol, formatvalue; static char s[81], temp[MAXCOLWIDTH + 1]; char *p; double value; if (cellptr == NULL) { if (!formatting || (format[col][row] < OVERWRITE)) { sprintf(s, "%*s", colwidth[col], ""); *color = BLANKCOLOR; } else { newcol = col; while (cell[--newcol][row] == NULL); p = cell[newcol][row]->v.text; while (newcol < col) p += colwidth[newcol++]; strncpy(temp, p, colwidth[col]); temp[colwidth[col]] = 0; sprintf(s, "%s%*s", temp, colwidth[col] - strlen(temp), ""); *color = TEXTCOLOR; } } else { formatvalue = format[col][row]; switch (cellptr->attrib) { case TEXT : textstring(cellptr->v.text, s, col, formatvalue, formatting); *color = TEXTCOLOR; break; case FORMULA : if (formdisplay) { textstring(cellptr->v.f.formula, s, col, formatvalue, formatting); *color = FORMULACOLOR; break; } else value = cellptr->v.f.fvalue; case VALUE : if (cellptr->attrib == VALUE) value = cellptr->v.value; valuestring(cellptr, value, s, col, formatvalue, color, formatting); break; } /* switch */ } return(s); } /* cellstring */ void writeprompt(char *prompt) /* Prints a prompt on the screen */ { writef(1, 24, PROMPTCOLOR, 80, prompt); } /* writeprompt */ void swap(int *val1, int *val2) /* Swaps the first and second values */ { int temp; temp = *val1; *val1 = *val2; *val2 = temp; } /* swap */ void checkforsave(void) /* If the spreadsheet has been changed, will ask the user if they want to save it. */ { int save; if (changed && getyesno(&save, MSGSAVESHEET) && (save == 'Y')) savesheet(); } /* checkforsave */ void initvars(void) /* Initializes various global variables */ { leftcol = toprow = curcol = currow = lastcol = lastrow = 0; setmem(colwidth, sizeof(colwidth), DEFAULTWIDTH); setmem(cell, sizeof(cell), 0); setmem(format, sizeof(format), DEFAULTFORMAT); } /* initvars */ int getcommand(char *msgstr, char *comstr) /* Reads in a command and acts on it */ { int ch, counter, len = strlen(msgstr); scroll(UP, 0, 1, 24, 80, 24, WHITE); for (counter = 0; counter < len; counter++) { if (isupper(msgstr[counter])) writef(counter + 1, 24, COMMANDCOLOR, 1, "%c", msgstr[counter]); else writef(counter + 1, 24, LOWCOMMANDCOLOR, 1, "%c", msgstr[counter]); } do ch = toupper(getkey()); while ((strchr(comstr, ch) == NULL) && (ch != ESC)); clearinput(); return((ch == ESC) ? -1 : strlen(comstr) - strlen(strchr(comstr, ch))); } /* getcommand */