kolibrios-gitea/programs/other/table/calc.cpp
Kirill Lipatov (Leency) 60e27afe74 table 0.99.3: fix several bugs
templates: upload to svn, add to ISO/res/templates


git-svn-id: svn://kolibrios.org@7544 a494cfbc-eb01-0410-851d-a64ba20cac60
2018-11-07 22:32:57 +00:00

1488 lines
31 KiB
C++

#include "func.h"
#include "parser.h"
#include "calc.h"
#include "kosSyst.h"
//#include "KosFile.h"
#define DEFAULT_CELL_W 82
#define DEFAULT_CELL_H 21
extern DWORD col_count, row_count;
extern char ***cells;
extern DWORD *cell_w, *cell_h;
extern char ***values;
extern DWORD *cell_x, *cell_y;
// áóôåð îáìåíà
extern char ***buffer;
extern DWORD buf_col, buf_row;
extern DWORD buf_old_x, buf_old_y;
extern bool sel_moved;
extern struct GRID
{
int x,y,w,h;
} grid;
int cf_x0, cf_x1, cf_y0, cf_y1;
#define sign(x) ((x) < 0 ? -1 : ((x) == 0 ? 0 : 1))
//extern const char er_file_not_found[];
//extern const char er_format[];
extern const char *sFileSign;
struct cell_list
{
int x,y;
cell_list *next;
};
// ïîëó÷èòü õ-êîîðäèíàòó ÿ÷åéêè ñ íîìåðîì õ
int get_x(int x)
{
int i, r = 0;
if (x > col_count)
x = col_count;
for (i = 0; i < x; i++)
r+=cell_w[i];
return r;
}
// àíàëîã
int get_y(int y)
{
int i, r = 0;
if (y > row_count)
y = row_count;
for (i = 0; i < y; i++)
r+=cell_h[i];
return r;
}
// ñãåíåðèòü çàãîëîâîê ñòîëáöà
char *make_col_cap(int i)
{
char *r = (char*)allocmem(3);
if (i <= 26)
{
r[0] = 'A' + i - 1;
r[1] = '\0';
return r;
}
else if (i % 26 == 0) // ôèêñ áàãà êîòîðûé íå ïîíÿë - äà ïðîñòÿò ìåíÿ ÷èòàòåëè è þçåðà
{
r[0] = (i / 26) - 1 + 'A' - 1;
r[1] = 'Z';
r[2] = '\0';
return r;
}
r[0] = (i / 26) + 'A' - 1;
r[1] = (i % 26) + 'A' - 1;
r[2] = '\0';
return r;
}
// -"- ñòðîêè
char *make_row_cap(int i)
{
char *r = (char*)allocmem(3);
if (i <= 9)
{
r[0] = '0' + i;
r[1] = '\0';
return r;
}
r[0] = (i / 10) + '0';
r[1] = (i % 10) + '0';
r[2] = '\0';
return r;
}
// èíèöèàëèçàöèÿ ÿ÷ååê
void init()
{
int i, j;
cell_w = (DWORD*)allocmem(col_count * sizeof(DWORD));
cell_h = (DWORD*)allocmem(row_count * sizeof(DWORD));
cell_x = (DWORD*)allocmem(col_count * sizeof(DWORD));
cell_y = (DWORD*)allocmem(row_count * sizeof(DWORD));
for (i = 0; i < col_count; i++)
{
cell_w[i] = DEFAULT_CELL_W;
}
cell_w[0] = 30; //make row headers smaller
for (i = 0; i < row_count; i++)
{
cell_h[i] = DEFAULT_CELL_H;
}
cells = (char***)allocmem(col_count * sizeof(char**));
values = (char***)allocmem(col_count * sizeof(char**));
for (i = 0; i < col_count; i++)
{
cells[i] = (char**)allocmem(row_count * sizeof(char*));
values[i] = (char**)allocmem(row_count * sizeof(char*));
for (j = 0; j < row_count; j++)
{
cells[i][j] = NULL;
if (i == 0 && j)
{
cells[i][j] = make_row_cap(j);
}
else if (j == 0 && i)
{
cells[i][j] = make_col_cap(i);
}
}
}
}
void reinit()
{
int i, j;
for (i = 0; i < col_count; i++)
{
cell_w[i] = DEFAULT_CELL_W;
}
cell_w[0] = 30; //make row headers smaller
for (i = 0; i < row_count; i++)
{
cell_h[i] = DEFAULT_CELL_H;
}
for (i = 1; i < col_count; i++)
{
for (j = 1; j < row_count; j++)
{
if (cells[i][j])
freemem(cells[i][j]);
cells[i][j] = NULL;
if (values[i][j])
freemem(values[i][j]);
values[i][j] = NULL;
}
}
}
void fill_cells(int sel_x, int sel_y, int sel_end_x, int sel_end_y, int old_end_x, int old_end_y)
{
// èòàê, (sel_x, sel_y) :: (old_end_x, old_end_y) - èñòî÷íèê
// ðåçóëüòàò õðàíèòñÿ ëèáî â ñòðîêå sel_x .. sel_end_x, ëèáî â ñòîëáöå sel_y .. sel_end_y
int i, start, end, step, gdir = -1;
int pdir = -1;
char *source;
cf_x0 = cf_y0 = 0;
cf_x1 = col_count;
cf_y1 = row_count;
if (sel_end_x == -1)
sel_end_x = sel_x;
if (sel_end_y == -1)
sel_end_y = sel_y;
// åñëè íàïðàâëåíèÿ âûäåëåíèé ïåðïåíäèêóëÿðíû, òî ïðîñòî â öèêëå ïîâòîðÿåì òî æå, ÷òî äëÿ 1 ÿ÷åéêè:
if (old_end_x == sel_end_x && sel_y == old_end_y)
{
gdir = 0;
}
else if (old_end_y == sel_end_y && sel_x == old_end_x)
{
gdir = 1;
}
//sprintf(debuf, "fuck in ass %U %U %U %U %U %U dir %U",sel_x,sel_y,sel_end_x,sel_end_y,old_end_x,old_end_y,gdir);
//rtlDebugOutString(debuf);
if (gdir != -1)
{
int gstep = gdir ? sign(old_end_y - sel_y) : sign(old_end_x - sel_x);
if (gstep == 0)
{
/* if (gdir)
{
//old_end_y += 1;
}
else
{
//old_end_x += 1;
}
*/
gstep = 1;
}
for (;gdir ? (sel_y != old_end_y + gstep) : (sel_x != old_end_x + gstep);
gdir ? (sel_y += gstep) : (sel_x += gstep))
{
//sprintf(debuf, "cycle %U %U %U %U %U %U dir %U",sel_x,sel_y,sel_end_x,sel_end_y,old_end_x,old_end_y,gdir);
//rtlDebugOutString(debuf);
int dir;
source = cells[sel_x][sel_y];
if (gdir == 0)
{
start = sel_y;
end = sel_end_y;
step = (sel_y < sel_end_y ? 1 : -1);
dir = 1;
}
else
{
start = sel_x;
end = sel_end_x;
step = (sel_x < sel_end_x ? 1 : -1);
dir = 0;
}
//sprintf(debuf, "cyc %U %U %U %U",start,end,step,dir);
//rtlDebugOutString(debuf);
for (i = start + step; i != end + step; i += step)
{
//char **p = &cells[dir ? sel_x : i][dir ? i : sel_end_y];
//sprintf(debuf, "to %U %U dir %U copying '%S'",dir ? sel_x : i,dir ? i : sel_y,dir,source);
//rtlDebugOutString(debuf);
if (cells[dir ? sel_x : i][dir ? i : sel_y])
{
freemem(cells[dir ? sel_x : i][dir ? i : sel_y]);
}
if (source)
{
cells[dir ? sel_x : i][dir ? i : sel_y] = change_formula(source, dir ? 0 : (i - start), dir ? (i - start) : 0);
//cells[dir ? sel_x : i][dir ? i : sel_y] = (char *)allocmem(strlen(source) + 1);
//strcpy(cells[dir ? sel_x : i][dir ? i : sel_y], source);
}
else
cells[dir ? sel_x : i][dir ? i : sel_y] = NULL;
}
}
}
// à âîò åñëè ïàðàëëåëüíû...
/*
if (sel_x == sel_end_x && sel_x == old_end_x)
{
pdir = 0;
}
if (sel_y == sel_end_y && sel_y == old_end_y)
{
pdir = 1;
}
if (pdir != -1)
{
// àðèôìåòè÷åñêàÿ ïðîãðåññèÿ - åñëè ÷èñëà. è òóïî ðàçìíîæèòüò ïîñëåäíåå, åñëè íåò
sprintf(debuf, "maybe arith dir %U", pdir);
rtlDebugOutString(debuf);
int is_arith = 1;
int gstep = pdir ? sign(old_end_y - sel_y) : sign(old_end_x - sel_x);
if (gstep == 0)
gstep = 1;
for (int i = pdir ? sel_y : sel_x; i != pdir ? (old_end_y + gstep) : (old_end_x + gstep); i++)
{
convert_error = 0;
sprintf(debuf,"cell %U %U", !pdir ? sel_x : i, !pdir ? i : sel_y);
rtlDebugOutString(debuf);
if (cells[!pdir ? sel_x : i][!pdir ? i : sel_y])
{
double d = atof(cells[!pdir ? sel_x : i][!pdir ? i : sel_y]);
if (convert_error)
{
rtlDebugOutString("failed arith");
is_arith = 0;
break;
}
}
else
{
is_arith = 0;
rtlDebugOutString("failed arith in null");
break;
}
}
double arith_first, arith_step;
if (is_arith)
{
rtlDebugOutString("really arith");
arith_first = atof(cells[sel_x][sel_y]);
arith_step = atof(cells[pdir ? sel_x : old_end_x][pdir ? sel_y : old_end_y]) - arith_first;
arith_first += arith_step * pdir ? abs(sel_end_x - old_end_x) : abs(sel_end_y - old_end_y);
}
else
rtlDebugOutString("none arith");
// ñîáñòâåííî çàïîëíåíèå
for (i = pdir ? old_end_y : old_end_x; i != pdir ? (sel_end_y + gstep) : (sel_end_x + gstep); i++)
{
if (cells[pdir ? sel_x : i][pdir ? i : sel_y])
freemem(cells[pdir ? sel_x : i][pdir ? i : sel_y]);
if (is_arith)
{
cells[pdir ? sel_x : i][pdir ? i : sel_y] = ftoa(arith_first);
arith_first += arith_step;
}
else
{
if (cells[sel_x][sel_y])
{
cells[pdir ? sel_x : i][pdir ? i : sel_y] = (char*)allocmem(strlen(cells[sel_x][sel_y]) + 1);
strcpy(cells[pdir ? sel_x : i][pdir ? i : sel_y], cells[sel_x][sel_y]);
}
}
}
}
*/
calculate_values();
}
int Kos_FileWrite(kosFileInfo &fileInfo, char *line, int mode = 3) // åñëè mode = 2 - ïåðåçàïèñàòü ôàéë
{
int res = 0;
fileInfo.dataCount = strlen(line);
fileInfo.bufferPtr = (Byte*)line;
fileInfo.rwMode = mode;
res = kos_FileSystemAccess(&fileInfo);
if (res != 0)
return 0;
fileInfo.OffsetLow += fileInfo.dataCount;
return 1;
}
int SaveCSV(char *fname)
{
int i, j;
int min_col = col_count, min_row = row_count, max_row = -1, max_col = -1;
int first = 1;
kosFileInfo fileInfo;
memset((Byte*)&fileInfo, 0, sizeof(fileInfo));
strcpy(fileInfo.fileURL,fname);
fileInfo.OffsetLow = 0;
fileInfo.OffsetHigh = 0;
fileInfo.rwMode = 8; // delete
rtlDebugOutString("savecsv: old file deleted");
for (i = 1; i < col_count; i++)
{
for (j = 1; j < row_count; j++)
{
if (cells[i][j])
{
min_col = min(min_col, i);
min_row = min(min_row, j);
max_col = max(max_col, i);
max_row = max(max_row, j);
}
}
}
sprintf(debuf, "col %U %U row", min_col, max_col, min_row, max_row);
rtlDebugOutString(debuf);
for (j = min_row; j <= max_row; j++)
{
char buffer[1024]; // íå íàäî òàê äåëàòü
int buf_len = 0;
memset((Byte*)buffer, 0, 1024);
for (i = min_col; i <= max_col; i++)
{
char *cur = values[i][j] ? values[i][j] : cells[i][j];
if (cur)
{
buffer[buf_len++] = '\"';
for (int k = 0; k < strlen(cur); k++)
{
if (cur[k] == '\"')
buffer[buf_len++] = '\"'; // êàâû÷åê - ïî äâå
buffer[buf_len++] = cur[k];
}
buffer[buf_len++] = '\"';
}
buffer[buf_len++] = ',';
}
rtlDebugOutString(buffer);
// î÷åðåäíàÿ ñòðîêà òåïåðü â áóôåðå
buffer[buf_len++] = '\n';
if (!Kos_FileWrite(fileInfo, buffer, first ? (first = 0, 2) : 3))
return 0;
}
return 1;
}
int str_is_csv(char *str)
{
int str_len = strlen(str);
if (str_len >= 5) {
if ( strnicmp(str + str_len - 4, ".CSV", 4) == 0) return 1;
}
return 0;
}
#define BUF_FOR_ALL 5000
int SaveFile(char *fname)
{
kosFileInfo fileInfo;
char *buffer = (char*)allocmem(BUF_FOR_ALL); // óæàñ! íî ïîêà ÷òî äîñòàòî÷íî
int filePointer = 0;
int i,j;
Dword res;
if (str_is_csv(fname))
return SaveCSV(fname);
//rtlDebugOutString(fname);
memset((Byte*)&fileInfo, 0, sizeof(fileInfo));
strcpy(fileInfo.fileURL,fname);
fileInfo.OffsetLow = 0;
fileInfo.OffsetHigh = 0;
fileInfo.rwMode = 8;
res = kos_FileSystemAccess(&fileInfo); // óäàëèòü
fileInfo.dataCount = strlen(sFileSign);
fileInfo.bufferPtr = (Byte*)sFileSign;
fileInfo.rwMode = 2;
res = kos_FileSystemAccess(&fileInfo);
if (res != 0)
return 0;
//sprintf(debuf, "create %U",res);
//rtlDebugOutString(debuf);
fileInfo.OffsetLow += fileInfo.dataCount;
// øèðèíó ñòîëáöîâ ñîõðàíÿåì
memset((Byte*)buffer,0,BUF_FOR_ALL);
for (i = 1; i < col_count; i++)
{
char smalbuf[32];
memset((Byte*)smalbuf,0,32);
sprintf(smalbuf, "%U,", cell_w[i]);
strcpy(buffer+strlen(buffer),smalbuf);
}
buffer[strlen(buffer)-1] = '\n'; // çàìåíèëè ïîñëåäíþþ çàïÿòóþ íà ïåðåâîä ñòðîêè
//rtlDebugOutString(buffer);
fileInfo.dataCount = strlen(buffer);
fileInfo.bufferPtr = (Byte*)buffer;
fileInfo.rwMode = 3;
res = kos_FileSystemAccess(&fileInfo);
if (res != 0)
return 0;
// ïåðåìîòàòü çàáûë ÿ ýòîò ôàéë
// íî óæ òåïåðü íå ïîïàäóñü íà ýòî!
fileInfo.OffsetLow += fileInfo.dataCount;
// âûñîòó ñòðîê ñîõðàíÿåì â ôàéëå ìû
memset((Byte*)buffer,0,BUF_FOR_ALL);
for (i = 1; i < row_count; i++)
{
char smalbuf[32];
memset((Byte*)smalbuf,0,32);
sprintf(smalbuf, "%U,", cell_h[i]);
strcpy(buffer+strlen(buffer),smalbuf);
}
buffer[strlen(buffer)-1] = '\n'; // çàìåíèëè ïîñëåäíþþ çàïÿòóþ íà ïåðåâîä ñòðîêè
//rtlDebugOutString(buffer);
fileInfo.dataCount = strlen(buffer);
fileInfo.bufferPtr = (Byte*)buffer;
fileInfo.rwMode = 3;
res = kos_FileSystemAccess(&fileInfo);
if (res != 0)
return 0;
// è âíîâü ïåðåìîòàþ ÿ ñåé ôàéë
fileInfo.OffsetLow += fileInfo.dataCount;
memset((Byte*)buffer,0,BUF_FOR_ALL);
// ñîõðàíèëè ïàðàìåòðû ÿ÷ååê ìû, ñîõðàíÿåì ñîäåðæèìîå èõ òåïåðü
for (i = 1; i < row_count; i++)
{
for (j = 1; j < col_count; j++)
if (cells[j][i])
{
memset((Byte*)buffer,0,512);
sprintf(buffer, "%U %U:%S\n", j, i, cells[j][i]);
fileInfo.dataCount = strlen(buffer);
fileInfo.bufferPtr = (Byte*)buffer;
fileInfo.rwMode = 3;
res = kos_FileSystemAccess(&fileInfo);
if (res != 0)
return 0;
//sprintf(debuf, "create %U",res);
//rtlDebugOutString(debuf);
fileInfo.OffsetLow += fileInfo.dataCount;
}
}
//rtlDebugOutString("saving finished");
freemem(buffer);
return 1;
}
char *Kos_FileRead(kosFileInfo &fileInfo, int &code)
{
char buffer[512], *p, *r;
fileInfo.dataCount = 512;
fileInfo.rwMode = 0;
fileInfo.bufferPtr = (Byte *)buffer;
memset((Byte*)buffer, 0, 512);
int z = kos_FileSystemAccess(&fileInfo);
code = z;
//sprintf(debuf, "kos file read %U", code);
//rtlDebugOutString(debuf);
if (z != 0 && z != 6)
return NULL;
p = buffer;
while (*p && *p++ != '\n');
if (p == buffer)
return NULL;
r = (char*)allocmem(p - buffer);
memset((Byte*)r, 0, p - buffer);
//strncpy(r, buffer, p - buffer);
for (int l = 0; l < p - buffer - 1; l++)
r[l] = buffer[l];
fileInfo.OffsetLow += p - buffer;
return r;
}
char GetCsvSeparator(char *fname)
{
char buffer[512];
kosFileInfo fileInfo;
rtlDebugOutString(fname);
strcpy(fileInfo.fileURL, fname);
fileInfo.OffsetLow = 0;
fileInfo.OffsetHigh = 0;
fileInfo.dataCount = 512;
fileInfo.rwMode = 0;
fileInfo.bufferPtr = (Byte *)buffer;
if (kos_FileSystemAccess(&fileInfo) == 0) {
int separ_coma = chrnum(buffer, ',');
int separ_semicolon = chrnum(buffer, ';');
//kos_DebugValue(",", separ_coma);
//kos_DebugValue(";", separ_semicolon);
if (separ_semicolon>separ_coma) return ';';
}
return ',';
}
int LoadCSV(char *fname)
{
// clear the table
reinit();
kosFileInfo fileInfo;
strcpy(fileInfo.fileURL,fname);
fileInfo.OffsetLow = 0;
fileInfo.OffsetHigh = 0;
char separator = GetCsvSeparator(fileInfo.fileURL);
char *line;
int col = 1, row = 1;
int code = 0;
do
{
line = Kos_FileRead(fileInfo, code);
if (!line || *line == '\0' || (code != 0 && code != 6))
{
sprintf(debuf, "read end, line not null = %U, code = %U", !line, code);
rtlDebugOutString(debuf);
break;
}
sprintf(debuf, "read '%S' len %U", line, strlen(line));
rtlDebugOutString(debuf);
// ðàçáîðàòü ñòðîêó
// âûäåëèòü ;, ïðè÷åì âíå "
int i = 0;
while (i <= strlen(line))
{
int inPar = 0;
// inPar: 0 - íå êàâû÷êè, 1 - òîëüêî ÷òî áûëà êàâû÷êà, 2 - êàâû÷êà áûëà, íî äàâíî
int start = i;
while (i <= strlen(line))
{
char c = line[i];
if (!c)
c = separator;
int yes_semicolon = 0;
switch (inPar)
{
case 0:
if (c == '\"')
{
inPar = 1;
}
else
{
if (c == separator)
yes_semicolon = 1;
}
break;
case 1:
inPar = 2;
break;
case 2:
if (c == '\"') // îíà çàêðûëàñü
{
inPar = 0;
}
/*else
{
if (c == separator)
yes_semicolon = 1;
}*/
break;
}
if (yes_semicolon)
{
// èòàê, line[i] = separator
int tmp = line[start] == '"' ? 1 : 0;
int sz = i - start - tmp * 2;
if (sz > 0)
{
cells[col][row] = (char *)allocmem(sz + 1);
memset((Byte*)cells[col][row], 0, sz + 1);
int m = 0;
for (int l = 0; l < sz; l++)
{
if (line[start + tmp + l] == '\"')
{
cells[col][row][m++] = '\"';
l++; // ïðîïóñòèòü ñëåäóþùóþ êàâû÷êó
}
else
cells[col][row][m++] = line[start + tmp + l];
}
sprintf(debuf, "set %U %U = '%S'", col, row, cells[col][row]);
rtlDebugOutString(debuf);
}
start = i + 1;
col++;
}
i++;
}
row++;
col = 1;
i++;
}
} while(line);
return 1;
}
int LoadFile(char *fname)
{
kosFileInfo fileInfo;
kosBDVK bdvk;
int filePointer = 0, i, j;
Dword res, filesize;
char buffer[512 + 1];
char *d, *s, *k;
int step = 0, items;
strcpy(fileInfo.fileURL,fname);
fileInfo.OffsetLow = 0;
fileInfo.OffsetHigh = 0;
fileInfo.rwMode = 5;
fileInfo.bufferPtr = (Byte *)&bdvk;
Dword rr = kos_FileSystemAccess(&fileInfo); // â CKosFile íåò îïðåäåëåíèÿ ðàçìåðà
//sprintf(debuf, "getsize: %U\n", rr);
//rtlDebugOutString(debuf);
if (rr != 0)
{
return -1;
}
if (str_is_csv(fname))
return LoadCSV(fname);
// clear the table
reinit();
filesize = bdvk.size_low;
fileInfo.rwMode = 0;
fileInfo.dataCount = strlen(sFileSign);
fileInfo.bufferPtr = (Byte*)buffer;
kos_FileSystemAccess(&fileInfo);
s = (char*)sFileSign;
d = buffer;
while (*s && *d && *s++==*d++); // çàñòðåëèòå ìåíÿ
if (*s != '\0' || *d != '\0')
{
return -2;
}
fileInfo.OffsetLow += fileInfo.dataCount;
items = 1;
while (fileInfo.OffsetLow < filesize)
{
// òàê ïðî÷èòàëè ëè ìû øèðèíó âñåõ ñòîáëöîâ, è äëèíó âñåõ ñòðîê ïðî÷èòàëè ëè ìû?
fileInfo.dataCount = 512;
memset((Byte*)buffer, 0, 512);
kos_FileSystemAccess(&fileInfo);
//sprintf(debuf, "%U", fileInfo.OffsetLow);
//rtlDebugOutString(debuf);
//sprintf(debuf, "buffer: %S", buffer);
//rtlDebugOutString(debuf);
// ÷òî ÿ óâèæó íà äîñêå îòëàäêè
// òî ìíå ïîìîæåò â æèçíåííîì ïóòè
// ñìîãó òîãäà ñâîåé îøèáêè ãàäêîé
// ïðè÷èíó íåïîñðåäñòâåííî íàéòè
switch (step)
{
case 0: // ñòîáëöû
d = buffer;
while (*d && *d != ',' && *d != '\n') d++;
//d--;
if (!*d)
{
return -2;
}
*d = '\0';
i = atoi(buffer);
cell_w[items++] = i;
if (items == col_count)
{
step++;
items = 1; // òåïåðü âûñîòû ñòðîê ÷èòàòü ìû áóäåì ñìåëî
// ÷òîá èõ âîññòàíîâèòü è áûëî êàê âñåãäà
//sprintf(debuf, "col_count read done last buf %S file pos %U",buffer,fileInfo.OffsetLow);
//rtlDebugOutString(debuf);
}
d+=2;
break;
case 1: // ñòðîêè, êîèõ âûñîòà çàïèñàíà
d = buffer;
while (*d && *d != ',' && *d != '\n') d++;
//d--;
if (!*d)
{
//sprintf(debuf,"oh shit, error at %U",items);
//rtlDebugOutString(debuf);
return -2;
}
*d = '\0';
i = atoi(buffer);
cell_h[items++] = i;
/*if (items > 5)
{
sprintf(debuf, "set row from %S hei %U %U",buffer,items-1,i);
rtlDebugOutString(debuf);
}*/
if (items == row_count)
{
step++; // à äàëåå ëåæàò ÿ÷åéêè â ôàéëå
// çàïèñàíû îíè â êðèâîì ôîðìàòå
// èáî ïèñàë ñåé êîä ÿ òåìíîé íî÷üþ
// íî íå êóðèë òðàâû, êëÿíóñü ÿ âàì
// èíà÷å áû è ýòîãî íå ñêîäèë
// äåáàæèòü ñåé ìíå êîä ïðåìíîãî âïàäëó
// íî ïîìíþ ïðàâèëî - êîëü íàïèñàë äåáàæü
// íåìåäëåííî - à òî íàõ âñå çàáóäåøü.
// âîò âûïüþ - à òàì ñðàçó çà îòëàäêó.
//sprintf(debuf, "before read cells offset %U %X",fileInfo.OffsetLow,fileInfo.OffsetLow);
//rtlDebugOutString(debuf);
}
d+=2;
break;
// î, áðÿêè ÿ çàáûë çàáèòü. î óæàñ.
// ïîçîð ìíå, íà êîñòðå ìåíÿ ñîæãèòå
// âåäü òîò, êòî break íå ñòàâèò ïîñëå casa
// ïîäîáåí ëàìåðó, ÷òî ñè íå çíàåò
// ñìîãó ëè ÿ òàêîå ïåðåæèòü?
case 2: // ÿ÷åéêè, èáî èõ ñîäåðæèìîå ñîõðàíåíî çäåñü îò èñ÷åçíîâåíèÿ
d = buffer;
while (*d && *d++ != ' '); // îóææàñ. çà÷åì òîëüêî ÿ ïèñàë ýòîò áðåä....
d--;
if (!*d)
{
return -2;
}
*d = '\0';
i = atoi(buffer);
d++;
s=d;
while (*d && *d++ != ':'); // êîãäà-òî ÿ óäèâëÿëñÿ, êàê ëþäè ìîãóò òàêóþ õåðíþ ïèñàòü... äîæèë
d--;
if (!*d)
{
return -2;
}
*d = '\0';
j = atoi(s);
//rtlDebugOutString(s);
d++;
k = d;
while (*d && *d++ != '\n');
d--;
*d = '\0';
d+=2;
//sprintf(debuf, "i:%U j:%U d:%S\n",i,j,k);
//rtlDebugOutString(debuf);
cells[i][j] = (char*)allocmem(strlen(k) + 1);
//memset(cells[i][j], 0, strlen(k) + 1);
strcpy(cells[i][j], k);
//sprintf(debuf, "offset: %U", fileInfo.OffsetLow);
//rtlDebugOutString(debuf);
}
fileInfo.OffsetLow += d - (char*)buffer - 1;
}
//rtlDebugOutString("loading finished");
return 1;
}
// î÷èñòèòü áóôåð îáìåíà
void freeBuffer()
{
int i, j;
if (!buffer)
return;
for (i = 0; i < buf_col; i++)
{
for (j = 0; j < buf_row; j++)
if (buffer[i][j])
freemem(buffer[i][j]);
freemem(buffer[i]);
}
freemem(buffer);
buffer = NULL;
buf_row = buf_col = 0;
}
// äàëåå - âû÷èñëåíèå ïî ôîðìóëàì
int abort_calc = 0;
cell_list *last_dep;
// ïïö, ãäå òî áàã, à ýòî òèïà ôèêñ
//#define allocmem2(x) allocmem(x+1000)
double calc_callback(char *str)
{
int i,j,x,y;
if (abort_calc == 1)
return 0.0;
//rtlDebugOutString(str);
if (*str == '$') str++;
for (i = 0; i < strlen(str); i++)
if (str[i] >= '0' && str[i] <= '9')
break;
if (str[i-1] == '$')
i--;
if (i == strlen(str))
{
abort_calc = 1;
serror(ERR_BADVARIABLE);
return 0.0;
}
x = -1;
for (j = 0; j < col_count; j++)
// if (strnicmp(str,cells[j][0],i-1)==0)
if (str[0] == cells[j][0][0] && ((i == 1) || (str[1] == cells[j][0][1])))
{
x = j;
break;
}
if (str[i] == '$')
i++;
y = -1;
for (j = 0; j < row_count; j++)
if (strcmp(str+i,cells[0][j])==0)
{
y = j;
break;
}
if (x == -1 || y == -1)
{
abort_calc = 1;
serror(ERR_BADVARIABLE);
return 0.0;
}
double hold;
if (values[x][y])
if (values[x][y][0] == '#')
{
serror(ERR_BADVARIABLE);
abort_calc = 1;
}
else
{
hold = atof(values[x][y]);
//if (convert_error) // íåðåàëüíûé ñëó÷àé...
//{
// serror(ERR_BADVARIABLE);
// abort_calc = 1;
//}
}
else
{
if (cells[x][y])
{
hold = atof(cells[x][y]);
if (convert_error == ERROR || convert_error == ERROR_END)
{
serror(ERR_BADVARIABLE);
abort_calc = 1;
}
}
else
{
sprintf(debuf, "bad var %S", str);
rtlDebugOutString(debuf);
serror(ERR_BADVARIABLE);
abort_calc = 1;
}
}
return hold;
}
double depend_callback(char *str)
{
cell_list *cur;
// íàäî âûäðàòü èç ÀÂ47 çíà÷åíèÿ õ è ó.
int i,j,x,y;
if (abort_calc == 1)
return 0.0;
if (*str == '$') str++;
for (i = 0; i < strlen(str); i++)
if (str[i] >= '0' && str[i] <= '9')
break;
if (str[i-1] == '$')
i--;
if (i == strlen(str))
{
abort_calc = 1;
serror(ERR_BADVARIABLE);
return 0.0;
}
x = -1;
for (j = 1; j < col_count; j++)
//if (strncmp(str,cells[j][0],i)==0)
if (str[0] == cells[j][0][0] && ((i == 1) || (str[1] == cells[j][0][1])))
{
x = j;
break;
}
if (str[i] == '$')
i++;
y = -1;
for (j = 1; j < row_count; j++)
if (strcmp(str+i,cells[0][j])==0)
{
y = j;
break;
}
if (x == -1 || y == -1)
{
abort_calc = 1;
serror(ERR_BADVARIABLE);
return 0.0;
}
cur = (cell_list*)allocmem(sizeof(cell_list));
cur->x = x;
cur->y = y;
cur->next = last_dep;
last_dep = cur;
return 0.0;
}
cell_list *find_depend(char *str)
{
double hold;
last_dep = NULL;
find_var = &depend_callback;
set_exp(str);
get_exp(&hold);
return last_dep;
}
bool is_in_list(cell_list *c1, cell_list *c2)
{
cell_list *p = c2;
while (p)
{
if (c1->x == p->x && c1->y == p->y)
return 1;
p = p->next;
}
return 0;
}
void calculate_values()
{
cell_list ***depend = NULL;
cell_list *first = NULL;
cell_list *sorted = NULL, *sorted_last = NULL;
cell_list *p = NULL;
int i,j;
//rtlDebugOutString("calc");
abort_calc = 0;
depend = (cell_list***)allocmem(col_count * sizeof(void*));
for (i = 0; i < col_count; i++)
{
depend[i] = (cell_list**)allocmem(row_count * sizeof(void*));
for (j = 0; j < row_count; j++)
{
if (values[i][j])
freemem(values[i][j]);
values[i][j] = NULL;
if (cells[i][j] && cells[i][j][0] == '=')
{
depend[i][j] = find_depend(cells[i][j] + 1); // ïîñëå =
if (abort_calc)
{
values[i][j] = (char*)allocmem(2);
values[i][j][0] = '#';
values[i][j][1] = '\0';
abort_calc = 0;
continue;
}
cell_list *cur;
cur = (cell_list*)allocmem(sizeof(cell_list));
cur->x = i;
cur->y = j;
cur->next = first; // âñòàâèëè òåê. ÿ÷åéêó â íà÷àëî ñïèñêà ÿ÷ååê ñ ôîðìóëàìè
first = cur;
}
}
}
//rtlDebugOutString("depend end");
// òîïîëîãè÷åñêàÿ ñîðòèðîâêà
if (!first)
goto free_memory;
if (abort_calc)
goto free_memory;
while (first)
{
// íàéòè íàèìåíüøèé ýëåìåíò. åñëè åãî íåò - îøèáêà, ò.ê. öèêëè÷åñêàÿ çàâèñèìîñòü
cell_list *prev = NULL,*min = first;
bool is_min;
while (min)
{
cell_list *p = first;
is_min = 1;
while (p && is_min)
{
if (is_in_list(p,depend[min->x][min->y]))
is_min = 0;
p = p->next;
}
if (is_min)
break;
prev = min;
min = min->next;
}
if (!is_min)
{
abort_calc = 1;
goto free_memory; // âñå ïëîõî. óæàñíî. ÿ ïëàêàþ, íî ïèøó goto
}
// íàäî óáðàòü ìèíèìóì âî âòîðîé ñïèñîê
if (prev == NULL)
{
first = first->next;
}
else
{
prev->next = min->next;
}
/*
min->next = sorted;
sorted = min;
*/
if (sorted == NULL)
{
sorted = min;
sorted_last = min;
}
else
{
sorted_last->next = min;
sorted_last = min;
min->next = NULL;
}
}
// âû÷èñëåíèå çíà÷åíèé
//rtlDebugOutString("sort end");
p = sorted;
while (p)
{
double d;
abort_calc = 0;
set_exp(cells[p->x][p->y]+1); // âñå ÷òî ïîñëå "="
find_var = &calc_callback;
if (get_exp(&d))
{
char *new_val = ftoa(d);
if (values[p->x][p->y] && strcmp(values[p->x][p->y],new_val) == 0)
{
freemem(new_val);
}
else
{
if (values[p->x][p->y])
freemem(values[p->x][p->y]);
values[p->x][p->y] = new_val;
sel_moved = 0;
}
//sprintf(debuf,"calc %U %U formula %S result %f",p->x,p->y,cells[p->x][p->y]+1,d);
//rtlDebugOutString(debuf);
}
else
{
values[p->x][p->y] = (char*)allocmem(2);
values[p->x][p->y][0] = '#';
values[p->x][p->y][1] = '\0';
//sprintf(debuf,"calc %U %U formula %S result #",p->x,p->y,cells[p->x][p->y]+1);
//rtlDebugOutString(debuf);
}
p = p->next;
}
if (abort_calc)
goto free_memory;
//rtlDebugOutString("calc end");
// îñâîáîæäåíèå ïàìÿòè
free_memory:
p = sorted;
while (p)
{
cell_list *tmp = p->next;
cell_list *pp = depend[p->x][p->y];
while (pp)
{
cell_list *tmp = pp->next;
freemem(pp);
pp = tmp;
}
freemem(p);
p = tmp;
}
for (i = 0; i < col_count; i++)
freemem(depend[i]);
freemem(depend);
//rtlDebugOutString("freemem end");
}
int parse_cell_name(char *str, int *px, int *py, int *xd, int *yd)
{
// íàäî âûäðàòü èç ÀÂ47 çíà÷åíèÿ õ è ó.
int i,j,x,y,dx = 0,dy = 0;
if (*str == '$')
{
str++;
dx = 1;
}
for (i = 0; i < strlen(str); i++)
if (str[i] >= '0' && str[i] <= '9')
break;
if (str[i-1] == '$')
{
i--;
dy = 1;
}
if (i == strlen(str))
{
return 0;
}
x = -1;
for (j = 1; j < col_count; j++)
if (strncmp(str,cells[j][0],i)==0)
{
/*int p = 0, z = 1;
for (p = 0; p < i; p++)
if (!str[p] || str[p] != cells[j][0][p])
{
z = 0;
break;
}
if (z)
*/
{
x = j;
break;
}
}
if (str[i] == '$')
i++;
y = -1;
for (j = 1; j < row_count; j++)
if (strcmp(str+i,cells[0][j])==0)
{
/*
int p = 0, z = 1;
for (p = 0;; p++)
{
if (str[i + p] != cells[0][j][p])
{
z = 0;
break;
}
if (cells[0][j][p] == '\0')
break;
}
if (z)
*/
{
y = j;
break;
}
}
if (x == -1 || y == -1)
{
return 0;
}
*px = x;
*py = y;
if (xd)
*xd = dx;
if (yd)
*yd = dy;
return 1;
}
char *make_cell_name(int x, int y, int xd, int yd)
{
char *col_cap = make_col_cap(x);
char *row_cap = make_row_cap(y);
if (x <= 0 || x > col_count || y <= 0 || y > row_count)
return NULL;
char *res = (char*)allocmem(strlen(col_cap) + strlen(row_cap) + xd ? 1 : 0 + yd ? 1 : 0 + 1);
int i = 0;
if (xd)
{
res[i] = '$';
i++;
}
strcpy(res + i, col_cap);
i += strlen(col_cap);
if (yd)
{
res[i] = '$';
i++;
}
strcpy(res + i, row_cap);
i += strlen(row_cap);
res[i] = '\0';
freemem(col_cap);
freemem(row_cap);
return res;
}
// çàìåíû ññûëêè íà îäíó ÿ÷åéêó
char *change_cell_ref(char *name, int sx, int sy)
{
int x0, y0, xd, yd;
parse_cell_name(name, &x0, &y0, &xd, &yd);
//sprintf(debuf, "parsed cell name %S to %U %U", name, x0, y0);
//rtlDebugOutString(debuf);
// ó íàñ åñòü õ0 è ó0.
//sprintf(debuf, "%U in %U %U, %U in %U %U",x0, cf_x0, cf_x1, y0, cf_y0, cf_y1);
//rtlDebugOutString(debuf);
if (x0 >= cf_x0 && x0 <= cf_x1 && y0 >= cf_y0 && y0 <= cf_y1)
{
if (!xd)
{
x0 += sx;
if (x0 <= 0 || x0 > col_count)
x0 -= sx;
}
if (!yd)
{
y0 += sy;
if (y0 <= 0 || y0 > row_count)
y0 -= sy;
}
}
return make_cell_name(x0, y0, xd, yd);
}
// çàìåíà âñåõ ññûëîê íà ÿ÷åéêè
char *change_formula(char *name, int sx, int sy)
{
int i = 0;
int in_name = 0; // 1 - ÷èòàåì áóêâåííóþ ÷àñòü. 2 - ÷èòàåì öèôðîâóþ. 0 - ÷èòàåì ðàçäåëèòåëè è ò.ä.
int alp_len = 0, dig_len = 0;
int buf_i = 0;
char buffer[256]; // î÷åíü ïëîõî
memset((Byte*)buffer, 0, 256);
//sprintf(debuf, "change formula %S by %U %U", name, sx, sy);
//rtlDebugOutString(debuf);
while (i < strlen(name) + 1)
{
char c;
if (i == strlen(name))
c = ' ';
else
c = name[i];
buffer[buf_i++] = c;
switch (in_name)
{
case 0:
{
if (isalpha2(c) || c == '$')
{
in_name = 1;
alp_len = 1;
dig_len = 0;
}
}
break;
case 1:
{
if (isalpha2(c))
{
alp_len++;
}
else if (c == '$' || isdigit(c))
{
in_name = 2;
dig_len++;
}
else
{
// íåçàâåðøåííîå èìÿ ÿ÷åéêè - íå èìÿ
in_name = 0;
alp_len = dig_len = 0;
}
}
break;
case 2:
{
if (isdigit(c))
{
dig_len++;
}
else
{
if (alp_len > 0 && dig_len > 0)
{
// âîò íîðìàëüíàÿ ÿ÷åéêà
int idx = i - alp_len - dig_len;
int len = alp_len + dig_len;
char *cell = (char*)allocmem(len + 1);
//strncpy(cell, name + i, alp_len + dig_len);
for (int l = 0; l < len; l++)
cell[l] = name[idx + l];
cell[len] = '\0';
//sprintf(debuf, "found cell name '%S' alp %U dig %U", cell, alp_len, dig_len);
//rtlDebugOutString(debuf);
char *cell_new = change_cell_ref(cell, sx, sy);
//sprintf(debuf, "rename to '%S'", cell_new);
//rtlDebugOutString(debuf);
if (cell_new)
{
char cc = buffer[buf_i - 1];
strcpy(buffer + buf_i - len - 1, cell_new);
buf_i += strlen(cell_new) - len;
buffer[buf_i - 1] = cc;
}
//freemem(cell);
//freemem(cell_new);
alp_len = dig_len = 0;
in_name = 0;
}
}
}
}
i++;
}
//sprintf(debuf, "change formula done");
//rtlDebugOutString(debuf);
char *res = (char*)allocmem(strlen(buffer) + 1);
strcpy(res, buffer);
return res;
}