Move source code into subdirectory

Also removed a stray copy of the automatically generated config.h which
  had somehow gotten into the distribution. Closes #36.
This commit is contained in:
Glen Whitney 2019-07-27 01:35:44 -04:00
parent 255bd86bf5
commit ea230efc23
41 changed files with 68 additions and 70 deletions

60
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,60 @@
add_subdirectory(common)
include_directories("${Teapot_SOURCE_DIR}/src")
include_directories("${Teapot_SOURCE_DIR}/src/common")
find_library(LIB_PORTABLEXDR portablexdr)
if (NOT LIB_PORTABLEXDR)
find_library(LIB_TIRPC tirpc)
if (LIB_TIRPC)
set(LIB_PORTABLEXDR ${LIB_TIRPC})
else ()
set(LIB_PORTABLEXDR "")
endif ()
endif ()
find_package(Curses)
if (CURSES_FOUND AND ENABLE_UTF8)
find_library(LIB_CURSESW ncursesw)
if (NOT LIB_CURSESW)
find_library(LIB_CURSESW ncursesw5)
endif ()
if (LIB_CURSESW)
set(teapot_DEB_DEPENDS ", libncursesw5 (>= 5.6+20071006-3)")
set(CURSES_CURSES_LIBRARY ${LIB_CURSESW})
else ()
set(ENABLE_UTF8 OFF)
set(teapot_DEB_DEPENDS ", libncurses5 (>= 5.6+20071006-3)")
endif ()
elseif (CURSES_FOUND)
set(teapot_DEB_DEPENDS ", libncurses5 (>= 5.6+20071006-3)")
endif ()
if (CURSES_FOUND)
include_directories("${CURSES_INCLUDE_DIR}")
add_executable(teapot display.c complete.c)
target_link_libraries(teapot teapotlib m ${CURSES_CURSES_LIBRARY} ${LIB_PORTABLEXDR})
install(TARGETS teapot DESTINATION bin)
endif ()
find_package(FLTK)
if (FLTK_FOUND)
fltk_wrap_ui(fteapot fteapot.fl)
add_executable(fteapot WIN32 ${fteapot_FLTK_UI_SRCS})
set(fteapot_DEB_DEPENDS ", libstdc++6 (>= 4.1.1), libfltk1.3")
if (ENABLE_HELP)
set(fteapot_DEB_DEPENDS "${fteapot_DEB_DEPENDS}, libfltk-images1.3")
if (ENABLE_STATIC)
target_link_libraries(fteapot teapotlib fltk fltk_images ${LIB_PORTABLEXDR})
else ()
target_link_libraries(fteapot teapotlib fltk fltk_images ${LIB_PORTABLEXDR})
endif ()
else ()
if (ENABLE_STATIC)
target_link_libraries(fteapot teapotlib fltk fltk_images ${LIB_PORTABLEXDR})
else ()
target_link_libraries(fteapot teapotlib fltk ${LIB_PORTABLEXDR})
endif ()
endif ()
install(TARGETS fteapot DESTINATION bin)
endif ()

View file

@ -0,0 +1,6 @@
include_directories("${Teapot_SOURCE_DIR}/src")
include_directories("${Teapot_SOURCE_DIR}/src/common")
link_directories("${Teapot_SOURCE_DIR}/src/common")
add_library(teapotlib context.c csv.c eval.c func.c htmlio.c latex.c main.c misc.c parser.c sc.c scanner.c sheet.c utf8.c wk1.c xdr.c)

147
src/common/context.c Normal file
View file

@ -0,0 +1,147 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "context.h"
#include "main.h"
#include "misc.h"
/*}}}*/
/* savecontext -- save as ConTeXt table */ /*{{{*/
const char *savecontext(Sheet *sheet, const char *name, int body,
const Location beg, const Location end,
unsigned int *count)
{
/* variables */ /*{{{*/
FILE *fp=(FILE*)0; /* cause runtime error */
Location w;
char buf[1024];
char num[20];
char fullname[PATH_MAX];
Cell *cell;
/*}}}*/
/* asserts */ /*{{{*/
assert(sheet != (Sheet*)0);
assert(name != (const char*)0);
/*}}}*/
*count=0;
w[X] = beg[X];
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
{
if (body)
/* open new file */ /*{{{*/
{
sprintf(num, ".%d", w[Z]);
fullname[sizeof(fullname)-strlen(num)-1]='\0';
(void)strncpy(fullname,name,sizeof(fullname)-strlen(num)-1);
fullname[sizeof(fullname)-1]='\0';
(void)strncat(fullname,num,sizeof(fullname)-strlen(num)-1);
fullname[sizeof(fullname)-1]='\0';
if ((fp=fopen(fullname,"w"))==(FILE*)0) return strerror(errno);
}
/*}}}*/
else
/* print header */ /*{{{*/
if (w[Z] == beg[Z])
{
if (fputs_close("\\starttext\n",fp)==EOF) return strerror(errno);
}
else
{
if (fputs_close("\\page\n",fp)==EOF) return strerror(errno);
}
/*}}}*/
/* print bogus format */ /*{{{*/
fprintf(fp,"\\starttable[");
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
if (fputs_close("|l",fp)==EOF) return strerror(errno);
fprintf(fp,"|]\n");
/*}}}*/
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
/* print contents */ /*{{{*/
{
for (w[X]=beg[X]; w[X]<=end[X]; )
{
int multicols;
char *bufp;
if (w[X] > beg[X] && fputs_close("\\NC",fp)==EOF) return strerror(errno);
for (multicols=w[X]+1; multicols<sheet->dimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols);
multicols=multicols-w[X];
if (multicols>1) fprintf(fp,"\\use{%d}",multicols);
cell = CELL_AT(sheet, w);
switch (getadjust(cell))
{
case LEFT: if (fputs_close("\\JustLeft ",fp)==EOF) return strerror(errno); break;
case RIGHT: if (fputs_close("\\JustRight ",fp)==EOF) return strerror(errno); break;
case CENTER: if (fputs_close("\\JustCenter ",fp)==EOF) return strerror(errno); break;
default: assert(0);
}
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell),
getprecision(cell), sheet, w);
/* if (fputs_close("}{",fp)==EOF) return strerror(errno);*/
if (transparent(cell))
{
if (fputs_close(buf,fp)==EOF) return strerror(errno);
}
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
{
case '%':
case '$':
case '&':
case '#':
case '_':
case '{':
case '}':
case '~':
case '^': if (fputc_close('\\',fp)==EOF || fputc_close(*bufp,fp)==EOF) return strerror(errno); break;
case '\\': if (fputs_close("\\backslash ",fp)==EOF) return strerror(errno); break;
default: if (fputc_close(*bufp,fp)==EOF) return strerror(errno);
}
/* if (fputc_close('}',fp)==EOF) return strerror(errno);*/
w[X] += multicols;
++*count;
}
if (fputs_close(w[Y]<end[Y] ? "\\MR\n" : "\n\\stoptable\n",fp)==EOF) return strerror(errno);
}
/*}}}*/
if (body)
{
if (fclose(fp)==EOF) return strerror(errno);
}
else
{
if (fputs_close("\n",fp)==EOF) return strerror(errno);
}
}
if (!body)
{
if (fputs_close("\\stoptext\n",fp)==EOF) return strerror(errno);
if (fclose(fp)==EOF) return strerror(errno);
}
return (const char*)0;
}
/*}}}*/

10
src/common/context.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef CONTEXT_H
#define CONTEXT_H
#include "sheet.h"
const char *savecontext(Sheet *sheet, const char *name, int body,
const Location beg, const Location end,
unsigned int *count);
#endif

160
src/common/csv.c Normal file
View file

@ -0,0 +1,160 @@
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef OLD_REALLOC
#define realloc(s,l) myrealloc(s,l)
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include "csv.h"
static int semicol=0;
/* csv_setopt -- set language */ /*{{{C}}}*//*{{{*/
void csv_setopt(int sem)
{
semicol=sem;
}
/*}}}*/
#if 0
/* csv_date -- convert string "year<sep>month<sep>day<sep>" to date */ /*{{{*/
static struct CSV_Date csv_date(const char *s, const char **end)
{
struct CSV_Date date;
assert(s!=(const char*)0);
assert(end!=(const char**)0);
*end=s;
if (*s=='"')
{
++s;
if (isdigit(*s))
{
for (date.year=0; isdigit(*s); date.year=10*date.year+(*s-'0'),++s);
if (*s)
{
++s;
if (isdigit(*s))
{
for (date.month=0; isdigit(*s); date.month=10*date.month+(*s-'0'),++s);
if (*s)
{
++s;
if (isdigit(*s))
{
for (date.day=0; isdigit(*s); date.day=10*date.day+(*s-'0'),++s);
if (*s=='"')
{
++s;
*end=s;
}
}
}
}
}
}
}
return date;
}
/*}}}*/
#endif
/* csv_separator -- convert string \t to nothing */ /*{{{*/
void csv_separator(const char *s, const char **end)
{
assert(s!=(const char*)0);
assert(end!=(const char**)0);
*end=s+(*s=='\t' || (semicol && *s==';') || (!semicol && *s==','));
}
/*}}}*/
/* csv_long -- convert string [0[x]]12345 to long */ /*{{{*/
long csv_long(const char *s, const char **end)
{
long value;
const char *t;
assert(s!=(const char*)0);
assert(end!=(const char**)0);
if (*s=='\t') { *end=s; return 0L; };
value=strtol(s,(char**)end,0);
if (s!=*end)
{
t=*end; csv_separator(t,end);
if (t!=*end || *t=='\0' || *t=='\n') return value;
}
*end=s; return 0L;
}
/*}}}*/
/* csv_double -- convert string 123.4e5 to double */ /*{{{*/
double csv_double(const char *s, const char **end)
{
double value;
const char *t;
assert(s!=(const char*)0);
assert(end!=(const char**)0);
if (*s=='\t') { *end=s; return 0.0; };
value=strtod(s,(char**)end);
if (s!=*end)
{
t=*end; csv_separator(t,end);
if (t!=*end || *t=='\0' || *t=='\n') return value;
}
*end=s; return 0.0;
}
/*}}}*/
/* csv_string -- convert almost any string to string */ /*{{{*/
char *csv_string(const char *s, const char **end)
{
static char *string;
static int strings,stringsz;
assert(s!=(const char*)0);
assert(end!=(const char**)0);
strings=0;
stringsz=0;
string=(char*)0;
if (!isprint((int)*s) || (!semicol && *s==',') || (semicol && *s==';')) return (char*)0;
if (*s=='"')
{
++s;
while (*s!='\0' && *s!='\n' && *s!='"')
{
if ((strings+2)>=stringsz)
{
string=realloc(string,stringsz+=32);
}
string[strings]=*s;
++strings;
++s;
}
if (*s=='"') ++s;
}
else
{
while (*s!='\0' && *s!='\n' && *s!='\t' && ((!semicol && *s!=',') || (semicol && *s!=';')))
{
if ((strings+2)>=stringsz)
{
string=realloc(string,stringsz+=32);
}
string[strings]=*s;
++strings;
++s;
}
}
string[strings]='\0';
*end=s;
csv_separator(s,end);
return string;
}
/*}}}*/

17
src/common/csv.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef CSV_H
#define CSV_H
struct CSV_Date
{
int day;
int month;
int year;
};
void csv_setopt(int sem);
void csv_separator(const char *s, const char **end);
char *csv_string(const char *s, const char **end);
double csv_double(const char *s, const char **end);
long csv_long(const char *s, const char **end);
#endif

38
src/common/default.h Normal file
View file

@ -0,0 +1,38 @@
#ifndef DEFAULT_H
#define DEFAULT_H
#include <stdlib.h>
/* default width of a column */
#define DEF_COLUMNWIDTH 12
/* default precision of a printed value */
#define DEF_PRECISION 2
/* default is no scientific notation for numbers */
#define DEF_SCIENTIFIC 0
/* character attribute for cell and row numbers */
#define DEF_NUMBER A_BOLD
/* character attribute for cell cursor */
#define DEF_CELLCURSOR A_REVERSE
/* character attribute for selected menu choice */
#define DEF_MENU A_REVERSE
/* maximum number of sort keys */
#define MAX_SORTKEYS 8
/* maximum number of eval() nesting */
#define MAX_EVALNEST 32
/* define if testing with EletricFence */
#ifdef THE_ELECTRIC_FENCE
#undef malloc
#undef free
#undef realloc
#undef calloc
#endif
#endif

1290
src/common/eval.c Normal file

File diff suppressed because it is too large Load diff

27
src/common/eval.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef THE_EVAL_H
#define THE_EVAL_H
#include "scanner.h"
Token tcopy(Token n);
void tfree(Token *n);
void tvecfreetoks(Token **tvec);
void tvecfree(Token **tvec);
size_t tveclen(Token **tvec);
Token tpow(Token l, Token r);
Token tdiv(Token l, Token r);
Token tmod(Token l, Token r);
Token tmul(Token l, Token r);
Token tadd(Token l, Token r);
Token tsub(Token l, Token r);
Token tneg(Token x);
Token tfuncall(Token *ident, int argc, Token argv[]);
Token tlt(Token l, Token r);
Token tle(Token l, Token r);
Token tge(Token l, Token r);
Token tgt(Token l, Token r);
Token teq(Token l, Token r);
Token tabouteq(Token l, Token r);
Token tne(Token l, Token r);
#endif

1441
src/common/func.c Normal file

File diff suppressed because it is too large Load diff

14
src/common/func.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef FUNC_H
#define FUNC_H
#include "scanner.h"
typedef struct
{
const char name[20];
Token (*func)(int, const Token[]);
} Tfunc;
extern Tfunc tfunc[];
#endif

123
src/common/htmlio.c Normal file
View file

@ -0,0 +1,123 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "htmlio.h"
#include "main.h"
#include "misc.h"
/*}}}*/
/* savehtml -- save as HTML table */ /*{{{*/
const char *savehtml(Sheet *sheet, const char *name, int body,
const Location beg, const Location end,
unsigned int *count)
{
/* variables */ /*{{{*/
FILE *fp=(FILE*)0; /* cause runtime error */
Location w;
char buf[1024];
char num[20];
char fullname[PATH_MAX];
Cell *cell;
/*}}}*/
/* asserts */ /*{{{*/
assert(sheet != (Sheet*)0);
assert(name != (const char*)0);
/*}}}*/
*count=0;
w[X] = beg[X];
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
{
if (body) /* open new file */ /*{{{*/
{
sprintf(num, ".%d", w[Z]);
fullname[sizeof(fullname)-strlen(num)-1]='\0';
(void)strncpy(fullname,name,sizeof(fullname)-strlen(num)-1);
fullname[sizeof(fullname)-1]='\0';
(void)strncat(fullname,num,sizeof(fullname)-strlen(num)-1);
fullname[sizeof(fullname)-1]='\0';
if ((fp=fopen(fullname,"w"))==(FILE*)0) return strerror(errno);
}
/*}}}*/
else /* print header */ /*{{{*/
if (fputs_close("<html>\n<head>\n<title>\n</title>\n</head>\n<body>\n",fp)==EOF) return strerror(errno);
/*}}}*/
if (fputs_close("<table>\n",fp)==EOF) return strerror(errno);
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y])) /* print contents */ /*{{{*/
{
if (fputs_close("<tr>",fp)==EOF) return strerror(errno);
for (w[X]=beg[X]; w[X]<=end[X]; )
{
int multicols;
char *bufp;
for (multicols=w[X]+1; multicols<sheet->dimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols);
multicols = multicols - w[X];
if (multicols>1) fprintf(fp,"<td colspan=%d",multicols);
else fprintf(fp,"<td");
cell = CELL_AT(sheet, w);
switch (getadjust(cell))
{
case LEFT: if (fputs_close(" align=left>",fp)==EOF) return strerror(errno); break;
case RIGHT: if (fputs_close(" align=right>",fp)==EOF) return strerror(errno); break;
case CENTER: if (fputs_close(" align=center>",fp)==EOF) return strerror(errno); break;
default: assert(0);
}
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell),
getprecision(cell), sheet, w);
if (transparent(cell))
{
if (fputs_close(buf,fp)==EOF) return strerror(errno);
}
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
{
case '<': if (fputs_close("&lt;",fp)==EOF) return strerror(errno); break;
case '>': if (fputs_close("&gt;",fp)==EOF) return strerror(errno); break;
case '&': if (fputs_close("&amp;",fp)==EOF) return strerror(errno); break;
case '"': if (fputs_close("&quot;",fp)==EOF) return strerror(errno); break;
default: if (fputc_close(*bufp,fp)==EOF) return strerror(errno);
}
if (fputs_close("</td>",fp)==EOF) return strerror(errno);
w[X] += multicols;
++*count;
}
if (fputs_close("</tr>\n",fp)==EOF) return strerror(errno);
}
/*}}}*/
if (fputs_close("</table>\n",fp)==EOF) return strerror(errno);
if (body)
{
if (fclose(fp)==EOF) return strerror(errno);
}
}
if (!body)
{
if (fputs_close("</body>\n</html>\n",fp)==EOF) return strerror(errno);
if (fclose(fp)==EOF) return strerror(errno);
}
return (const char*)0;
}
/*}}}*/

10
src/common/htmlio.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef HTML_H
#define HTML_H
#include "sheet.h"
const char *savehtml(Sheet *sheet, const char *name, int body,
const Location beg, const Location end,
unsigned int *count);
#endif

147
src/common/latex.c Normal file
View file

@ -0,0 +1,147 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "latex.h"
#include "main.h"
#include "misc.h"
/*}}}*/
/* savelatex -- save as LaTeX table */ /*{{{*/
const char *savelatex(Sheet *sheet, const char *name, int body,
const Location beg, const Location end,
unsigned int *count)
{
/* variables */ /*{{{*/
FILE *fp=(FILE*)0; /* cause runtime error */
Location w;
char buf[1024];
char num[20];
char fullname[PATH_MAX];
Cell *cell;
/*}}}*/
/* asserts */ /*{{{*/
assert(sheet != (Sheet*)0);
assert(name != (const char*)0);
/*}}}*/
*count=0;
w[X] = beg[X];
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
{
if (body)
/* open new file */ /*{{{*/
{
sprintf(num, ".%d", w[Z]);
fullname[sizeof(fullname)-strlen(num)-1]='\0';
(void)strncpy(fullname,name,sizeof(fullname)-strlen(num)-1);
fullname[sizeof(fullname)-1]='\0';
(void)strncat(fullname,num,sizeof(fullname)-strlen(num)-1);
fullname[sizeof(fullname)-1]='\0';
if ((fp=fopen(fullname,"w"))==(FILE*)0) return strerror(errno);
}
/*}}}*/
else
/* print header */ /*{{{*/
if (w[Z] == beg[Z])
{
if (fputs_close("\\documentclass{article}\n\\usepackage{longtable}\n\\begin{document}\n\\setlongtables\n\\vfill\n",fp)==EOF) return strerror(errno);
}
else
{
if (fputs_close("\\clearpage\n\\vfill\n",fp)==EOF) return strerror(errno);
}
/*}}}*/
/* print bogus format */ /*{{{*/
fprintf(fp,"\\begin{longtable}{");
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X])) if (fputc_close('l',fp)==EOF) return strerror(errno);
fprintf(fp,"}\n");
/*}}}*/
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
/* print contents */ /*{{{*/
{
for (w[X]=beg[X]; w[X]<=end[X]; )
{
int multicols;
char *bufp;
if (w[X]>beg[X] && fputc_close('&',fp)==EOF) return strerror(errno);
for (multicols = w[X]+1; multicols<sheet->dimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols);
multicols = multicols - w[X];
fprintf(fp,"\\multicolumn{%d}{",multicols);
cell = CELL_AT(sheet, w);
switch (getadjust(cell))
{
case LEFT: if (fputc_close('l',fp)==EOF) return strerror(errno); break;
case RIGHT: if (fputc_close('r',fp)==EOF) return strerror(errno); break;
case CENTER: if (fputc_close('c',fp)==EOF) return strerror(errno); break;
default: assert(0);
}
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell),
getprecision(cell), sheet, w);
if (fputs_close("}{",fp)==EOF) return strerror(errno);
if (transparent(cell))
{
if (fputs_close(buf,fp)==EOF) return strerror(errno);
}
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
{
case '%':
case '$':
case '&':
case '#':
case '_':
case '{':
case '}':
case '~':
case '^': if (fputc_close('\\',fp)==EOF || fputc_close(*bufp,fp)==EOF) return strerror(errno); break;
case '\\': if (fputs_close("\\backslash ",fp)==EOF) return strerror(errno); break;
default: if (fputc_close(*bufp,fp)==EOF) return strerror(errno);
}
if (fputc_close('}',fp)==EOF) return strerror(errno);
w[X] += multicols;
++*count;
}
if (fputs_close(w[Y]<end[Y] ? "\\\\\n" : "\n\\end{longtable}\n",fp)==EOF) return strerror(errno);
}
/*}}}*/
if (body)
{
if (fclose(fp)==EOF) return strerror(errno);
}
else
{
if (fputs_close("\\vfill\n",fp)==EOF) return strerror(errno);
}
}
if (!body)
{
if (fputs_close("\\end{document}\n",fp)==EOF) return strerror(errno);
if (fclose(fp)==EOF) return strerror(errno);
}
return (const char*)0;
}
/*}}}*/

10
src/common/latex.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef LATEX_H
#define LATEX_H
#include "sheet.h"
const char *savelatex(Sheet *sheet, const char *name, int body,
const Location beg, const Location end,
unsigned int *count);
#endif

1965
src/common/main.c Normal file

File diff suppressed because it is too large Load diff

97
src/common/main.h Normal file
View file

@ -0,0 +1,97 @@
#ifndef MAIN_H
#define MAIN_H
#include "config.h"
#define _(x) (x)
#include "sheet.h"
#ifdef __cplusplus
extern "C" {
#endif
extern int batch;
extern int def_precision;
extern int quote;
extern int header;
extern int debug_level;
extern unsigned int batchln;
/* A variable of type Key is either a special symbol from this enum, representing
actions the user has triggered (by whatever means available), or a Unicode
character that was entered
*/
typedef enum {
K_NONE = 0,
K_INVALID = -1,
K_BACKSPACE = -2,
K_BPAGE = -3,
K_CLOCK = -4,
K_COPY = -5,
K_DC = -6,
K_DOWN = -7,
K_END = -8,
K_ENTER = -9,
K_FIRSTL = -10,
K_FPAGE = -11,
K_FSHEET = -12,
K_HOME = -13,
K_LASTL = -14,
K_LEFT = -15,
K_LOAD = -16,
K_LOADMENU = -17,
K_LSHEET = -18,
K_MARK = -19,
K_MENTER = -20,
K_NPAGE = -21,
K_NSHEET = -22,
K_PPAGE = -23,
K_PSHEET = -24,
K_QUIT = -25,
K_RECALC = -26,
K_RIGHT = -27,
K_SAVE = -28,
K_SAVEMENU = -29,
K_SAVEQUIT = -30,
K_UP = -31,
K_GOTO = -32,
K_NAME = -33,
ADJUST_LEFT = -34,
ADJUST_RIGHT = -35,
ADJUST_CENTER = -36,
ADJUST_SCIENTIFIC = -37,
ADJUST_BOLD = -38,
ADJUST_PRECISION = -39,
ADJUST_SHADOW = -40,
ADJUST_TRANSPARENT = -41,
ADJUST_LABEL = -42,
ADJUST_LOCK = -43,
ADJUST_IGNORE = -44,
K_COLWIDTH = -45,
BLOCK_CLEAR = -46,
BLOCK_INSERT = -47,
BLOCK_DELETE = -48,
BLOCK_MOVE = -49,
BLOCK_COPY = -50,
BLOCK_FILL = -51,
BLOCK_SORT = -52,
BLOCK_MIRROR = -53,
K_ABOUT = -54,
K_HELP = -55,
K_DUMPCELL = -56,
ADJUST_UNDERLINE = -57
} Key;
extern int do_sheetcmd(Sheet *cursheet, Key c, int moveonly);
extern int doanyway(Sheet *sheet, const char *msg);
extern void moveto(Sheet *sheet, int x, int y, int z);
extern void movetoloc(Sheet *sheet, const Location dest);
extern void relmoveto(Sheet *sheet, int x, int y, int z);
extern void do_mark(Sheet *cursheet, MarkState ms);
#ifdef __cplusplus
}
#endif
#endif

249
src/common/misc.c Normal file
View file

@ -0,0 +1,249 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#ifdef NEED_BCOPY
#define memmove(dst,src,len) bcopy(src,dst,len)
#endif
#include "default.h"
#include "main.h"
#include "misc.h"
#include "utf8.h"
/*}}}*/
/* posnumber -- match positive integer */ /*{{{*/
long int posnumber(const char *s, const char **endptr)
{
unsigned int base=10;
unsigned char c;
register const char *nptr = s;
long int result = 0L;
int saw_a_digit = 0;
if (*nptr == '0')
{
if ((c = *++nptr) == 'x' || c == 'X')
{
++nptr;
base = 16;
}
else
{
saw_a_digit = 1;
base = 8;
}
}
--nptr;
while ((c=*++nptr)!='\0')
{
if (isdigit(c)) c -= '0';
else if (isupper(c)) c -= ('A'-10);
else if (islower(c)) c -= ('a'-10);
else break;
if (c>=base) break;
saw_a_digit = 1;
result = result*base+c;
}
*endptr=(saw_a_digit ? nptr : s);
return result;
}
/*}}}*/
/* posorder -- sort two integers */ /*{{{*/
void posorder(int *x, int *y)
{
/* variables */ /*{{{*/
int t;
/*}}}*/
assert(x!=(int*)0);
assert(*x>=0);
assert(y!=(int*)0);
assert(*y>=0);
if (*x>*y)
{
t=*x;
*x=*y;
*y=t;
}
}
/*}}}*/
/* mystrmalloc -- return malloced copy of string */ /*{{{*/
char *mystrmalloc(const char *str)
{
return (strcpy(malloc(strlen(str)+1),str));
}
/*}}}*/
/* finite -- return error message about number or null */ /*{{{*/
static volatile int caughtfpe;
static void catchfpe(int n)
{
caughtfpe=1;
}
const char *dblfinite(double x)
{
/*struct sigaction act;
caughtfpe=0;
act.sa_handler=catchfpe;
act.sa_flags=0;
(void)sigemptyset(&act.sa_mask);
(void)sigaction(SIGFPE,&act,(struct sigaction*)0);*/
signal(SIGFPE, catchfpe);
if (x==0.0)
{
if (caughtfpe) return _("Not a (finite) floating point number"); /* who knows */
else return (const char*)0;
}
else
{
if (caughtfpe) return _("Not a (finite) floating point number");
/* If one comparison was allowed, more won't hurt either. */
if (x<0.0)
{
if (x<-DBL_MAX) return _("Not a (finite) floating point number"); /* -infinite */
else return (const char*)0;
}
else if (x>0.0)
{
if (x>DBL_MAX) return _("Not a (finite) floating point number"); /* +infinite */
else return (const char*)0;
}
else return _("Not a (finite) floating point number"); /* NaN */
}
}
/*}}}*/
/* fputc_close -- error checking fputc which closes stream on error */ /*{{{*/
int fputc_close(char c, FILE *fp)
{
int e;
if ((e=fputc(c,fp))==EOF)
{
int oerrno;
oerrno=errno;
(void)fclose(fp);
errno=oerrno;
}
return e;
}
/* fputs_close -- error checking fputs which closes stream on error */ /*{{{*/
int fputs_close(const char *s, FILE *fp)
{
int e;
if ((e=fputs(s,fp))==EOF)
{
int oerrno;
oerrno=errno;
(void)fclose(fp);
errno=oerrno;
}
return e;
}
/* adjust -- readjust a left adjusted string in a buffer */ /*{{{*/
void adjust(Adjust a, char *s, size_t n)
{
assert(s!=(char*)0);
assert(mbslen(s)<=n);
switch (a)
{
/* LEFT */ /*{{{*/
case LEFT: break;
/*}}}*/
/* RIGHT */ /*{{{*/
case RIGHT:
{
size_t len;
len=mbslen(s);
if (len < n)
{
memmove(s+n-len, s, strlen(s)+1);
memset(s, ' ', n-len);
}
break;
}
/*}}}*/
/* CENTER */ /*{{{*/
case CENTER:
{
size_t len,pad;
len=mbslen(s);
pad=(n-len)/2;
assert((pad+len)<=n);
memmove(s+pad, s, strlen(s)+1);
memset(s, ' ', pad);
//*(s+strlen(s)+n-pad-len)='\0';
//(void)memset(s+strlen(s),' ',n-pad-len-1);
break;
}
/*}}}*/
/* default */ /*{{{*/
default: assert(0);
/*}}}*/
}
}
/*}}}*/
/* strerror -- strerror(3) */ /*{{{*/
#ifdef NEED_STRERROR
extern int sys_nerr;
extern const char *sys_errlist[];
const char *strerror(int errno)
{
return (errno>=0 && errno<sys_nerr ? sys_errlist[errno] : "unknown error");
}
#endif
/*}}}*/
/* myrealloc -- ANSI conforming realloc() */ /*{{{*/
#ifdef OLD_REALLOC
#undef realloc
void *myrealloc(void *p, size_t n)
{
return (p==(void*)0 ? malloc(n) : realloc(p,n));
}
#endif
/*}}}*/
char *striphtml(const char *in)
{
char *end, *stripped = malloc(strlen(in)), *out = stripped;
in--;
while (in && (end = strchr(++in, '<'))) {
memcpy(out, in, end-in);
out += end-in;
in = strchr(end+1, '>');
}
if (in) strcpy(out, in);
else *out = 0;
return stripped;
}

25
src/common/misc.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef MISC_H
#define MISC_H
#include <stdio.h>
#include "sheet.h"
#ifdef __cplusplus
extern "C" {
#endif
void posorder(int *x, int *y);
long int posnumber(const char *s, const char **endptr);
char *mystrmalloc(const char *str);
const char *dblfinite(double x);
int fputc_close(char c, FILE *fp);
int fputs_close(const char *s, FILE *fp);
void adjust(Adjust a, char *s, size_t n);
char *striphtml(const char *in);
#ifdef __cplusplus
}
#endif
#endif

328
src/common/parser.c Normal file
View file

@ -0,0 +1,328 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "eval.h"
#include "main.h"
#include "misc.h"
#include "parser.h"
#include "scanner.h"
#include "sheet.h"
/*}}}*/
/* #defines */ /*{{{*/
#define MAXARGC 16
/*}}}*/
/* prototypes */ /*{{{*/
static Token term(Token *n[], int *i);
/*}}}*/
/* primary -- parse and evaluate a primary term */ /*{{{*/
static Token primary(Token *n[], int *i)
{
/* variables */ /*{{{*/
int argc,j;
Token *ident,argv[MAXARGC],result;
/*}}}*/
if (n[*i]==(Token*)0)
/* error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("missing operator"))+1),_("missing operator"));
return result;
}
/*}}}*/
else switch (n[*i]->type)
{
/* STRING, FLOAT, INT */ /*{{{*/
case STRING:
case FLOAT:
case INT:
{
return tcopy(*n[(*i)++]);
}
/*}}}*/
/* OPERATOR */ /*{{{*/
case OPERATOR:
{
if (n[*i]->u.op==OP)
/* return paren term */ /*{{{*/
{
++(*i);
result=term(n,i);
if (result.type==EEK) return result;
if (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==CP)
{
++(*i);
return result;
}
tfree(&result);
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_(") expected"))+1),_(") expected"));
return result;
}
/*}}}*/
else if (n[*i]->u.op==MINUS)
/* return negated term */ /*{{{*/
{
++(*i);
return(tneg(primary(n,i)));
}
/*}}}*/
else
/* return error, value expected */ /*{{{*/
{
result.type=EEK;
result.u.err=mystrmalloc(_("value expected"));
return result;
}
/*}}}*/
}
/*}}}*/
/* LIDENT */ /*{{{*/
case LIDENT:
{
ident=n[*i];
++(*i);
return findlabel(upd_sheet,ident->u.lident);
}
/*}}}*/
/* FIDENT */ /*{{{*/
case FIDENT:
{
ident=n[*i];
++(*i);
if (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==OP)
/* parse arguments and closing paren of function call, return its value */ /*{{{*/
{
++(*i);
argc=0;
if (!(n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==CP))
/* parse at least one argument */ /*{{{*/
{
if (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==COMMA)
/* empty argument */ /*{{{*/
{
argv[argc].type=EMPTY;
}
/*}}}*/
else argv[argc]=term(n,i);
if (argv[argc].type==EEK) return argv[argc];
++argc;
while (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==COMMA)
/* parse the following argument */ /*{{{*/
{
++(*i);
if (argc<=MAXARGC)
{
if (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && (n[*i]->u.op==COMMA || n[*i]->u.op==CP))
{
argv[argc].type=EMPTY;
}
else argv[argc]=term(n,i);
}
else
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("too many arguments"))+1),_("too many arguments"));
for (j=0; j<=argc; ++j) tfree(&argv[j]);
return result;
}
++argc;
}
/*}}}*/
}
/*}}}*/
if (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==CP)
/* eval function */ /*{{{*/
{
++(*i);
result=tfuncall(ident,argc,argv);
for (j=0; j<argc; ++j) tfree(&argv[j]);
}
/*}}}*/
else
/* ) expected */ /*{{{*/
{
for (j=0; j<argc; ++j) tfree(&argv[j]);
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_(") expected"))+1),_(") expected"));
}
/*}}}*/
return result;
}
/*}}}*/
else
{
result.type=EEK;
result.u.err=mystrmalloc(_("( expected"));
return result;
}
}
/*}}}*/
default: ; /* fall through */
}
result.type=EEK;
result.u.err=mystrmalloc(_("value expected"));
return result;
}
/*}}}*/
/* powterm -- parse and evaluate a x^y term */ /*{{{*/
static Token powterm(Token *n[], int *i)
{
Token l;
l=primary(n,i);
if (l.type==EEK) return l;
while (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op==POW)
{
Token result,r;
++(*i);
r=primary(n,i);
result=tpow(l,r);
tfree(&l);
tfree(&r);
if (result.type==EEK) return result;
l=result;
}
return l;
}
/*}}}*/
/* piterm -- parse and evaluate a product/division/modulo term */ /*{{{*/
static Token piterm(Token *n[], int *i)
{
Token l;
l=powterm(n,i);
if (l.type==EEK) return l;
while (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && (n[*i]->u.op==DIV || n[*i]->u.op==MUL || n[*i]->u.op==MOD))
{
Operator op;
Token result,r;
op=n[*i]->u.op;
++(*i);
r=powterm(n,i);
switch (op)
{
case MUL: result=tmul(l,r); break;
case DIV: result=tdiv(l,r); break;
case MOD: result=tmod(l,r); break;
default: assert(0);
}
tfree(&l);
tfree(&r);
if (result.type==EEK) return result;
l=result;
}
return l;
}
/*}}}*/
/* factor -- parse and evaluate a factor of sums/differences */ /*{{{*/
static Token factor(Token *n[], int *i)
{
Token l;
l=piterm(n,i);
if (l.type==EEK) return l;
while (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && (n[*i]->u.op==PLUS || n[*i]->u.op==MINUS))
{
Operator op;
Token result,r;
op=n[*i]->u.op;
++(*i);
r=piterm(n,i);
result=(op==PLUS ? tadd(l,r) : tsub(l,r));
tfree(&l);
tfree(&r);
if (result.type==EEK) return result;
l=result;
}
return l;
}
/*}}}*/
/* term -- parse and evaluate a relational term */ /*{{{*/
static Token term(Token *n[], int *i)
{
Token l;
l=factor(n,i);
if (l.type==EEK) return l;
while (n[*i]!=(Token*)0 && n[*i]->type==OPERATOR && n[*i]->u.op>=LT && n[*i]->u.op<=NE)
{
Operator op;
Token result,r;
op=n[*i]->u.op;
++(*i);
r=factor(n,i);
switch (op)
{
case LT: result=tlt(l,r); break;
case LE: result=tle(l,r); break;
case GE: result=tge(l,r); break;
case GT: result=tgt(l,r); break;
case ISEQUAL: result=teq(l,r); break;
case ABOUTEQ: result=tabouteq(l,r); break;
case NE: result=tne(l,r); break;
default: assert(0);
}
tfree(&l);
tfree(&r);
if (result.type==EEK) return result;
l=result;
}
return l;
}
/*}}}*/
/* eval -- parse and evaluate token sequence */ /*{{{*/
Token eval(Token **n)
{
Token result;
int i;
assert(upd_sheet!=(Sheet*)0);
i=0;
result=term(n,&i);
if (result.type==EEK) return result;
if (n[i]!=(Token*)0)
{
tfree(&result);
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("parse error after term"))+1),_("parse error after term"));
return result;
}
return result;
}
/*}}}*/
/* eval_safe -- like eval, but handles null pointer to token sequence */ /*{{{*/
Token eval_safe(Token **n)
{
Token result;
if (n == EMPTY_TVEC)
{
result.type = EMPTY;
return result;
}
return eval(n);
}

9
src/common/parser.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef PARSER_H
#define PARSER_H
#include "scanner.h"
Token eval_safe(Token **n); /* OK to call on null ptr */
Token eval(Token *n[]); /* Don't call with null ptr */
#endif

329
src/common/sc.c Normal file
View file

@ -0,0 +1,329 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "eval.h"
#include "main.h"
#include "sheet.h"
#include "sc.h"
/*}}}*/
static const char *s2t_s;
static char *s2t_t;
static int s2t_term(Sheet *sheet);
/* s2t_loc */ /*{{{*/
static int s2t_loc(Sheet *sheet, const char **s, char **t)
{
int x,y;
Location tmp;
char label[10],*l;
l=label;
if (**s>='A' && **s<='Z')
{
*l++=**s;
*(*t)++=**s;
x=*(*s)++-'A';
}
else return 0;
if (**s>='A' && **s<='Z')
{
*l++=**s;
*(*t)++=**s;
x=x*26+(*(*s)++-'A');
}
if (**s>='0' && **s<='9')
{
*l++=**s;
y=**s-'0';
*(*t)++=*(*s)++;
}
else return 0;
while (**s>='0' && **s<='9')
{
*l++=**s;
y=y*10+(**s-'0');
*(*t)++=*(*s)++;
}
*l='\0';
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
if (*getlabel(CELL_AT(sheet, tmp))=='\0') setlabel(sheet, tmp, label, 0);
return 1;
}
/*}}}*/
/* s2t_range */ /*{{{*/
static int s2t_range(Sheet *sheet)
{
if (s2t_loc(sheet,&s2t_s,&s2t_t)==0) return 0;
if (*s2t_s==':')
{
s2t_s++; *s2t_t++=',';
if (s2t_loc(sheet,&s2t_s,&s2t_t)==0) return 0;
return 1;
}
else return 0;
}
/*}}}*/
/* s2t_primary */ /*{{{*/
static int s2t_primary(Sheet *sheet)
{
if (*s2t_s=='@')
/* @function */ /*{{{*/
{
++s2t_s;
if (strncmp(s2t_s,"sum(",4)==0)
/* @sum(range) -> sum(range) */ /*{{{*/
{
s2t_s+=4;
*s2t_t++='s'; *s2t_t++='u'; *s2t_t++='m'; *s2t_t++='(';
if (s2t_range(sheet)==0) return 0;
*s2t_t++=')';
return 1;
}
/*}}}*/
else if (strncmp(s2t_s,"rnd(",4)==0)
/* @rnd(e) -> int(e,-1,1) */ /*{{{*/
{
s2t_s+=4;
*s2t_t++='i'; *s2t_t++='n'; *s2t_t++='t'; *s2t_t++='(';
if (s2t_term(sheet)==0) return 0;
*s2t_t++=','; *s2t_t++='-'; *s2t_t++='1'; *s2t_t++=','; *s2t_t++='1'; *s2t_t++=')';
return 1;
}
/*}}}*/
else if (strncmp(s2t_s,"floor(",6)==0)
/* @floor(e) -> int(e,-2,-2) */ /*{{{*/
{
s2t_s+=6;
*s2t_t++='i'; *s2t_t++='n'; *s2t_t++='t'; *s2t_t++='(';
if (s2t_term(sheet)==0) return 0;
*s2t_t++=','; *s2t_t++='-'; *s2t_t++='2'; *s2t_t++=','; *s2t_t++='-'; *s2t_t++='2'; *s2t_t++=')';
return 1;
}
/*}}}*/
else if (strncmp(s2t_s,"ceil(",5)==0)
/* @ceil(e) -> int(e,2,2) */ /*{{{*/
{
s2t_s+=5;
*s2t_t++='i'; *s2t_t++='n'; *s2t_t++='t'; *s2t_t++='(';
if (s2t_term(sheet)==0) return 0;
*s2t_t++=','; *s2t_t++='2'; *s2t_t++=','; *s2t_t++='2'; *s2t_t++=')';
return 1;
}
/*}}}*/
else return 0;
}
/*}}}*/
else if ((*s2t_s>='0' && *s2t_s<='9') || *s2t_s=='.')
/* number */ /*{{{*/
{
if (*s2t_s=='.') *s2t_t++='0'; else *s2t_t++=*s2t_s++;
while (*s2t_s>='0' && *s2t_s<='9') *s2t_t++=*s2t_s++;
if (*s2t_s=='.')
{
*s2t_t++=*s2t_s++;
while (*s2t_s>='0' && *s2t_s<='9') *s2t_t++=*s2t_s++;
}
else
{
*s2t_t++='.'; *s2t_t++='0';
}
return 1;
}
/*}}}*/
else if (*s2t_s>='A' && *s2t_s<='Z')
/* cell value */ /*{{{*/
{
*s2t_t++='@'; *s2t_t++='(';
if (s2t_loc(sheet,&s2t_s,&s2t_t)==0) return 0;
*s2t_t++=')';
return 1;
}
/*}}}*/
else if (*s2t_s) return 0;
else return 1;
}
/*}}}*/
/* s2t_powterm */ /*{{{*/
static int s2t_powterm(Sheet *sheet)
{
if (s2t_primary(sheet)==0) return 0;
while (*s2t_s=='^')
{
*s2t_t++=*s2t_s++;
if (s2t_primary(sheet)==0) return 0;
}
return 1;
}
/*}}}*/
/* s2t_piterm */ /*{{{*/
static int s2t_piterm(Sheet *sheet)
{
if (s2t_powterm(sheet)==0) return 0;
while (*s2t_s=='*' || *s2t_s=='/')
{
*s2t_t++=*s2t_s++;
if (s2t_powterm(sheet)==0) return 0;
}
return 1;
}
/*}}}*/
/* s2t_term */ /*{{{*/
static int s2t_term(Sheet *sheet)
{
if (s2t_piterm(sheet)==0) return 0;
while (*s2t_s=='+' || *s2t_s=='-')
{
*s2t_t++=*s2t_s++;
if (s2t_piterm(sheet)==0) return 0;
}
return 1;
}
/*}}}*/
/* loadsc */ /*{{{*/
const char *loadsc(Sheet *sheet, const char *name)
{
/* variables */ /*{{{*/
static char errbuf[80];
FILE *fp;
char buf[256];
int line;
size_t width;
const char *err;
Cell *cell;
Location tmp;
int x,y;
/*}}}*/
if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
freesheet(sheet,0);
err=(const char*)0;
line=1;
while (fgets(buf,sizeof(buf),fp)!=(char*)0)
{
/* remove nl */ /*{{{*/
width=strlen(buf);
if (width>0 && buf[width-1]=='\n') buf[width-1]='\0';
/*}}}*/
if (buf[0] && buf[0]!='#')
{
if (strncmp(buf,"format ",7)==0) /* format col width precision whoknows */ /*{{{*/
{
char colstr[3];
int col,colwidth,precision,whoknows;
sscanf(buf+7,"%s %d %d %d",colstr,&colwidth,&precision,&whoknows);
col=(colstr[0]-'A'); if (colstr[1]) col=col*26+(colstr[1]-'A');
OLOCATION(tmp);
tmp[X] = col;
cell = initcell(sheet, tmp);
cell->adjust = RIGHT;
cell->precision = precision;
setwidth(sheet, col, 0, colwidth);
}
/*}}}*/
else if (strncmp(buf,"leftstring ",11)==0 || strncmp(buf,"rightstring ",12)==0) /* rightstring/leftstring cell = "string" */ /*{{{*/
{
int x,y;
const char *s;
Token **contents;
if (strncmp(buf,"leftstring ",11)==0) s=buf+11; else s=buf+12;
x=*s++-'A'; if (*s>='A' && *s<='Z') x=x*26+(*s++-'A');
y=*s++-'0'; while (*s>='0' && *s<='9') y=10*y+(*s++-'0');
s+=3;
contents=scan(&s);
if (contents==(Token**)0)
{
tvecfree(contents);
sprintf(errbuf,_("Expression syntax error in line %d"),line);
err=errbuf;
goto eek;
}
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
cell = initcell(sheet, tmp);
cell->adjust = strncmp(buf,"leftstring ",11) ? RIGHT : LEFT;
cell->contents[BASE] = contents;
}
/*}}}*/
else if (strncmp(buf,"let ",4)==0) /* let cell = expression */ /*{{{*/
{
/* variables */ /*{{{*/
const char *s;
Token **contents;
char newbuf[512];
/*}}}*/
s=buf+4;
x=*s++-'A'; if (*s>='A' && *s<='Z') x=x*26+(*s++-'A');
y=*s++-'0'; while (*s>='0' && *s<='9') y=10*y+(*s++-'0');
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
if (getcont(CELL_ATC(sheet,x,y,0),BASE)==(Token**)0)
{
s+=3;
s2t_s=s; s2t_t=newbuf;
if (s2t_term(sheet)==0)
{
*s2t_t='\0';
if (err==(const char*)0)
{
sprintf(errbuf,_("Unimplemented SC feature in line %d"),line);
err=errbuf;
}
}
*s2t_t='\0';
s=newbuf;
contents=scan(&s);
if (contents==(Token**)0)
{
tvecfree(contents);
sprintf(errbuf,_("Expression syntax error in line %d"),line);
err=errbuf;
goto eek;
}
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
cell = initcell(sheet, tmp);
cell->adjust = RIGHT;
cell->contents[BASE] = contents;
}
}
/*}}}*/
}
++line;
}
/* set precisions for each column */ /*{{{*/
for (x=0; x<sheet->dimx; ++x)
{
int prec;
prec=getprecision(CELL_ATC(sheet,x,0,0))==def_precision ? 2 : getprecision(CELL_ATC(sheet,x,0,0));
for (y=1; y<sheet->dimy; ++y) if (CELL_ATC(sheet,x,y,0)) CELL_ATC(sheet,x,y,0)->precision=prec;
}
/*}}}*/
eek:
if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno);
sheet->changed=0;
cachelabels(sheet);
forceupdate(sheet);
return err;
}
/*}}}*/

8
src/common/sc.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef SC_H
#define SC_H
#include "sheet.h"
const char *loadsc(Sheet *sheet, const char *name);
#endif

416
src/common/scanner.c Normal file
View file

@ -0,0 +1,416 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
#include <string.h>
#include "default.h"
#include "func.h"
#include "main.h"
#include "misc.h"
#include "utf8.h"
#include "scanner.h"
/*}}}*/
const char *Type_Name[] =
{ [EMPTY] = "EMPTY", [STRING] = "STRING", [FLOAT] = "FLOAT", [INT] = "INT",
[OPERATOR] = "OPERATOR", [LIDENT] = "LABEL", [FIDENT] = "FUNCTION",
[LOCATION] = "LOCATION", [EEK] = "ERROR"
};
/* identcode -- return number of identifier */ /*{{{*/
int identcode(const char *s, size_t len)
{
Tfunc *p;
int fident;
for (p=tfunc,fident=0; p->name[0]!='\0' && (len!=strlen(p->name) || strncmp(s,p->name,len)); ++p,++fident);
if (p->name[0]=='\0') return -1;
else return fident;
}
/*}}}*/
/* loc_in_box -- returns true if test is in the box determined by b and c */
bool loc_in_box(const Location test,
const Location b, const Location c)
{
for (Dimensions dim = X; dim < HYPER; ++dim)
{
if (test[dim] < b[dim] && test[dim] < c[dim]) return false;
if (test[dim] > b[dim] && test[dim] > c[dim]) return false;
}
return true;
}
/* charstring -- match quoted string and return token */ /*{{{*/
static Token *charstring(const char **s)
{
const char *r;
r=*s;
if (**s=='"')
{
++(*s);
while (**s!='\0' && **s!='"') if (**s=='\\' && *((*s)+1)!='\0') (*s)+=2; else ++(*s);
if (**s=='\0') { *s=r; return 0; }
else
{
Token *n;
char *t;
++(*s);
n=malloc(sizeof(Token));
n->type=STRING;
t=n->u.string=malloc((size_t)(*s-r));
/* Clean string of quotes. This may waste a few bytes, so? */
++r;
while (r<(*s-1)) if (*r=='\\') { *t++=*(r+1); r+=2; } else *t++=*r++;
*t='\0';
return n;
}
}
else return (Token*)0;
}
/*}}}*/
/* integer -- match an unsigned integer and return token */ /*{{{*/
static Token *integer(const char **s)
{
const char *r;
long i;
r=*s;
i=posnumber(r,s);
if (*s!=r && **s!='.' && **s!='e')
{
Token *n;
n=malloc(sizeof(Token));
n->type=INT;
n->u.integer=i;
return n;
}
else { *s=r; return (Token*)0; }
}
/*}}}*/
/* flt -- match a floating point number */ /*{{{*/
static Token *flt(const char **s)
{
/* variables */ /*{{{*/
const char *t;
char *end;
Token *n;
double x;
/*}}}*/
t=*s;
x=strtod(t,&end);
*s = end;
if (t!=*s && dblfinite(x)==(const char*)0)
{
n=malloc(sizeof(Token));
n->type=FLOAT;
n->u.flt=x;
return n;
}
else
{
*s=t;
return (Token*)0;
}
}
/*}}}*/
/* op -- match an op and return token */ /*{{{*/
static Token *op(const char **s)
{
Token *n;
Operator op;
switch (**s)
{
case '+': op=PLUS; break;
case '-': op=MINUS; break;
case '*': op=MUL; break;
case '/': op=DIV; break;
case '%': op=MOD; break;
case '(': op=OP; break;
case ')': op=CP; break;
case ',': op=COMMA; break;
case '^': op=POW; break;
case '<': if (*(*s+1)=='=') { ++(*s); op=LE; } else op=LT; break;
case '>': if (*(*s+1)=='=') { ++(*s); op=GE; } else op=GT; break;
case '=': if (*(*s+1)=='=') { ++(*s); op=ISEQUAL; } else return (Token*)0; break;
case '~': if (*(*s+1)=='=') { ++(*s); op=ABOUTEQ; } else return (Token*)0; break;
case '!': if (*(*s+1)=='=') { ++(*s); op=NE; } else return (Token*)0; break;
default: return (Token*)0;
}
n=malloc(sizeof(Token));
n->type=OPERATOR;
n->u.op=op;
++(*s);
return n;
}
/*}}}*/
/* ident -- match an identifier and return token */ /*{{{*/
static Token *ident(const char **s)
{
const char *begin;
Token *result;
if (isalpha((int)**s) || **s=='_' || **s=='@' || **s=='&' || **s=='.' || **s=='$')
{
int fident;
begin=*s; ++(*s);
while (isalpha((int)**s) || **s=='_' || **s=='@' || **s=='&' || **s=='.' || **s=='$' || isdigit((int)**s)) ++(*s);
result=malloc(sizeof(Token));
if ((fident=identcode(begin,(size_t)(*s-begin)))==-1)
{
result->type=LIDENT;
result->u.lident=malloc((size_t)(*s-begin+1));
(void)strncpy(result->u.lident,begin,(size_t)(*s-begin));
result->u.lident[*s-begin]='\0';
}
else
{
result->type=FIDENT;
result->u.fident=fident;
}
return result;
}
return (Token*)0;
}
/*}}}*/
/* scan -- scan string into tokens */ /*{{{*/
Token **scan(const char **s)
{
/* variables */ /*{{{*/
Token **na,*n;
const char *r;
int i,j;
/*}}}*/
/* compute number of tokens */ /*{{{*/
r=*s;
while (*r==' ') ++r;
for (i=0; *r!='\0'; ++i)
{
const char *or;
or=r;
while (*r==' ') ++r;
n=charstring(&r);
if (n==(Token*)0) n=op(&r);
if (n==(Token*)0) n=integer(&r);
if (n==(Token*)0) n=flt(&r);
if (n==(Token*)0) n=ident(&r);
if (or==r) { *s=r; return (Token**)0; }
}
/*}}}*/
/* allocate token space */ /*{{{*/
na=malloc(sizeof(Token*)*(i+1));
/*}}}*/
/* store tokens */ /*{{{*/
r=*s;
while (*r==' ') ++r;
for (j=0; j<i; ++j)
{
while (*r==' ') ++r;
n=charstring(&r);
if (n==(Token*)0) n=op(&r);
if (n==(Token*)0) n=integer(&r);
if (n==(Token*)0) n=flt(&r);
if (n==(Token*)0) n=ident(&r);
na[j]=n;
}
na[j]=(Token*)0;
/*}}}*/
return na;
}
/*}}}*/
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
size_t printtok(char* dest, size_t size, size_t field_width,
int quote_strings, int use_scientific,
int precision, int verbose_error, Token *tok)
{
size_t cur;
if (debug_level > 2) {
printf("..Entering printtok; bufsize %d, field_width %d, qs %d, us %d, prec %d, verr %d\n", size, field_width, quote_strings, use_scientific, precision, verbose_error);
}
cur = 0;
if (tok != NULLTOKEN) switch (tok->type)
{
/* EMPTY */ /*{{{*/
case EMPTY: if (size > 0) dest[cur++] = '\0'; break;
/*}}}*/
/* STRING */ /*{{{*/
case STRING:
{
char *str = tok->u.string;
if (quote_strings && cur<size) dest[cur++] = '"';
for (;cur<size && *str != '\0'; ++str)
{
if (quote_strings && (*str == '"' || *str=='\\')) dest[cur++] = '\\';
if (cur<size) dest[cur++]=*str;
}
if (quote_strings && cur<size) dest[cur++] = '"';
break;
}
/*}}}*/
/* INT */ /*{{{*/
case INT:
{
char buf[20];
size_t buflen;
buflen=sprintf(buf,"%ld",tok->u.integer);
assert(buflen<sizeof(buf));
(void)strncpy(dest+cur,buf,size-cur-1);
cur+=buflen;
break;
}
/*}}}*/
/* FLOAT */ /*{{{*/
case FLOAT:
{
/* variables */ /*{{{*/
char buf[1024],*p;
size_t len;
/*}}}*/
len=sprintf(buf, use_scientific ? "%.*e" : "%.*f",
precision == -1 ? DBL_DIG-2 : precision,
tok->u.flt);
assert(len<sizeof(buf));
if (!use_scientific && precision==-1)
{
p=&buf[len-1];
while (p>buf && *p=='0' && *(p-1)!='.') { *p='\0'; --p; --len; }
}
p=buf+len;
while (*--p==' ') { *p='\0'; --len; }
(void)strncpy(dest+cur,buf,size-cur-1);
cur+=len;
break;
}
/*}}}*/
/* OPERATOR */ /*{{{*/
case OPERATOR:
{
static const char *ops[]={ "+", "-", "*", "/", "(", ")", ",", "<", "<=", ">=", ">", "==", "~=", "!=", "^", "%" };
if ((size-cur)>1)
{
dest[cur++]=*ops[tok->u.op];
if (*(ops[tok->u.op]+1) && size>cur) dest[cur++]=*(ops[tok->u.op]+1);
}
break;
}
/*}}}*/
/* LIDENT */ /*{{{*/
case LIDENT:
{
size_t identlen;
identlen=strlen(tok->u.lident);
if ((cur+identlen+1)<=size) strcpy(dest+cur,tok->u.lident);
else (void)strncpy(dest+cur,tok->u.lident,size-cur-1);
cur+=identlen;
break;
}
/*}}}*/
/* FIDENT */ /*{{{*/
case FIDENT:
{
size_t identlen;
if (debug_level > 2) {
printf("...Found function [%s].\n", tfunc[tok->u.fident].name);
}
identlen=strlen(tfunc[tok->u.fident].name);
if ((cur+identlen+1)<=size) strcpy(dest+cur,tfunc[tok->u.fident].name);
else (void)strncpy(dest+cur,tfunc[tok->u.fident].name,size-cur-1);
cur+=identlen;
break;
}
/*}}}*/
/* LOCATION */ /*{{{*/
case LOCATION:
{
char buf[60];
sprintf(buf,"&(%d,%d,%d)",tok->u.location[0],tok->u.location[1],tok->u.location[2]);
(void)strncpy(dest+cur,buf,size-cur-1);
cur+=strlen(buf);
break;
}
/*}}}*/
/* EEK */ /*{{{*/
case EEK:
{
size_t errlen;
(void)strncpy(dest+cur,_("ERROR"),size-cur-1);
cur += strlen(_("ERROR"));
if (verbose_error)
{
(void)strncpy(dest+cur, ": ", size-cur-1);
cur += 2;
errlen = strlen(tok->u.err);
if ((cur+errlen+1) <= size) strcpy(dest+cur, tok->u.err);
else (void)strncpy(dest+cur, tok->u.err, size-cur-1);
cur += errlen;
}
break;
}
/*}}}*/
/* default */ /*{{{*/
default: assert(0);
/*}}}*/
}
if (cur<size) dest[cur] = 0;
else
{
dest[size-1] = 0;
cur = size;
}
if (field_width && mbslen(dest) > field_width) {
for (cur = 0; cur < field_width; ++cur) dest[cur] = '#';
dest[cur] = 0;
}
return cur;
}
/*}}}*/
/* print -- print token sequence */ /*{{{*/
void print(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Token **n)
{
size_t cur;
cur=0;
if (n != EMPTY_TVEC) for (; cur<size-1 && (*n) != NULLTOKEN; ++n)
cur += printtok(s+cur, size-cur, 0, quote, scientific, precision, 0, *n);
if (cur<size) s[cur] = 0;
else s[size-1] = 0;
if (chars && mbslen(s) > chars) {
for (cur=0; cur < chars; ++cur) s[cur] = '#';
s[cur] = 0;
}
}
/*}}}*/

68
src/common/scanner.h Normal file
View file

@ -0,0 +1,68 @@
#ifndef SCANNER_H
#define SCANNER_H
#include <sys/types.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
EMPTY
#ifndef __cplusplus
, STRING, FLOAT, INT, OPERATOR, LIDENT, FIDENT, LOCATION, EEK
#endif
} Type;
extern const char *Type_Name[];
typedef enum { PLUS, MINUS, MUL, DIV, OP, CP, COMMA, LT, LE, GE, GT, ISEQUAL, ABOUTEQ, NE, POW, MOD } Operator;
typedef int Location[3]; /* NOTE: Locations are passed by REFERENCE not value */
/* I.e., to accapt a Location argument, declare the parameter to be of type
const Location*
*/
typedef enum { X=0, Y=1, Z=2, HYPER} Dimensions;
#define OLOCATION(loc) ((void)memset(loc, 0, sizeof(Location)))
#define IN_OCTANT(loc) (loc[X]>=0 && loc[Y]>=0 && loc[Z]>=0)
#define LOCATION_GETS(la,lb) ((void)memcpy(la, lb, sizeof(Location)))
#define SAME_LOC(la,lb) (memcmp(la,lb,sizeof(Location))==0)
#define LOCATION_SUB(la,lb) (la)[X]-=(lb)[X]; (la)[Y]-=(lb)[Y]; (la)[Z]-=(lb)[Z];
bool loc_in_box(const Location test,
const Location b, const Location c);
typedef struct
{
Type type;
union
{
char *string;
double flt;
long integer;
Operator op;
char *lident;
int fident;
Location location;
char *err;
} u;
} Token;
#define NULLTOKEN ((Token*)0)
#define EMPTY_TVEC ((Token**)0)
int identcode(const char *s, size_t len);
Token **scan(const char **s);
size_t printtok(char* dest, size_t size, size_t field_width,
int quote_strings, int use_scientific,
int precision, int verbose_error, Token *tok);
void print(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Token **n);
#ifdef __cplusplus
}
#endif
#endif

2164
src/common/sheet.c Normal file

File diff suppressed because it is too large Load diff

164
src/common/sheet.h Normal file
View file

@ -0,0 +1,164 @@
#ifndef SHEET_H
#define SHEET_H
#include "scanner.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { LEFT=0, RIGHT=1, CENTER=2, AUTOADJUST=3 } Adjust;
typedef enum { IN_X, IN_Y, IN_Z } Direction;
/* must be a prime */
#define LABEL_CACHE 29
#define ASCENDING 001
typedef struct
{
int x;
int y;
int z;
int sortkey; /* OR-ed value of the above constants */
} Sortkey;
typedef enum { BASE=0, ITERATIVE=1, CONTINGENT=2 } ContentVariety;
typedef struct
{
Token **contents[CONTINGENT];
char *label;
Token value;
Token resvalue;
Adjust adjust;
int precision;
unsigned int updated:1;
unsigned int shadowed:1;
unsigned int scientific:1;
unsigned int locked:1;
unsigned int transparent:1;
unsigned int ignored:1;
unsigned int clock_t0:1;
unsigned int clock_t1:1;
unsigned int clock_t2:1;
unsigned int bold:1;
unsigned int underline:1;
} Cell;
#define NULLCELL ((Cell*)0)
struct Label
{
const char *label;
Location location;
struct Label *next;
};
typedef enum { MARK_CYCLE = 0, GET_MARK_CUR = 1, GET_MARK_ALL = 2,
MARKING = 3, MARKED = 4, UNMARKED = 5 } MarkState;
typedef struct
{
struct Label *labelcache[LABEL_CACHE];
Location cur;
Location mark1, mark2;
MarkState marking;
int offx, offy;
Cell **sheet;
int *column;
int dimx, dimy, dimz;
int orix, oriy, maxx, maxy;
int width;
char *name;
unsigned int changed:1;
unsigned int moveonly:1;
unsigned int clk:1;
void *display;
} Sheet;
#define LOC_WITHINC(s,x,y,z) (x<s->dimx && y<s->dimy && z<s->dimz)
#define LOC_WITHIN(s,l) (LOC_WITHINC(s,l[X],l[Y],l[Z]))
#define CELL_ATC(s,x,y,z) (*((s)->sheet + (z)*(s)->dimy*(s)->dimx + (y)*(s)->dimx +(x)))
#define CELL_AT(s,l) (CELL_ATC(s,l[X],l[Y],l[Z]))
#define CELL_IS_NULLC(s,x,y,z) (CELL_ATC(s,x,y,z) == NULLCELL)
#define CELL_IS_NULL(s,l) (CELL_AT(s,l) == NULLCELL)
#define CELL_IS_GOODC(s,x,y,z) (LOC_WITHINC(s,x,y,z) && !CELL_IS_NULLC(s,x,y,z))
#define CELL_IS_GOOD(s,l) (LOC_WITHIN(s,l) && !CELL_IS_NULL(s,l))
#define SHADOWEDC(s,x,y,z) (CELL_IS_GOODC(s,x,y,z) && CELL_ATC(s,x,y,z)->shadowed)
#define SHADOWED(s,l) (CELL_IS_GOOD(s,l) && CELL_AT(s,l)->shadowed)
#define ALL_COORDS_IN_SHEETC(s,x,y,z) x=0; x<(s)->dimx; ++x) for (y=0; y<(s)->dimy; ++y) for (z=0; z<(s)->dimz; ++z
#define ALL_LOCS_IN_SHEET(s,l) l[Z]=0; l[Z]<(s)->dimz; ++(l[Z])) for (l[Y]=0; l[Y]<(s)->dimy; ++(l[Y])) for (l[X]=0; l[X]<(s)->dimx; ++(l[X])
#define ALL_LOCS_IN_REGION(s,l) l[Z]=(s)->mark1[Z]; l[Z]<=(s)->mark2[Z]; ++(l[Z])) for (l[Y]=(s)->mark1[Y]; l[Y]<=(s)->mark2[Y]; ++(l[Y])) for (l[X]=(s)->mark1[X]; l[X]<=(s)->mark2[X]; ++(l[X])
#define ALL_CELLS_IN_SHEET(s,i,c) i=0,c=*((s)->sheet); i<(s)->dimx*(s)->dimy*(s)->dimz; ++i, c=*((s)->sheet+i)
extern Sheet *upd_sheet;
extern Location upd_l;
extern int max_eval;
void initialize_sheet(Sheet *sheet);
void resize(Sheet *sheet, int x, int y, int z);
Cell *initcell(Sheet *sheet, const Location at);
Cell *safe_cell_at(Sheet *sheet, const Location at);
Cell *curcell(Sheet *sheet);
void cachelabels(Sheet *sheet);
void freesheet(Sheet *sheet, int all);
void forceupdate(Sheet *sheet);
MarkState getmarkstate(Sheet *sheet);
void dump_current_cell(Sheet *sheet);
void freecell(Sheet *sheet, const Location at);
int columnwidth(Sheet *sheet, int x, int z);
void setwidth(Sheet *sheet, int x, int z, int width);
int cellwidth(Sheet *sheet, const Location at);
void putcont(Sheet *sheet, const Location at, Token **t, ContentVariety v);
Token **getcont(const Cell *cell, ContentVariety v);
Token getvalue(Sheet *sheet, const Location at);
void update(Sheet *sheet);
char *geterror(Sheet *sheet, const Location at);
void printvalue(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Sheet *sheet, const Location at);
Adjust getadjust(const Cell *cell);
void setadjust(Sheet *sheet, const Location at, Adjust adjust);
void shadow(Sheet *sheet, const Location at, int yep);
int shadowed(const Cell *cell);
void bold(Sheet *sheet, const Location at, int yep);
int isbold(const Cell *cell);
void underline(Sheet *sheet, const Location at, int yep);
int underlined(const Cell *cell);
void lockcell(Sheet *sheet, const Location at, int yep);
int locked(const Cell *cell);
int transparent(const Cell *cell);
void maketrans(Sheet *sheet, const Location at, int yep);
void igncell(Sheet *sheet, const Location at, int yep);
int ignored(const Cell *cell);
void clk(Sheet *sheet, const Location at);
void setscientific(Sheet *sheet, const Location at, int yep);
int getscientific(const Cell *cell);
void setprecision(Sheet *sheet, const Location at, int precision);
int getprecision(const Cell* cell);
const char *getlabel(const Cell* cell);
void setlabel(Sheet *sheet, const Location at, const char *buf, int update);
Token findlabel(Sheet *sheet, const char *label);
void relabel(Sheet* sheet, const Location at,
const char *oldlabel, const char *newlabel);
const char *savexdr(Sheet *sheet, const char *name, unsigned int *count);
const char *savetbl(Sheet *sheet, const char *name, int body, const Location beg, const Location end, unsigned int *count);
const char *savetext(Sheet *sheet, const char *name, const Location beg, const Location end, unsigned int *count);
const char *savecsv(Sheet *sheet, const char *name, char sep, const Location beg, const Location end, unsigned int *count);
const char *saveport(Sheet *sheet, const char *name, unsigned int *count);
const char *loadxdr(Sheet *sheet, const char *name);
const char *loadport(Sheet *sheet, const char *name);
const char *loadcsv(Sheet *sheet, const char *name);
void insertcube(Sheet *sheet, const Location beg, const Location end, Direction ins);
void deletecube(Sheet *sheet, const Location beg, const Location end, Direction ins);
void moveblock(Sheet *sheet, const Location beg, const Location end, const Location dest, int copy);
const char *sortblock(Sheet *sheet, const Location beg, const Location end, Direction dir, Sortkey *sk, size_t sklen);
void mirrorblock(Sheet *sheet, const Location beg, const Location end, Direction dir);
#ifdef __cplusplus
}
#endif
#endif

70
src/common/utf8.c Normal file
View file

@ -0,0 +1,70 @@
/*
UTF-8 wrapper for teapot
Copyright (C) 2010 Joerg Walter
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 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#include "utf8.h"
#include <string.h>
#ifdef ENABLE_UTF8
size_t mbslen(const char *s)
{
const unsigned char *str = (unsigned char *)s;
size_t chars = 0;
while (*str) {
chars++;
if (is_mbchar(*str++)) while (is_mbcont(*str)) str++;
}
return chars;
}
char *mbspos(const char *s, int ch)
{
const unsigned char *str = (unsigned char *)s;
int chars = 0;
if (ch < 0) {
while (chars > ch) {
chars--;
while (is_mbcont(*--str));
}
} else {
while (chars < ch && *str) {
chars++;
if (is_mbchar(*str++)) while (is_mbcont(*str)) str++;
}
}
return (char *)(void *)str;
}
#else
size_t mbslen(const char *str)
{
return strlen(str);
}
char *mbspos(const char *str, int ch)
{
return (char *)(void *)(str+ch);
}
#endif

64
src/common/utf8.h Normal file
View file

@ -0,0 +1,64 @@
/*
UTF-8 wrapper for teapot
Copyright (C) 2010 Joerg Walter
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 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef UTF8_H
#define UTF8_H
#include <sys/types.h>
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
size_t mbslen(const char *str);
char *mbspos(const char *str, int ch);
#ifdef ENABLE_UTF8
#define UTF8SZ 4
static inline int is_mbcont(unsigned char c)
{
return (c >= 0x80 && c < 0xc0);
}
static inline int is_mbchar(unsigned char c)
{
return (c >= 0x80);
}
#else
#define UTF8SZ 1
static inline int is_mbcont(unsigned char c)
{
return 0;
}
static inline int is_mbchar(unsigned char c)
{
return 0;
}
#endif
#ifdef __cplusplus
}
#endif
#endif

1171
src/common/wk1.c Normal file

File diff suppressed because it is too large Load diff

8
src/common/wk1.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef WK1_H
#define WK1_H
#include "sheet.h"
const char *loadwk1(Sheet *sheet, const char *name);
#endif

211
src/common/xdr.c Normal file
View file

@ -0,0 +1,211 @@
/* Notes */ /*{{{C}}}*//*{{{*/
/*
xdr_enum() is unusable, because enum_t may have a different size than
an enum. The construction
int_value=*enum_value;
result=xdr_int(xdrs,&int_value);
*enum_value=int_value;
return result;
solves the problem and works for both encoding and decoding.
Unfortunately, I could not yet find such a solution for a variable sized
array terminated by a special element.
*/
/*}}}*/
/* #includes */ /*{{{*/
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "sheet.h"
#include "xdr.h"
/*}}}*/
/* xdr_token */ /*{{{*/
static bool_t xdr_token(XDR *xdrs, Token *t)
{
int x,result;
if (xdrs->x_op==XDR_DECODE) (void)memset(t,0,sizeof(Token));
x=t->type;
if (t->type==OPERATOR) x|=t->u.op<<8;
result=xdr_int(xdrs,&x);
if ((x&0xff)==OPERATOR) t->u.op=(x>>8)&0xff;
t->type=x&0xff;
if (result==0) return result;
switch (t->type)
{
/* EMPTY */ /*{{{*/
case EMPTY:
{
return 1;
}
/*}}}*/
/* STRING */ /*{{{*/
case STRING:
{
return xdr_wrapstring(xdrs,&(t->u.string));
}
/*}}}*/
/* FLOAT */ /*{{{*/
case FLOAT:
{
return xdr_double(xdrs,&(t->u.flt));
}
/*}}}*/
/* INT */ /*{{{*/
case INT:
{
return xdr_long(xdrs,&(t->u.integer));
}
/*}}}*/
/* OPERATOR */ /*{{{*/
case OPERATOR:
{
return 1; /* since op is encoded in type */
}
/*}}}*/
/* LIDENT */ /*{{{*/
case LIDENT:
{
return xdr_wrapstring(xdrs,&(t->u.lident));
}
/*}}}*/
/* FIDENT */ /*{{{*/
case FIDENT:
{
return xdr_int(xdrs,&(t->u.fident));
}
/*}}}*/
/* LOCATION */ /*{{{*/
case LOCATION:
{
return (xdr_int(xdrs,&(t->u.location[0])) && xdr_int(xdrs,&(t->u.location[1])) && xdr_int(xdrs,&(t->u.location[2])));
}
/*}}}*/
/* EEK */ /*{{{*/
case EEK:
{
return xdr_wrapstring(xdrs,&(t->u.err));
}
/*}}}*/
/* default -- should not happen */ /*{{{*/
default: assert(0);
/*}}}*/
}
return 0;
}
/*}}}*/
/* xdr_tokenptr */ /*{{{*/
static bool_t xdr_tokenptr(XDR *xdrs, Token **t)
{
return xdr_pointer(xdrs,(char**)t,sizeof(Token),(xdrproc_t)xdr_token);
}
/*}}}*/
/* xdr_tokenptrvec */ /*{{{*/
static bool_t xdr_tokenptrvec(XDR *xdrs, Token ***t)
{
unsigned int len;
int result;
assert(t!=(Token***)0);
if (xdrs->x_op!=XDR_DECODE)
{
Token **run;
if (*t==(Token**)0) len=0;
else for (len=1,run=*t; *run!=(Token*)0; ++len,++run);
}
result=xdr_array(xdrs,(char**)t,&len,65536,sizeof(Token*),(xdrproc_t)xdr_tokenptr);
if (len==0) *t=(Token**)0;
return result;
}
/*}}}*/
/* xdr_mystring */ /*{{{*/
static bool_t xdr_mystring(XDR *xdrs, char **str)
{
static struct xdr_discrim arms[3]=
{
{ 0, (xdrproc_t)xdr_void },
{ 1, (xdrproc_t)xdr_wrapstring },
{ -1, (xdrproc_t)0 }
};
enum_t x;
int res;
x=(*str!=(char*)0);
res=xdr_union(xdrs, &x, (char*)str, arms, (xdrproc_t)0);
if (!x) *str=(char*)0;
return res;
}
/*}}}*/
/* Notes */ /*{{{*/
/*
The saved sheet consists of three xdr_int()s which specify x, y and z
position of the cell saved with xdr_cell(). Perhaps xdr_cell could be
given those as parameters, which would be more correct concerning the
purpose of the xdr_functions. Then again, reading the position may
fail (eof), whereas after the position has been read, xdr_cell() must
not fail when loading a sheet.
*/
/*}}}*/
/* xdr_cell */ /*{{{*/
bool_t xdr_cell(XDR *xdrs, Cell *cell)
{
int result,x;
assert(cell!=(Cell*)0);
if (!(xdr_tokenptrvec(xdrs, &(cell->contents[BASE]))
&& xdr_tokenptrvec(xdrs, &(cell->contents[ITERATIVE])) /* && xdr_token(xdrs, &(cell->value)) */ ))
return 0;
if (xdr_mystring(xdrs, &(cell->label))==0) return 0;
x=cell->adjust;
result=xdr_int(xdrs, &x);
cell->adjust=x;
if (result==0) return 0;
if (xdr_int(xdrs, &(cell->precision))==0) return 0;
x=(cell->updated&1)|((cell->shadowed&1)<<1)|((cell->scientific&1)<<2)|((cell->locked&1)<<3)|((cell->transparent&1)<<4)|((cell->ignored&1)<<5)|((cell->bold&1)<<6)|((cell->underline&1)<<7);
result=xdr_int(xdrs, &x);
cell->updated=((x&(1))!=0);
cell->shadowed=((x&(1<<1))!=0);
cell->scientific=((x&(1<<2))!=0);
cell->locked=((x&(1<<3))!=0);
cell->transparent=((x&(1<<4))!=0);
cell->ignored=((x&(1<<5))!=0);
cell->bold=((x&(1<<6))!=0);
cell->underline=((x&(1<<7))!=0);
return result;
}
/*}}}*/
/* xdr_column */ /*{{{*/
bool_t xdr_column(XDR *xdrs, int *x, int *z, int *width)
{
return (xdr_int(xdrs, x) && xdr_int(xdrs, z) && xdr_int(xdrs, width));
}
/*}}}*/
/* xdr_magic */ /*{{{*/
#define MAGIC0 (('#'<<24)|('!'<<16)|('t'<<8)|'e')
#define MAGIC1 (('a'<<24)|('p'<<16)|('o'<<8)|'t')
#define MAGIC2 (('\n'<<24)|('x'<<16)|('d'<<8)|'r')
bool_t xdr_magic(XDR *xdrs)
{
long m0,m1,m2;
m0=MAGIC0;
m1=MAGIC1;
m2=MAGIC2;
return (xdr_long(xdrs,&m0) && m0==MAGIC0 && xdr_long(xdrs,&m1) && m1==MAGIC1 && xdr_long(xdrs,&m2) && m2==MAGIC2);
}
/*}}}*/

20
src/common/xdr.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef XDR_H
#define XDR_H
/* Thanks to curses. */
#if 0
#undef TRUE
#undef FALSE
#endif
#include <sys/types.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "sheet.h"
bool_t xdr_cell(XDR *xdrs, Cell *cell);
bool_t xdr_column(XDR *xdrs, int *x, int *z, int *width);
bool_t xdr_magic(XDR *xdrs);
#endif

55
src/complete.c Normal file
View file

@ -0,0 +1,55 @@
#define _XOPEN_SOURCE 500
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include "complete.h"
void completefile(char *file, char *pos, size_t size)
{
struct dirent *direntp;
char *dir, *slash, *complete;
char next;
int required, atmost;
DIR *dirp;
next = *pos;
*pos = 0;
if (!(complete=strrchr(file,'/'))) {
dir = strdup(".");
complete = file;
} else {
if (complete == file) {
dir = strdup("/");
} else {
dir = strdup(file);
dir[complete-file] = 0;
}
complete++;
}
required = strlen(complete);
if (!(dirp = opendir(dir))) {
free(dir);
return;
}
while ((direntp = readdir(dirp))) {
if ((direntp->d_name[0] != '.' || complete[0] == '.') && !strncmp(complete, direntp->d_name, required)) {
if (!next && strlen(direntp->d_name) > required) {
strncpy(pos, direntp->d_name+required, size-(pos-file));
file[size-1] = 0;
break;
} else if (direntp->d_name[required] == next && !strcmp(pos+1, direntp->d_name+required+1)) {
next = 0;
}
}
}
closedir(dirp);
free(dir);
}

6
src/complete.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef COMPLETE_H
#define COMPLETE_H
void completefile(char *, char *, size_t size);
#endif

1145
src/display.c Normal file

File diff suppressed because it is too large Load diff

38
src/display.h Normal file
View file

@ -0,0 +1,38 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#include "main.h"
#include "sheet.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
Key c;
char *str;
} MenuChoice;
void display_main(Sheet *cursheet);
void display_init(Sheet *cursheet, int always_redraw);
void display_end(void);
void redraw_cell(Sheet *sheet, const Location at);
void redraw_sheet(Sheet *sheet);
const char *line_file(const char *file, const char *pattern, const char *title, int create);
int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx);
int line_ok(const char *prompt, int curx);
void line_msg(const char *prompt, const char *msg);
int keypressed(void);
void show_text(const char *text);
Key show_menu(Sheet *cursheet);
int line_menu(const char *prompt, const MenuChoice *choice, int curx);
void find_helpfile(char *buf, int size, const char *argv0);
#ifdef __cplusplus
}
#endif
#endif

871
src/fteapot.fl Normal file
View file

@ -0,0 +1,871 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0300
header_name {.h}
code_name {.cxx}
decl {\#include <unistd.h>} {private global
}
decl {\#include <stdint.h>} {private global
}
decl {\#include <limits.h>} {private global
}
decl {\#include <fcntl.h>} {private global
}
decl {\#define shadow _shadow} {private global
}
decl {\#define transparent _transparent} {private global
}
decl {\#define MenuChoice _MenuChoice} {private global
}
decl {\#define Cell _Cell} {private global
}
decl {\#include <FL/fl_message.H>} {private local
}
decl {\#include <FL/fl_draw.H>} {private global
}
decl {\#include <FL/Fl_Native_File_Chooser.H>} {private global
}
decl {\#include <FL/Fl_File_Icon.H>} {private global
}
decl {\#include <FL/filename.H>} {private global
}
decl {\#include <FL/Fl_Table.H>} {public global
}
decl {\#include <FL/Fl_Select_Browser.H>} {public global
}
decl {\#include <FL/Fl_Sys_Menu_Bar.H>} {public global
}
decl {\#undef shadow} {private global
}
decl {\#undef transparent} {private global
}
decl {\#undef MenuChoice} {private global
}
decl {\#undef Cell} {private global
}
decl {\#include "misc.h"} {private global
}
decl {\#include "display.h"} {public global
}
class TeapotTable {open : {public Fl_Table}
} {
decl {Sheet *cursheet;} {protected local
}
decl {bool cut, updating;} {protected local
}
decl {static const TableContext ACTION = (TableContext)(1<<8);} {public local
}
decl {static const TableContext REFRESH = (TableContext)(1<<9);} {public local
}
Function {TeapotTable(int x, int y, int w, int h, const char *l=0) : Fl_Table(x, y, w, h, l), cut(false), updating(false)} {open
} {
code {end();
col_resize_min(10);
col_resize(true);
col_header(header);
row_resize(false);
row_header(header);
set_visible_focus();
table_box(FL_THIN_UP_FRAME);} {}
}
Function {~TeapotTable()} {} {
code {} {}
}
Function {sheet(Sheet *s)} {open return_type void
} {
code {cursheet = s;
s->display = (void *)this;
clear();
update_table();
do_callback(CONTEXT_NONE, 0, 0);} {}
}
Function {sheet()} {return_type {Sheet *}
} {
code {return cursheet;} {}
}
Function {draw_cell(TableContext context, int R, int C, int xx, int yy, int W, int H)} {open return_type void
} {
code {char s[1024];
//printf("DRAW: %i @%i,%i - (%i,%i) %ix%i\\n", context, C,R, xx,yy, W,H);
switch (context) {
case CONTEXT_ENDPAGE:
W = xx-x()-2;
H = yy-y()-2;
xx = x()+2;
yy = y()+2;
fl_font(FL_HELVETICA | FL_BOLD, 14);
fl_push_clip(xx, yy, W, H);
fl_draw_box(FL_DIAMOND_UP_BOX, xx, yy, W, H, col_header_color());
fl_color(FL_INACTIVE_COLOR);
sprintf(s, "%d", cursheet->cur[Z]);
fl_draw(s, xx, yy, W, H, FL_ALIGN_CENTER);
fl_pop_clip();
break;
case CONTEXT_STARTPAGE:
adjust_outside();
if (Fl::event_button1()) update_sheet();
break;
case CONTEXT_COL_HEADER:
fl_font(FL_HELVETICA | FL_BOLD, 14);
fl_push_clip(xx, yy, W, H);
fl_draw_box(FL_THIN_UP_BOX, xx, yy, W, H, col_header_color());
fl_color(FL_FOREGROUND_COLOR);
sprintf(s, "%d", C);
fl_draw(s, xx, yy, W, H, FL_ALIGN_CENTER);
fl_pop_clip();
return;
case CONTEXT_ROW_HEADER:
fl_font(FL_HELVETICA | FL_BOLD, 14);
fl_push_clip(xx, yy, W, H);
fl_draw_box(FL_THIN_UP_BOX, xx, yy, W, H, row_header_color());
fl_color(FL_FOREGROUND_COLOR);
sprintf(s, "%d", R);
fl_draw(s, xx, yy, W, H, FL_ALIGN_CENTER);
fl_pop_clip();
return;
case CONTEXT_CELL: {
while (SHADOWEDC(cursheet, C, R, cursheet->cur[Z])) xx -= W = col_width(--C);
int x = C+1;
while (SHADOWEDC(cursheet,x,R,cursheet->cur[Z])) W += col_width(x), x++;
fl_push_clip(xx, yy, W, H);
bool selected = false;
MarkState ms = getmarkstate(cursheet);
Location test;
test[X] = C; test[Y] = R; test[Z] = cursheet->cur[Z];
if (ms != UNMARKED)
selected = loc_in_box(test, cursheet->mark1, cursheet->mark2);
bool iscurrent = C == cursheet->cur[X] && R == cursheet->cur[Y];
fl_draw_box(iscurrent ? FL_BORDER_BOX : FL_THIN_DOWN_BOX, xx, yy, W, H,
selected ? FL_SELECTION_COLOR : FL_BACKGROUND2_COLOR);
if (Fl::focus() == this && iscurrent)
draw_focus(FL_BORDER_BOX, xx, yy, W, H);
fl_pop_clip();
Cell *cell = safe_cell_at(cursheet, test);
fl_push_clip(xx+3, yy+3, W-6, H-6);
fl_color(FL_FOREGROUND_COLOR);
fl_font(FL_HELVETICA | (isbold(cell) ? FL_BOLD : 0), 14);
printvalue(s, sizeof(s), 0, 0, getscientific(cell),
getprecision(cell), cursheet, test);
int ww = 0, hh = 0;
fl_measure(s, ww, hh, 0);
if (ww > W-6) for (int i = 0; s[i]; i++) s[i] = '\#';
int adj = getadjust(cell);
fl_draw(s, xx+3, yy+3, W-6, H-6, adj == RIGHT?FL_ALIGN_RIGHT:adj == LEFT?FL_ALIGN_LEFT:FL_ALIGN_CENTER);
if (underlined(cell)) fl_xyline(xx, yy+H-7, xx+W);
fl_pop_clip();
return;
}
default:
return;
}} {selected
}
}
Function {update_table()} {open return_type void
} {
code {if (updating) return;
updating = true;
//printf("update_table: %ix%i@%i,%i; %i[%i], %i[%i]\\n", cursheet->dimx, cursheet->dimy, cursheet->curx, cursheet->cury, cursheet->offx, cursheet->maxx, cursheet->offy, cursheet->maxy);
if (cursheet->dimx > cols()) cols(cursheet->dimx);
if (cursheet->dimy > rows()) rows(cursheet->dimy);
adjust_outside();
for (int x = 0; x < cursheet->dimx; x++) {
int w = columnwidth(cursheet, x, cursheet->cur[Z])*10;
if (col_width(x) != w) col_width(x, w);
}
col_position(cursheet->offx);
row_position(cursheet->offy);
set_selection(cursheet->cur[Y], cursheet->cur[X],
cursheet->cur[Y], cursheet->cur[X]);
move_cursor(0,0);
updating = false;} {}
}
Function {update_sheet()} {return_type void
} {
code {int x1, x2, y1, y2;
if (updating) return;
updating = true;
get_selection(y1, x1, y2, x2);
if (x1 != x2 || y1 != y2) {
cursheet->mark1[X] = x1;
cursheet->mark1[Y] = y1;
cursheet->mark2[X] = x2;
cursheet->mark2[Y] = y2;
cursheet->mark1[Z] = cursheet->mark2[Z] = cursheet->cur[Z];
cursheet->marking = MARKED;
}
moveto(cursheet, current_col, current_row, -1);
visible_cells(cursheet->offy, cursheet->maxy, cursheet->offx, cursheet->maxx);
cursheet->maxx -= cursheet->offx;
cursheet->maxy -= cursheet->offy;
if (is_interactive_resize()) {
for (int C = 0; C < cursheet->dimx; C++) {
int w = (col_width(C) + 5)/10;
if (w != columnwidth(cursheet, C, cursheet->cur[Z]))
setwidth(cursheet, C, cursheet->cur[Z], w);
}
}
updating = false;
//printf("update_sheet: %ix%i@%i,%i; %i[%i], %i[%i] (%i,%i)-(%i,%i)\\n", cols(), rows(), cursheet->curx, cursheet->cury, cursheet->offx, cursheet->maxx, cursheet->offy, cursheet->maxy, x1, y1, x2, y2);} {}
}
Function {handle(int event)} {open return_type int
} {
code {if (event == FL_KEYDOWN) {
int ctrl = Fl::event_ctrl();
int alt = Fl::event_alt();
int shift = Fl::event_shift();
Key k = (Key)Fl::event_key();
switch ((unsigned int)k) {
case FL_Escape: k = K_INVALID; break;
case FL_BackSpace: k = K_BACKSPACE; break;
case FL_F+1: k = ctrl?K_ABOUT:K_HELP; break;
case FL_F+8: k = ctrl?K_RECALC:K_CLOCK; break;
case FL_F+9: k = ctrl?K_RECALC:K_CLOCK; break;
case FL_F+10: k = (Key)'/'; break;
case FL_Tab: if (shift) { k = K_CLOCK; break; }
case FL_Enter:
case FL_KP_Enter: k = alt?K_MENTER:K_ENTER; break;
case 'c': if (ctrl) { do_mark(cursheet, GET_MARK_CUR); cut = false; k = K_NONE; } break;
case 'v': if (ctrl) { do_mark(cursheet, MARKED);
k = cut ? BLOCK_MOVE : BLOCK_COPY;
}
break;
case 'x': if (ctrl) { do_mark(cursheet, GET_MARK_CUR); cut = true, k = K_NONE; } break;
case 'r': if (ctrl) k = K_RECALC; break;
case 'd': if (ctrl && shift && debug_level > 0) k = K_DUMPCELL; break;
case FL_Insert: if (ctrl) { do_mark(cursheet, GET_MARK_CUR); cut = false; } k = !shift?K_NONE:cut?BLOCK_MOVE:BLOCK_COPY; break;
case FL_Delete: if (shift) { do_mark(cursheet, GET_MARK_CUR); cut = true; } k = shift?K_NONE:BLOCK_CLEAR; break;
case FL_Home: k = ctrl?K_FIRSTL:shift?K_FSHEET:K_HOME; break;
case FL_End: k = ctrl?K_LASTL:shift?K_LSHEET:K_END; break;
case FL_Up: if (shift) do_mark(cursheet, MARKING); k = ctrl?K_PPAGE:K_UP; break;
case FL_Down: if (shift) do_mark(cursheet, MARKING); k = ctrl?K_NPAGE:K_DOWN; break;
case FL_Right: if (shift) do_mark(cursheet, MARKING); k = ctrl?K_FPAGE:K_RIGHT; break;
case FL_Left: if (shift) do_mark(cursheet, MARKING); k = ctrl?K_BPAGE:K_LEFT; break;
case FL_Page_Down: k = shift?K_NSHEET:ctrl?K_LASTL :K_NPAGE; break;
case FL_Page_Up: k = shift?K_PSHEET:ctrl?K_FIRSTL:K_PPAGE; break;
}
if (k > 0 && (ctrl || alt)) return 0;
// Quick and dirty upper-case fix, fails for international chars on keyboards...
if (shift && !alt && !ctrl && k >= 'a' && k <= 'z') k = (Key)(k - 'a' + 'A');
do_sheetcmd(cursheet, k, cursheet->moveonly);
do_callback(ACTION, 0, 0);
redraw();
} else if (event == FL_FOCUS) {
do_callback(REFRESH, 0, 0);
return 1;
} else if (event == FL_PUSH) {
int ex = Fl::event_x() - x(), ey = Fl::event_y() - y();
if (ex >= row_header_width() || ey >= col_header_height()) {
int rc = Fl_Table::handle(event);
do_callback(ACTION, 0, 0);
return rc;
}
if (ex < row_header_width()/2) relmoveto(cursheet, 0, 0, -1);
else relmoveto(cursheet, 0, 0, 1);
return 1;
} else if (event != FL_KEYUP) {
return Fl_Table::handle(event);
}
return 1;} {}
}
Function {adjust_outside()} {open protected return_type void
} {
code {int x1, x2, y1, y2;
if (!cols() || !rows()) {
cols(1);
rows(1);
}
visible_cells(y1, y2, x1, x2);
//printf("adj: (%i,%i)-(%i,%i) %ix%i\\n", x1, y1, x2, y2, cols(), rows());
if (x2+2 < cols() && cols() > cursheet->dimx) cols(x2+2 < cursheet->dimx?cursheet->dimx:x2+2);
else if (x2+1 == cols()) {
int xpos = col_scroll_position(cols());
int w = col_width(cols()-1);
x2 += (tow + hscrollbar->value() - xpos) / w + 2;
//printf(" : t: %i, w: %i, p: %i, r: %i\\n", tow, w, xpos, x2+1);
cols(x2+1);
}
if (y2+2 < rows() && rows() > cursheet->dimy) rows(y2+2 < cursheet->dimy?cursheet->dimy:y2+2);
else if (y2+1 == rows()) {
int ypos = row_scroll_position(rows());
int h = row_height(rows()-1);
y2 += (toh + vscrollbar->value() - ypos) / h + 2;
rows(y2+1);
}} {}
}
}
class MainWindow {open
} {
decl {static MainWindow *current;} {protected local
}
decl {int edit_rc;} {private local
}
Function {MainWindow(Sheet *sheet)} {open
} {
Fl_Window window {
label teapot
callback {if (Fl::event_key(FL_Escape)) table->take_focus();
else if (do_sheetcmd(table->sheet(), K_QUIT, 0) && doanyway(table->sheet(), _("Sheet modified, leave anyway?"))) {
line_label->deactivate();
window->hide();
}} open
protected xywh {866 342 800 600} type Double when 0 hide resizable
} {
Fl_Menu_Bar menu {
callback {Sheet *sheet = table->sheet();
Key action = (Key)(intptr_t)o->mvalue()->user_data();
if (do_sheetcmd(sheet, action, sheet->moveonly) && doanyway(sheet, _("Sheet modified, leave anyway?"))) {
window->hide();
return;
}
table->update_table();
table->redraw();} open
xywh {0 0 800 25}
class Fl_Sys_Menu_Bar
} {
Submenu {} {
label {&File}
xywh {25 25 67 24}
} {
MenuItem {} {
label {&Open...}
user_data K_LOADMENU
xywh {5 5 30 20} shortcut 0x4006f
}
MenuItem {} {
label {&Save}
user_data K_SAVE
xywh {0 0 30 20} shortcut 0x40073
}
MenuItem {} {
label {Save &As...}
user_data K_NAME
xywh {0 0 30 20} shortcut 0x50053 divider
}
MenuItem {} {
label {&Quit}
user_data K_QUIT
xywh {0 0 30 20} shortcut 0x40071
}
}
Submenu {} {
label {&Block}
xywh {25 25 67 24}
} {
MenuItem {} {
label {&Insert}
user_data BLOCK_INSERT
xywh {0 0 30 20} shortcut 0x90069
}
MenuItem {} {
label {&Delete}
user_data BLOCK_DELETE
xywh {0 0 30 20} shortcut 0x90064 divider
}
MenuItem {} {
label {&Move}
user_data BLOCK_MOVE
xywh {0 0 30 20} shortcut 0x9006d
}
MenuItem {} {
label {&Copy}
user_data BLOCK_COPY
xywh {0 0 36 21} shortcut 0x90063 divider
}
MenuItem {} {
label {&Fill}
user_data BLOCK_FILL
xywh {0 0 36 21} shortcut 0x90066
}
MenuItem {} {
label {C&lear}
user_data BLOCK_CLEAR
xywh {0 0 36 21} shortcut 0x9006c divider
}
MenuItem {} {
label {&Sort}
user_data BLOCK_SORT
xywh {0 0 36 21} shortcut 0x90073
}
MenuItem {} {
label {Mi&rror}
user_data BLOCK_MIRROR
xywh {0 0 36 21} shortcut 0x90072
}
}
Submenu {} {
label {&View}
xywh {0 0 70 21}
} {
MenuItem {} {
label {Column &Width...}
user_data K_COLWIDTH
xywh {0 0 36 21} shortcut 0x80077
}
MenuItem {} {
label {&Goto}
user_data K_GOTO
xywh {0 0 36 21} shortcut 0x40067
}
}
Submenu {} {
label {F&ormat} open
xywh {5 5 70 21}
} {
MenuItem {} {
label {L&abel...}
user_data ADJUST_LABEL
xywh {0 0 36 21} shortcut 0x80061 divider
}
MenuItem bold {
label {&Bold}
user_data ADJUST_BOLD
protected xywh {0 0 34 21} shortcut 0x80062
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem underline {
label {&Underline}
user_data ADJUST_UNDERLINE
protected xywh {0 0 34 21} shortcut 0x80075 divider
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem left {
label {&Left}
user_data ADJUST_LEFT
protected xywh {0 0 36 21} shortcut 0x8006c
code0 {o->flags |= FL_MENU_RADIO;}
}
MenuItem right {
label {&Right}
user_data ADJUST_RIGHT
protected xywh {0 0 36 21} shortcut 0x80072
code0 {o->flags |= FL_MENU_RADIO;}
}
MenuItem center {
label {&Center}
user_data ADJUST_CENTER
protected xywh {0 0 36 21} shortcut 0x80063 divider
code0 {o->flags |= FL_MENU_RADIO;}
}
MenuItem {} {
label {&Precision...}
user_data ADJUST_PRECISION
xywh {0 0 36 21} shortcut 0x80070 divider
}
MenuItem sci {
label {&Scientific}
user_data ADJUST_SCIENTIFIC
protected xywh {0 0 36 21} shortcut 0x80073
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem shadow {
label {Shadow&ed}
user_data ADJUST_SHADOW
protected xywh {0 0 36 21} shortcut 0x80065
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem transparent {
label {&Transparent}
user_data ADJUST_TRANSPARENT
protected xywh {0 0 36 21} shortcut 0x80074 divider
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem lock {
label {Lo&ck}
user_data ADJUST_LOCK
protected xywh {0 0 36 21} shortcut 0x80063
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem ignore {
label {&Ignore}
user_data ADJUST_IGNORE
protected xywh {0 0 36 21} shortcut 0x80069
code0 {o->flags |= FL_MENU_TOGGLE;}
}
}
Submenu {} {
label {&Help} open
xywh {25 25 67 24}
} {
MenuItem {} {
label {&Manual}
user_data K_HELP
xywh {0 0 30 20} shortcut 0xffbe
}
MenuItem {} {
label {&About}
user_data K_ABOUT
xywh {0 0 30 20}
}
}
}
Fl_Group line_label {
label { Input:} open
protected xywh {0 25 800 25} box ROUND_UP_BOX align 20 deactivate
} {
Fl_Input line_input {
callback {bool enterkey = Fl::event_key(FL_Enter) || Fl::event_key(FL_KP_Enter);
if (Fl::focus() && (Fl::focus() != table || enterkey || Fl::event_key(FL_Escape))) {
if (enterkey) edit_rc = 0;
line_label->deactivate();
}}
protected xywh {75 27 723 21} box ROUND_DOWN_BOX labeltype NO_LABEL align 20 when 6 deactivate
}
}
Fl_Box table {
callback {Sheet *sheet = table->sheet();
table->update_sheet();
const char *label = getlabel(curcell(sheet));
char moveonly=sheet->moveonly ? *_("V") : *_("E");
char buf[1024];
if (*label == 0)
snprintf(buf, sizeof(buf), "%c @@(%d,%d,%d)=", moveonly,
sheet->cur[X], sheet->cur[Y], sheet->cur[Z]);
else snprintf(buf, sizeof(buf), "%c @@(%s)=", moveonly, label);
if (moveonly && table->callback_context() == TeapotTable::ACTION) {
char valbuf[1024] = "";
if (Fl::event_key() == 'p' || Fl::event_button1())
sprintf(valbuf, "(%i,%i,%i)",
sheet->cur[X], sheet->cur[Y], sheet->cur[Z]);
else if (Fl::event_key() == 'v')
printvalue(valbuf, sizeof(valbuf), 0, 1,
getscientific(curcell(sheet)), -1, sheet, sheet->cur);
else if (Fl::event_key(FL_Tab)) line_input->take_focus();
if (valbuf[0]) {
line_input->insert(valbuf);
line_input->take_focus();
}
}
char *err;
char val[1024];
if ((err = geterror(sheet, sheet->cur))) {
strncpy(val,err,sizeof(val));
free(err);
val[sizeof(val)-1] = 0;
} else {
print(val, sizeof(val), 0, 1, getscientific(curcell(sheet)), -1,
getcont(curcell(sheet), BASE));
Token **iter = getcont(curcell(sheet), ITERATIVE);
if (iter != EMPTY_TVEC) {
snprintf(val+strlen(val),sizeof(val)-strlen(val)," -> ");
print(val+strlen(val), sizeof(val)-strlen(val), 0, 1,
getscientific(curcell(sheet)), -1, iter);
}
}
line_edit(sheet, val, 0, buf, 0, 0);
Cell *cell = curcell(sheet);
int adj = getadjust(cell);
if (adj == LEFT) left->setonly();
else if (adj == RIGHT) right->setonly();
else if (adj == CENTER) center->setonly();
if (SHADOWEDC(sheet, sheet->cur[X]+1, sheet->cur[Y], sheet->cur[Z]))
shadow->set();
else shadow->clear();
if (::transparent(cell)) transparent->set();
else transparent->clear();
if (locked(cell)) lock->set();
else lock->clear();
if (ignored(cell)) ignore->set();
else ignore->clear();
if (isbold(cell)) bold->set();
else bold->clear();
if (underlined(cell)) underline->set();
else underline->clear();
if (getscientific(cell)) sci->set();
else sci->clear();}
protected xywh {0 50 800 525} box DOWN_FRAME labeltype NO_LABEL resizable
code0 {table->sheet(sheet);}
class TeapotTable
}
Fl_Box status {
label {teapot ready.}
protected xywh {0 575 800 25} box GTK_ROUND_DOWN_BOX align 20
}
}
code {current = this;} {}
}
Function {line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx)} {open return_type int
} {
code {if (line_label->active()) {
if (x) line_msg(NULL, "Action not possible at this time.");
return -1;
}
line_label->copy_label(prompt);
int ww = 0, hh = 0;
line_label->measure_label(ww, hh);
line_input->resize(line_label->x()+ww+5, line_input->y(), line_label->w()-ww-7, line_input->h());
line_input->value(buf);
if (!x) return 0;
line_input->maximum_size(size);
line_input->position(*x, *x);
line_label->activate();
line_input->activate();
table->sheet()->moveonly = 1;
line_input->take_focus();
edit_rc = -1;
while (line_label->active()) Fl::wait();
memcpy(buf, line_input->value(), size);
line_input->deactivate();
table->sheet()->moveonly = 0;
table->take_focus();
return edit_rc;} {}
}
Function {line_msg(const char *prompt, const char *msg)} {return_type void
} {
code {char label[1024];
snprintf(label, sizeof(label), "%s%s%s", prompt?prompt:"", prompt?" ":"", msg);
status->copy_label(label);} {}
}
decl {friend void line_msg(const char*, const char*);} {private local
}
}
Function {line_file(const char *file, const char *pattern, const char *title, int create)} {open C return_type {const char *}
} {
code {static char buf[PATH_MAX];
Fl_Native_File_Chooser chooser;
chooser.title(title);
chooser.type(create?Fl_Native_File_Chooser::BROWSE_SAVE_FILE:Fl_Native_File_Chooser::BROWSE_FILE);
chooser.filter(pattern);
chooser.options((create?Fl_Native_File_Chooser::NEW_FOLDER:0)|Fl_Native_File_Chooser::SAVEAS_CONFIRM);
if (file) {
fl_filename_absolute(buf, sizeof(buf), file);
char *p = (char *)fl_filename_name(buf);
*p = 0;
chooser.directory(buf);
}
if (chooser.show()) return NULL;
strncpy(buf, chooser.filename(), sizeof(buf));
buf[sizeof(buf)-1] = 0;
return buf;} {}
}
Function {line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx)} {C return_type int
} {
code {if (sheet) return ((MainWindow*)((TeapotTable*)sheet->display)->parent()->user_data())->line_edit(sheet, buf, size, prompt, x, offx);
const char *val = fl_input("%s", buf, prompt);
if (val) {
strncpy(buf, val, size);
buf[size-1] = 0;
}
return !val;} {}
}
Function {line_ok(const char *prompt, int curx)} {C return_type int
} {
code {int rc = !!fl_choice("%s", "&No", NULL, "&Yes", prompt);
if (Fl::event_key(FL_Escape)) return -1;
return rc;} {}
}
Function {line_msg(const char *prompt, const char *msg)} {C return_type void
} {
code {MainWindow::current->line_msg(prompt, msg);} {}
}
Function {keypressed()} {open C return_type int
} {
code {while (Fl::wait(.01)) if (Fl::event_key(FL_Escape)) return 1;
return 0;} {}
}
Function {line_menu(const char *prompt, const MenuChoice *choice, int curx)} {C return_type int
} {
Fl_Window line_menu_menu {
label {Please Choose} open
xywh {706 58 250 245} type Double hide resizable modal
} {
Fl_Group {} {
label {Please Choose:} open
xywh {0 0 250 200} box ENGRAVED_BOX align 21
} {
Fl_Browser line_menu_browser {
callback {line_menu_menu->hide();}
xywh {5 25 240 170}
class Fl_Select_Browser
}
}
Fl_Button {} {
label Cancel
callback {line_menu_menu->hide();}
xywh {5 205 240 35}
}
}
code {line_menu_browser->clear();
while (choice->str) {
line_menu_browser->add(choice->str+1);
choice++;
}
line_menu_menu->show();
while (line_menu_menu->shown()) Fl::wait();
return line_menu_browser->value()-1;} {}
}
Function {redraw_sheet(Sheet *sheet)} {C return_type void
} {
code {TeapotTable *t = (TeapotTable*)sheet->display;
t->update_table();
t->redraw();} {}
}
Function {redraw_cell(Sheet *sheet, const Location /* at */)} {C return_type void
} {
code {redraw_sheet(sheet);} {}
}
Function {display_init(Sheet *sheet, int always_redraw)} {open C return_type void
} {
code {Fl::get_system_colors();
\#ifdef ENABLE_HELP
Fl_File_Icon::load_system_icons();
\#endif
Fl::scheme("gtk+");
int ch = sheet->changed;
resize(sheet, 1, 1, 1);
sheet->changed = ch;
new MainWindow(sheet);} {}
}
Function {display_end()} {C return_type void
} {
code {} {}
}
Function {display_main(Sheet *cursheet)} {C return_type void
} {
code {((TeapotTable *)cursheet->display)->parent()->show();
Fl::run();} {}
}
Function {show_menu(Sheet *sheet)} {C return_type Key
} {
code {return K_NONE;} {}
}
decl {MainWindow *MainWindow::current;} {private global
}
declblock {\#ifdef ENABLE_HELP} {after {\#endif}
} {
decl {\#include <FL/Fl_Help_Dialog.H>} {private global
}
Function {show_text(const char *text)} {open C return_type void
} {
code {Fl_Help_Dialog *d = new Fl_Help_Dialog();
if (strchr(text, '<')) {
d->value(text);
} else {
d->load(text);
}
d->resize(d->x(), d->y(), d->w()*3/2, d->h()*3/2);
d->show();} {}
}
}
declblock {\#ifndef ENABLE_HELP} {after {\#endif}
} {
Function {show_text(const char *text)} {open C return_type void
} {
code {char *txt = striphtml(text);
fl_message("%s", txt);
free(txt);} {}
}
}
Function {find_helpfile(char *buf, int size, const char *argv0)} {open C return_type void
} {
code {fl_filename_absolute(buf, size, argv0);
char *p = (char *)fl_filename_name(buf);
strncpy(p, "../share/doc/teapot/html/index.html", buf+size-p);
buf[size-1] = 0;
// Check if help exists in default installed location, fallback value is valid for build directory
int test = open(buf, O_RDONLY);
if (test < 0) strncpy(p, "html/index.html", buf+size-p);
else close(test);
buf[size-1] = 0;
// Try the configure-time determined value
test = open(buf, O_RDONLY);
if (test < 0) strncpy(buf, HELPFILE, size);
else close(test);
buf[size-1] = 0;
// Fall back to a sane value for unixoid systems
test = open(buf, O_RDONLY);
if (test < 0) strncpy(buf, "/usr/share/doc/teapot/html/index.html", size);
else close(test);
buf[size-1] = 0;
} {}
}

247
src/graph.c Normal file
View file

@ -0,0 +1,247 @@
/* #includes */ /*{{{C}}}*//*{{{*/
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#define _GNU_SOURCE 1
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
#ifdef OLD_REALLOC
#define realloc(s,l) myrealloc(s,l)
#endif
extern char *optarg;
extern int optind,opterr,optopt;
int getopt(int argc, char * const *argv, const char *optstring);
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include "csv.h"
/*}}}*/
int main(int argc, char *argv[]) /*{{{*/
{
/* variables */ /*{{{*/
struct Pair
{
const char *label;
double value;
int special;
} *pair;
int pairs;
double height,width;
int box;
int nl;
/*}}}*/
/* parse options */ /*{{{*/
{
int c;
height=width=2.0;
box=0;
nl=1;
while ((c=getopt(argc,argv,"bnw:h:?"))!=EOF) switch (c)
{
/* w width */ /*{{{*/
case 'w':
{
char *end;
width=strtod(optarg,&end);
if (*end!='\0')
{
fprintf(stderr,"graph: invalid width\n");
exit(1);
}
break;
}
/*}}}*/
/* h height */ /*{{{*/
case 'h':
{
char *end;
height=strtod(optarg,&end);
if (*end!='\0')
{
fprintf(stderr,"graph: invalid height\n");
exit(1);
}
break;
}
/*}}}*/
/* n */
case 'n':
{
nl=0;
break;
}
/* b */
case 'b':
{
box=1;
break;
}
default:
{
fprintf(stderr,"Usage: graph [-b][-h height][-w width]\n");
exit(1);
}
}
}
/*}}}*/
/* get data */ /*{{{*/
{
char ln[256];
int line,pairsz;
pairs=pairsz=0;
pair=(struct Pair*)0;
for (line=1; fgets(ln,sizeof(ln),stdin); ++line)
{
const char *s;
const char *end;
if (pairs==pairsz)
{
if ((pair=realloc(pair,sizeof(struct Pair)*(pairsz+=128)))==(struct Pair*)0)
{
fprintf(stderr,"graph:%d:out of memory\n",line);
exit(1);
}
}
s=ln;
pair[pairs].label=csv_string(s,&end);
if (s==end) fprintf(stderr,"graph:%d:invalid string, ignoring record\n",line);
else
{
s=end;
pair[pairs].value=csv_double(s,&end);
if (s==end) fprintf(stderr,"graph:%d:invalid value, ignoring record\n",line);
else
{
s=end;
pair[pairs].special=csv_double(s,&end);
if (s==end && *s!='\n') fprintf(stderr,"graph:%d:invalid mark value, ignoringrecord\n",line);
else
{
s=end;
if (*s!='\n') fprintf(stderr,"graph:%d:trailing garbage\n",line);
}
++pairs;
}
}
}
}
/*}}}*/
if (box) /* make box graph */ /*{{{*/
{
double height,boxwid,min,max,scale;
int i;
height=2;
boxwid=width/pairs;
for (min=max=0.0,i=0; i<pairs; ++i)
{
if (pair[i].value<min) min=pair[i].value;
else if (pair[i].value>max) max=pair[i].value;
}
scale=height/(max-min);
printf("[\nFRAME: box invis wid %f ht %f\n",width,height);
for (i=0; i<pairs; ++i)
{
double v;
v=fabs(pair[i].value);
printf
(
"box wid %f ht %f with .%s at FRAME.sw + (%f,%f) \"%s\"\n",
boxwid,
v*scale,
pair[i].value>0 ? "sw" : "nw",
i*boxwid,
-min*scale,
pair[i].label
);
}
printf("]"); if (nl) printf("\n");
}
/*}}}*/
else /* make pie graph */ /*{{{*/
{
int anyspecial,i;
double sum,scale,extra,arc;
for (sum=0.0,i=0,anyspecial=0; i<pairs; ++i)
{
sum+=pair[i].value;
if (pair[i].special) anyspecial=1;
}
scale=2.0*M_PI/sum;
printf("[\n");
printf("box invis wid %f ht %f\n",width,width);
if (anyspecial) width-=width/10.0;
for (sum=0,i=0; i<pairs; sum+=pair[i].value,++i)
{
extra=(pair[i].special!=0)*width/20.0;
for (arc=0; (arc+M_PI_4)<(pair[i].value*scale); arc+=M_PI_4)
{
printf
(
"arc from last box.c + (%f,%f) to last box.c + (%f,%f) rad %f\n",
cos((sum+arc)*scale)*width/2.0 + cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+arc)*scale)*width/2.0 + sin((sum+pair[i].value/2.0)*scale)*extra,
cos((sum+arc+M_PI_4)*scale)*width/2.0 + cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+arc+M_PI_4)*scale)*width/2.0 + sin((sum+pair[i].value/2.0)*scale)*extra,
width/2.0
);
}
printf
(
"arc from last box.c + (%f,%f) to last box.c + (%f,%f) rad %f\n",
cos((sum+arc)*scale)*width/2.0 + cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+arc)*scale)*width/2.0 + sin((sum+pair[i].value/2.0)*scale)*extra,
cos((sum+pair[i].value)*scale)*width/2.0 + cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+pair[i].value)*scale)*width/2.0 + sin((sum+pair[i].value/2.0)*scale)*extra,
width/2.0
);
printf
(
"line from last box.c + (%f,%f) to last box.c + (%f,%f)\n",
cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+pair[i].value/2.0)*scale)*extra,
cos(sum*scale)*width/2.0+cos((sum+pair[i].value/2.0)*scale)*extra,
sin(sum*scale)*width/2.0+sin((sum+pair[i].value/2.0)*scale)*extra
);
printf
(
"line from last box.c + (%f,%f) to last box.c + (%f,%f)\n",
cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+pair[i].value/2.0)*scale)*extra,
cos((sum+pair[i].value)*scale)*width/2.0+cos((sum+pair[i].value/2.0)*scale)*extra,
sin((sum+pair[i].value)*scale)*width/2.0+sin((sum+pair[i].value/2.0)*scale)*extra
);
printf
(
"\"%s\" at last box.c + (%f,%f)\n",
pair[i].label,
cos((sum+pair[i].value/2.0)*scale)*width*0.35,
sin((sum+pair[i].value/2.0)*scale)*width*0.35
);
}
printf("]"); if (nl) printf("\n");
}
/*}}}*/
return 0;
}
/*}}}*/