├── CHANGES ├── CHANGES-git ├── LICENSE ├── Makefile.in ├── Makefile.in.vpath ├── README ├── README.md ├── SC.MACROS ├── TODO ├── VMS_NOTES ├── abbrev.c ├── build.com ├── cmds.c ├── color.c ├── compat.c ├── configure ├── crypt.c ├── eres.sed ├── format.c ├── frame.c ├── gram.y ├── help.c ├── interp.c ├── lex.c ├── pipe.c ├── psc.c ├── psc.doc ├── range.c ├── sc-7.16.lsm ├── sc.c ├── sc.doc ├── sc.h ├── scqref.doc ├── screen.c ├── sort.c ├── sres.sed ├── torev ├── tutorial.sc ├── version.c ├── version.h ├── vi.c ├── vmtbl.c ├── xmalloc.c ├── xsc.doc └── xsc.sh /CHANGES-git: -------------------------------------------------------------------------------- 1 | 2017-09-08 2 | * Changes to make sc build on NetBSD 1.5 3 | (Issue #3 reported by DNied@GitHub) 4 | 2016-04-14 5 | * Option -M (process mouse events) 6 | 2016-04-13 7 | * When rows or columns are deleted (e.g. with "dr" or "dc"), 8 | enclosed color ranges had not been deleted. An attempt had been 9 | made to fix this. 10 | * Bugfix: Automatic color range removal in fix_crange() led to a 11 | invalid pointer access crash. 12 | * Bugfix: "set cslop/!cslop" had no visual effect an did set the 13 | internal cslope value to the wrong (inverted) logical level. 14 | * Left mouse button support for edit/input line 15 | * Bugfix: vi commands f,t,F,T: Buffer out of bounds access fixed 16 | 2016-04-06 17 | * Selecting cells with the left mouse button added. 18 | * Bugfix: Scrolling upwards with ^Y did not check if top row is 19 | already zero and decremented further. This led to unpredictable 20 | effects. 21 | 2016-04-05 22 | * On some terminals ^Y did suspend sc instead of scrolling the 23 | screen down. This "delayed suspend" is now disabled (like in vi) 24 | to make ^Y's scroll down function work on any terminal. 25 | * Vertical scrolling using the mouse wheel possible after .scrc 26 | command "set mouse" 27 | 2016-04-01 28 | If the history had been saved and which filename was used for this 29 | had been configured in the Makefile. It is now possible to use 30 | the command "histfile" in .scrc to set this filename or to disable 31 | saving the history. 32 | 2016-03-24 33 | * Saving an existing database into a backup file before overwriting 34 | had been controlled by the Makefile definition DOBACKUPS. This is 35 | removed now and replaced by the options backup/!backup which can 36 | be set in .scrc 37 | * By definition command 'W' writes the database into a file as it 38 | appears on the screen. This did not work for double quotes (") or 39 | escaped double quotes (\"). Here the required escape characters 40 | itself (\) had been displayed. But sc does remove 1 or 2 '\' 41 | before a '"' when drawing on the screen. 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to https://unlicense.org 25 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile $Revision: 7.16 $ 2 | # 3 | # 1) Select the proper EXDIR (path), MANDIR, MANEXT, LIBDIR, SIGVOID, 4 | # REGEX, DFLT_PAGER, and FMOD. Most of the other things aren't 5 | # normally changed (see the comments with each) 6 | # 2) Select the proper machine/compiler/OS section of code 7 | # for MS-DOS look for the pattern 'MS-DOS' 8 | # 3) make install 9 | # 4) If you have the command 'file' that uses /etc/magic add the line: 10 | # 38 string Spreadsheet sc file 11 | 12 | RM ?= rm -f 13 | 14 | # SRCDIR will be filled in by the configure script, either a full or relative path or . 15 | SRCDIR= 16 | 17 | # Specify the name of the program. 18 | # All documentation and installation keys on this value. 19 | # 20 | name=sc 21 | NAME=SC 22 | 23 | # The base directory where everything should be installed. If you're 24 | # packaging this with an O/S, for example, you'll probably want to change 25 | # this to /usr. Otherwise, /usr/local is probably more appropriate, unless 26 | # you're replacing the vendor-supplied version. 27 | prefix=/usr/local 28 | 29 | # This is where the install step puts it. 30 | EXDIR=${prefix}/bin 31 | 32 | # This is where the man page goes. 33 | MANDIR=${prefix}/share/man/man1 34 | MANEXT=1 35 | MANMODE=644 36 | 37 | # This is where the library file (tutorial) goes. 38 | #LIBDIR=/usr/local/share/$(name) # reno 39 | LIBDIR=${prefix}/share/$(name) 40 | LIBRARY=-DLIBDIR=\"${LIBDIR}\" 41 | 42 | # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up 43 | #SIMPLE=-DSIMPLE 44 | SIMPLE= 45 | 46 | # Set BROKENCURSES if your curses has the nl/nonl bug 47 | # if it does and you don't set BROKENCURSES, the display will 48 | # be staggered across the screen. Also try IDLOKBAD below. 49 | #BROKENCURSES=-DBROKENCURSES 50 | BROKENCURSES= 51 | 52 | # Set USELOCALE to enable country-dependent display of decimal points, 53 | # local character recognition in words, and local @date() format. 54 | #USELOCALE= 55 | USELOCALE=-DUSELOCALE 56 | 57 | # Set SIGVOID if signal routines are type void. 58 | # use: SIGVOID=-DSIGVOID for: 59 | # System 5.3, SunOS 4.X, VMS, BSD4.4 (reno), and ANSI C Compliant systems 60 | # use: SIGVOID= for: 61 | # BSD systems (excluding reno, BSD4.4), and the UNIXPC 'cc' 62 | #SIGVOID= 63 | SIGVOID=-DSIGVOID 64 | 65 | # Set IEEE_MATH if you need setsticky() calls in your signal handlers 66 | # 67 | #IEEE_MATH=-DIEEE_MATH 68 | IEEE_MATH= 69 | 70 | # The -ffloat-store compiler option is necessary for compiling interp.c to 71 | # prevent spurious "Still changing after x iterations" errors, intermittent 72 | # problems with the @round function, comparisons failing when they shouldn't, 73 | # and potentially other similar problems due to FPU registers having greater 74 | # precision than doubles in memory. This is known to be necessary for GCC 75 | # on x86 processors/FPUs, and probably others. 76 | #FLOAT_STORE=-ffloat-store 77 | 78 | # Set RINT=-DRINT if you do not have rint() in math.h 79 | # Set RINT= on/with (they have rint): 80 | # SunOS 4.0.3c compiler 81 | # BSD4.4 (reno) 82 | #RINT=-DRINT 83 | RINT= 84 | 85 | # If your system supports POSIX.2 regular expressions, REGEX should be 86 | # set to -DREGCOMP. Otherwise, set REGEX to -DREGCMP if you have the 87 | # regcmp/regex regular expression routines (most System V based systems 88 | # do) or to -DRE_COMP if you have the re_comp/re_exec regular expression 89 | # routines (most BSD based systems do). If your system has no support for 90 | # regular expressions, leave REGEX unset. 91 | #REGEX= 92 | #REGEX=-DREGCMP 93 | #REGEX=-DRE_COMP 94 | REGEX=-DREGCOMP 95 | 96 | # This is the name of a pager like "more". 97 | # "pg" may be appropriate for SYSV. 98 | #DFLT_PAGER=-DDFLT_PAGER=\"more\" # generic && reno 99 | DFLT_PAGER=-DDFLT_PAGER=\"less\" 100 | 101 | # this is the name to save back ups in 102 | SAVE=-DSAVENAME=\"$(NAME).SAVE\" 103 | 104 | # path to crypt, do not define if you don't have crypt 105 | # most systems 106 | #CRYPT=-DCRYPT_PATH=\"/bin/crypt\" 107 | # BSD 108 | # CRYPT=-DCRYPT_PATH=\"/usr/bin/crypt\" 109 | # other people? 110 | #CRYPT=-DCRYPT_PATH=\"/usr/local/bin/crypt\" 111 | 112 | # If you get errors about fmod being undefined when you try to 113 | # compile, then define NO_FMOD (most likely BSD4.3 and Mt Xinu). 114 | #FMOD=-DNO_FMOD 115 | FMOD= 116 | 117 | # buffer size of a single field. It defines the max string length that sc can process. 118 | # The default size is 1024. 119 | FBUF=-DFBUFLEN=10240 120 | #FBUF= 121 | 122 | # If your system doesn't have notimeout() in curses define NONOTIMEOUT 123 | NO_NOTIMEOUT=-DNONOTIMEOUT 124 | #NO_NOTIMEOUT= 125 | 126 | # flags for lint 127 | LINTFLAGS=-abchxv 128 | 129 | # Format of quick reference guide generated by $(name)qref 130 | # Leave undefined for normal text output. 131 | #QREF_FMT= 132 | QREF_FMT=-DTROFF 133 | 134 | # *** SPECIAL NOTES *** 135 | # For ULTRIX: define the BSD4.2 section and SIGVOID above 136 | # tdw@cl.cam.ac.uk tested on Ultrix 3.1C-0 137 | # HP-UX 7.0: Do NOT use -O 138 | # (known broken, try sc's boolean operators if you wish) 139 | # 140 | # **** SYSV curses bugs... **** 141 | # Try setting IDLOKBAD to fix (with an empty spreadsheet): 142 | # a) Redrawing the bottom half of the screen when you 143 | # move between row 9 <-> 10 144 | # b) the highlighted row labels being trash when you 145 | # move between row 9 <-> 10 146 | # c) On an xterm on Esix Rev. D+ from eating lines 147 | # -goto (or move) a few lines (or more) past the bottom 148 | # of the screen, goto (or move) to the top line on the 149 | # screen, move upward and the current line is deleted, the 150 | # others move up even when they should not, check by 151 | # noticing the rows become 2, 3, 40, 41, 42... (etc). 152 | # Known systems/terminfos w/ curses problems: 153 | # {Esix Rev. D+, AT&T SysV3.2.1}:at386-m,xterm, HP-UX7.0:(not sure) 154 | #IDLOKISBAD=-DIDLOKBAD 155 | IDLOKISBAD= 156 | 157 | # If you don't have idlok() in your curses define NOIDLOK 158 | #NO_IDLOK=-DNOIDLOK 159 | NO_IDLOK= 160 | 161 | # If moving right off the screen causes the screen to not redraw 162 | # properly, define RIGHT_CBUG to get around a curses problem on some 163 | # boxes, this forces screen redraws when going right off the screen 164 | #RIGHTBUG=-DRIGHT_CBUG 165 | RIGHTBUG= 166 | 167 | # IF you have problems w/ your yacc try bison, Berkeley yacc, or 168 | # some other yacc. Some systems don't allow you to 169 | # increase the number of terminals (mostly AT&T), SCO's does though. 170 | # YACC=yacc 171 | # NOTE: Do not use with bison 1.16! Get a new version.... 172 | #YACC=bison -y 173 | 174 | # MS-DOS needs y_tab instead of the normal y.tab 175 | #YTAB=y_tab 176 | YTAB=y.tab 177 | 178 | # Command to use to make temporary copies of some source files. 179 | LN=ln -s 180 | #LN=cp 181 | #LN=ln 182 | 183 | #### SYSTEM DEFINES #### 184 | 185 | ######################################### 186 | # Use this for system AIX V3.1 187 | #CFLAGS= -O -DSYSV2 -DCHTYPE=int -DNLS 188 | #LDFLAGS= 189 | #LDADD=-lm -lPW -lcurses 190 | 191 | ######################################### 192 | # Use this for system V.2 (includes: HP-UX 7.05, UNIXPC) 193 | #CFLAGS= -O -DSYSV2 194 | #LDFLAGS= 195 | #LDADD=-lm -lPW -lcurses 196 | # with gcc on a Sequent also use: 197 | #CC=att gcc 198 | #CFLAGS= -DSYSV2 -g -pipe -traditional 199 | 200 | ######################################### 201 | # Use this for system V.3 202 | #CFLAGS= -DSYSV3 -O 203 | #LDFLAGS= -s 204 | #CFLAGS= -DSYSV3 -g 205 | #LDFLAGS= -g 206 | #LDADD=-lm -lncurses -lfl 207 | # with gcc also use: 208 | #CC=gcc 209 | #CFLAGS= -DSYSV3 -O -pipe 210 | # debugging bison (bison 1.16 is broken) 211 | #CFLAGS= -DSYSV3 -g -pipe -traditional 212 | #YACC=bison -y -v -t -l 213 | 214 | ######################################### 215 | # Use this for system V.4 216 | #CFLAGS= -DSYSV4 -DSYSV3 -O 217 | #LDFLAGS= -s 218 | #LDADD=-lm -lcurses -lgen 219 | # with gcc also use: 220 | #CC=gcc 221 | #CFLAGS= -DSYSV3 -O -pipe 222 | 223 | ######################################### 224 | # Microport 225 | #CFLAGS= -DSYSV2 -O -DUPORT -Ml 226 | #LDFLAGS=-Ml 227 | #LDADD=-lm -lcurses -lPW 228 | 229 | ######################################### 230 | # Use this for BSD 4.2 231 | #CFLAGS= -O -DBSD42 232 | #LDFLAGS= 233 | #LDADD=-lm -lcurses -ltermcap 234 | # with gcc also use: 235 | #CC=gcc 236 | 237 | ######################################### 238 | # Use this for Sequent boxes 239 | #CC=atscc 240 | #CFLAGS=-O -DBSD42 241 | #LDFLAGS= 242 | #LDADD=-lm -lcurses -ltermcap 243 | #PSCLIB=-lseq 244 | # with gcc also use: 245 | #CC=gcc 246 | #CFLAGS= -O -DBSD42 -pipe 247 | 248 | ######################################### 249 | # Use this for BSD 4.3 250 | #CFLAGS= -O -DBSD43 #-O or -g 251 | #LDFLAGS= # -lg might help if -g used in CFLAGS 252 | #LDADD=-lm -lcurses -ltermcap 253 | 254 | ######################################### 255 | # Use this for SunOS 4.X if you have the System V package installed. 256 | # This will link with the System V curses which is preferable to the 257 | # BSD curses (especially helps scrolling on slow (9600bps or less) 258 | # serial lines). 259 | # 260 | # Be sure to define SIGVOID and REGEX (to -DRE_COMP) above. 261 | # 262 | #CC=/usr/5bin/cc 263 | #CFLAGS= -O -DSYSV3 264 | #LDFLAGS= 265 | #LDADD=-lm -lcurses 266 | 267 | ######################################### 268 | # Use this for system III (XENIX) 269 | #CFLAGS= -O -DSYSIII 270 | #LDFLAGS= -i 271 | #LDADD=-lm -lcurses -ltermcap 272 | 273 | ######################################### 274 | # Use this for XENIX Version 2.3 275 | #CFLAGS= -O -DSYSIII -DXENIX2_3 276 | #LDFLAGS= -i 277 | #LDADD=-lm -lcurses -ltermcap 278 | 279 | ######################################### 280 | # Use this for VENIX 281 | #CFLAGS= -DVENIX -DBSD42 -DV7 282 | #LDFLAGS= -z -i 283 | #LDADD=-lm -lcurses -ltermcap 284 | 285 | ######################################### 286 | # For SCO Unix V rel. 3.2.0 287 | # -compile using rcc, cc does not cope with gram.c 288 | # -edit /usr/include/curses.h, rcc does not understand #error 289 | # -link: make CC=cc, rcc's loader gets unresolved __cclass, __range 290 | # (rather strange,?) 291 | #CC=rcc 292 | #CC=cc 293 | #CC=gcc -fstrength-reduce 294 | #SIGVOID=-DSIGVOID 295 | #CFLAGS= -O -DSYSV3 296 | #LDFLAGS= 297 | #LDADD=-lm -lcurses -ltinfo -lPW 298 | #YACC=yacc -Sm10000 299 | 300 | ######################################### 301 | # Use this for SCO Unix 3.2.2 and ODT 1.1 302 | #CC=cc 303 | #CFLAGS= -O -DSYSV3 304 | #LDFLAGS= 305 | #LDADD=-lm -lcurses -lPW -lmalloc -lc_s 306 | #YACC=yacc -Sm10000 307 | 308 | ######################################### 309 | # Use this for MS-DOS, Microsoft C 5.1 and NDMAKE 310 | #CC=cl 311 | #CFLAGS= -AL -O -Fo$*.o 312 | #LDFLAGS=/noi /st:0x4000 313 | #LDADD=lcurses 314 | #YACC=bison -y 315 | # 316 | #.SUFFIXES : .o .c 317 | #.c.o: 318 | # $(CC) $(CFLAGS) -c $*.c 319 | 320 | ######################################### 321 | # Use this for MS-DOS with DJGPP 322 | # REGEX should also be undefined (see above) unless a separate REGEX library 323 | # is installed (gdb includes one, but may result in file conflicts with 324 | # existing DJGPP files). 325 | #CC=gcc 326 | # Only use -Wall for testing, since it produces warnings that are of no 327 | # real effect on the reliability of the program, but may concern some 328 | # people who don't understand them. 329 | #CFLAGS=-DSYSV3 -O2 -Wall -UMSDOS 330 | #CFLAGS=-DSYSV3 -O2 -UMSDOS 331 | #LDADD=-lm -lpdcurses 332 | 333 | ######################################### 334 | CPPFLAGS += -I$(SRCDIR) 335 | _CFLAGS= $(CPPFLAGS) $(CFLAGS) $(INCDIR_CURSES) $(DEFINES) $(FBUF) $(__CDBG) $(__CLDBG) \ 336 | #-DTRACE='"/tmp/trace.txt"' 337 | _LDFLAGS=$(LDFLAGS) $(__CLDBG) -s 338 | LDADD=-lm $(LIBDIR_CURSES) $(LIB_CURSES) 339 | 340 | # All of the source files 341 | SRC=Makefile abbrev.c cmds.c color.c crypt.c eres.sed frame.c format.c gram.y \ 342 | help.c interp.c lex.c pipe.c psc.c range.c sc.c sc.h screen.c sort.c \ 343 | sres.sed version.c vi.c vmtbl.c xmalloc.c 344 | 345 | # The objects 346 | OBJS=abbrev.o cmds.o color.o crypt.o format.o frame.o gram.o help.o interp.o \ 347 | lex.o pipe.o range.o sc.o screen.o sort.o version.o vi.o vmtbl.o \ 348 | xmalloc.o compat.o 349 | 350 | # The documents in the Archive 351 | DOCS=CHANGES README sc.doc psc.doc tutorial.sc VMS_NOTES torev build.com 352 | 353 | all: $(name) p$(name) $(name)qref $(name).1 p$(name).1 $(name)qref.1 \ 354 | x$(name) x$(name).1 355 | 356 | $(name):$(PAR) $(OBJS) 357 | $(CC) $(_CFLAGS) ${_LDFLAGS} ${OBJS} $(RPATH_CURSES) -o $(name) \ 358 | ${LDADD} 359 | 360 | # Alternative link for MS-DOS 361 | #$(name): $(OBJS) 362 | # link ${_LDFLAGS} ${OBJS},$(name),,${LDADD}; 363 | 364 | gram.c: gram.y 365 | $(YACC) -d gram.y 366 | mv $(YTAB).c gram.c 367 | 368 | $(YTAB).h: gram.y 369 | 370 | p$(name): psc.c pvmtbl.o pxmalloc.o version.o 371 | $(CC) $(_CFLAGS) ${_LDFLAGS} -o p$(name) psc.c \ 372 | pvmtbl.o pxmalloc.o version.o ${PSCLIB} 373 | 374 | # Alternative link for MS-DOS (NB: MSC 5.1 has no getopt.c) 375 | #p$(name): psc.o pvmtbl.o pxmalloc.o getopt.o 376 | # link ${_LDFLAGS} psc.o pvmtbl.o pxmalloc.o getopt.o,p$(name); 377 | 378 | qhelp.c: help.c 379 | -$(RM) qhelp.c 380 | ${LN} help.c qhelp.c 381 | 382 | $(name)qref: qhelp.c sc.h 383 | $(CC) $(_CFLAGS) $(_LDFLAGS) -DQREF $(QREF_FMT) \ 384 | -DSCNAME=\"$(NAME)\" -o $(name)qref qhelp.c 385 | 386 | # Alternative link for MS-DOS 387 | #$(name)qref: qhelp.c sc.h 388 | # $(CC) -AL -O -Foqhelp.o -c -DQREF -DSCNAME=\"$(name)\" qhelp.c 389 | # link ${_LDFLAGS} qhelp.o,$(name)qref; 390 | 391 | pvmtbl.c: vmtbl.c 392 | -$(RM) pvmtbl.c 393 | ${LN} vmtbl.c pvmtbl.c 394 | 395 | pvmtbl.o: sc.h pvmtbl.c 396 | $(CC) $(_CFLAGS) -c -DPSC pvmtbl.c 397 | 398 | pxmalloc.c: xmalloc.c 399 | -$(RM) pxmalloc.c 400 | ${LN} xmalloc.c pxmalloc.c 401 | 402 | # Objects 403 | 404 | abbrev.o: abbrev.c sc.h 405 | $(CC) $(_CFLAGS) ${DFLT_PAGER} -c abbrev.c 406 | 407 | cmds.o: cmds.c sc.h 408 | $(CC) $(_CFLAGS) ${CRYPT} -c cmds.c 409 | 410 | color.o: color.c sc.h 411 | 412 | crypt.o: crypt.c sc.h 413 | $(CC) $(_CFLAGS) ${CRYPT} -c crypt.c 414 | 415 | format.o: format.c 416 | 417 | frame.o: frame.c sc.h 418 | 419 | gram.o: gram.y sc.h $(YTAB).h gram.c sres.sed eres.sed 420 | sed < gram.y > experres.h -f eres.sed 421 | sed < gram.y > statres.h -f sres.sed 422 | $(CC) $(_CFLAGS) ${USELOCALE} -c gram.c 423 | 424 | help.o: help.c sc.h 425 | $(CC) $(_CFLAGS) ${CRYPT} -c help.c 426 | 427 | interp.o: interp.c sc.h 428 | $(CC) $(_CFLAGS) ${FLOAT_STORE} ${IEEE_MATH} \ 429 | ${SIGVOID} ${RINT} ${REGEX} ${FMOD} -c interp.c 430 | 431 | lex.o: sc.h $(YTAB).h gram.o lex.c 432 | $(CC) $(_CFLAGS) ${SIMPLE} ${IEEE_MATH} \ 433 | ${LIBRARY} ${SIGVOID} ${NO_NOTIMEOUT} -c lex.c 434 | 435 | pipe.o: pipe.c sc.h 436 | 437 | pxmalloc.o: pxmalloc.c sc.h 438 | $(CC) $(_CFLAGS) -c -DPSC pxmalloc.c 439 | 440 | qhelp.o: qhelp.c sc.h 441 | $(CC) $(_CFLAGS) ${CRYPT} -c qhelp.c 442 | 443 | range.o: range.c sc.h 444 | 445 | sc.o: sc.c sc.h 446 | $(CC) $(_CFLAGS) ${DFLT_PAGER} ${SIGVOID} \ 447 | ${SAVE} -c sc.c 448 | 449 | screen.o: screen.c sc.h 450 | $(CC) $(_CFLAGS) ${BROKENCURSES} ${IDLOKISBAD} \ 451 | ${RIGHTBUG} ${SIGVOID} ${NO_IDLOK} -c screen.c 452 | 453 | sort.o: sort.c sc.h 454 | 455 | vi.o: vi.c sc.h 456 | $(CC) $(_CFLAGS) ${REGEX} ${HISTORY_FILE} -c vi.c 457 | 458 | # other stuff 459 | 460 | clean: 461 | $(RM) *.o *res.h $(YTAB).h debug core gram.c y.output pxmalloc.c \ 462 | pvmtbl.c qhelp.c tags 463 | 464 | clobber: clean 465 | $(RM) $(name) p$(name) $(name)qref $(name).1 p$(name).1 $(name)qref.1 \ 466 | x$(name) x$(name).1 467 | 468 | distclean: clean 469 | $(RM) $(name) p$(name) $(name)qref x$(name) Makefile config.log \ 470 | $(name).1 p$(name).1 $(name)qref.1 x$(name).1 compat.h 471 | 472 | shar: ${SRC} ${DOCS} 473 | shar -c -m 64000 -f shar ${DOCS} ${SRC} 474 | 475 | sshar: ${SRC} 476 | shar -c -m 1000000 -f shar ${SRC} 477 | 478 | lint: sc.h sc.c lex.c gram.c interp.c cmds.c color.c crypt.c frame.c pipe.c \ 479 | range.c help.c vi.c version.c xmalloc.c format.c vmtbl.c 480 | lint ${LINTFLAGS} $(_CFLAGS) ${SIMPLE} sc.c \ 481 | lex.c gram.c interp.c cmds.c color.c crypt.c frame.c pipe.c \ 482 | range.c help.c vi.c version.c xmalloc.c format.c vmtbl.c \ 483 | $(LDADD) 484 | make lintqref 485 | 486 | lintqref: help.c 487 | lint ${LINTFLAGS} $(_CFLAGS) ${SIMPLE} -DQREF \ 488 | help.c 489 | 490 | lintpsc: psc.c vmtbl.c 491 | lint ${LINTFLAGS} $(_CFLAGS) ${SIMPLE} -DPSC \ 492 | psc.c vmtbl.c 493 | 494 | .SUFFIXES: .doc .1 495 | 496 | .c.o: 497 | $(CC) $(_CFLAGS) -c $< 498 | 499 | .doc.1: 500 | name=$(name) NAME=$(NAME) LIBDIR=$(LIBDIR) SRCDIR=$(SRCDIR) sh $(SRCDIR)/torev $< > $@ 501 | 502 | install: $(EXDIR)/$(name) $(EXDIR)/$(name)qref $(EXDIR)/p$(name) \ 503 | $(LIBDIR)/tutorial.$(name) $(MANDIR)/$(name).$(MANEXT) \ 504 | $(MANDIR)/p$(name).$(MANEXT) $(MANDIR)/$(name)qref.$(MANEXT) \ 505 | $(EXDIR)/x$(name) $(MANDIR)/x$(name).$(MANEXT) 506 | 507 | $(EXDIR)/$(name): $(name) $(EXDIR) 508 | install $(name) $(EXDIR)/ 509 | 510 | $(EXDIR)/$(name)qref: $(name)qref $(EXDIR) 511 | install $(name)qref $(EXDIR)/ 512 | 513 | $(EXDIR)/p$(name): p$(name) $(EXDIR) 514 | install p$(name) $(EXDIR)/ 515 | 516 | $(EXDIR)/x$(name): p$(name) $(EXDIR) 517 | install x$(name) $(EXDIR)/ 518 | 519 | x$(name): xsc.sh 520 | name=$(name) SRCDIR=$(SRCDIR) sh $(SRCDIR)/torev < $< > x$(name) 521 | 522 | $(LIBDIR)/tutorial.$(name): tutorial.sc $(LIBDIR) $(LIBDIR)/plugins 523 | install -m $(MANMODE) tutorial.sc $(LIBDIR)/tutorial.$(name) 524 | 525 | $(EXDIR): 526 | mkdir -p $(EXDIR) 527 | 528 | $(LIBDIR): 529 | mkdir -p $(LIBDIR) 530 | 531 | $(LIBDIR)/plugins: 532 | mkdir -p $(LIBDIR)/plugins 533 | 534 | $(MANDIR): 535 | mkdir -p $(MANDIR) 536 | 537 | $(MANDIR)/$(name).$(MANEXT): $(MANDIR) $(name).1 538 | install -m $(MANMODE) $(name).1 $@ 539 | 540 | $(MANDIR)/p$(name).$(MANEXT): $(MANDIR) p$(name).1 541 | install -m $(MANMODE) p$(name).1 $@ 542 | 543 | $(MANDIR)/x$(name).$(MANEXT): $(MANDIR) x$(name).1 544 | install -m $(MANMODE) x$(name).1 $@ 545 | 546 | $(MANDIR)/$(name)qref.$(MANEXT): $(MANDIR) $(name)qref.1 547 | install -m $(MANMODE) $(name)qref.1 $@ 548 | 549 | uninstall: 550 | $(RM) $(EXDIR)/$(name) 551 | $(RM) $(EXDIR)/$(name)qref 552 | $(RM) $(EXDIR)/p$(name) 553 | $(RM) $(EXDIR)/x$(name) 554 | $(RM) -r $(LIBDIR) 555 | $(RM) $(MANDIR)/$(name).$(MANEXT) 556 | $(RM) $(MANDIR)/p$(name).$(MANEXT) 557 | $(RM) $(MANDIR)/$(name)qref.$(MANEXT) 558 | 559 | files: 560 | @find $(DOCS) $(SRC) -print 561 | -------------------------------------------------------------------------------- /Makefile.in.vpath: -------------------------------------------------------------------------------- 1 | # Makefile $Revision: 7.16 $ 2 | # 3 | # 1) Select the proper EXDIR (path), MANDIR, MANEXT, LIBDIR, SIGVOID, 4 | # REGEX, DFLT_PAGER, and FMOD. Most of the other things aren't 5 | # normally changed (see the comments with each) 6 | # 2) Select the proper machine/compiler/OS section of code 7 | # for MS-DOS look for the pattern 'MS-DOS' 8 | # 3) make install 9 | # 4) If you have the command 'file' that uses /etc/magic add the line: 10 | # 38 string Spreadsheet sc file 11 | 12 | RM ?= rm -f 13 | 14 | # SRCDIR will be filled in by the configure script, either a full or relative path or . 15 | SRCDIR= 16 | VPATH=$(SRCDIR): 17 | 18 | # Specify the name of the program. 19 | # All documentation and installation keys on this value. 20 | # 21 | name=sc 22 | NAME=SC 23 | 24 | # The base directory where everything should be installed. If you're 25 | # packaging this with an O/S, for example, you'll probably want to change 26 | # this to /usr. Otherwise, /usr/local is probably more appropriate, unless 27 | # you're replacing the vendor-supplied version. 28 | prefix=/usr/local 29 | 30 | # This is where the install step puts it. 31 | EXDIR=${prefix}/bin 32 | 33 | # This is where the man page goes. 34 | MANDIR=${prefix}/share/man/man1 35 | MANEXT=1 36 | MANMODE=644 37 | 38 | # This is where the library file (tutorial) goes. 39 | #LIBDIR=/usr/local/share/$(name) # reno 40 | LIBDIR=${prefix}/share/$(name) 41 | LIBRARY=-DLIBDIR=\"${LIBDIR}\" 42 | 43 | # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up 44 | #SIMPLE=-DSIMPLE 45 | SIMPLE= 46 | 47 | # Set BROKENCURSES if your curses has the nl/nonl bug 48 | # if it does and you don't set BROKENCURSES, the display will 49 | # be staggered across the screen. Also try IDLOKBAD below. 50 | #BROKENCURSES=-DBROKENCURSES 51 | BROKENCURSES= 52 | 53 | # Set USELOCALE to enable country-dependent display of decimal points, 54 | # local character recognition in words, and local @date() format. 55 | #USELOCALE= 56 | USELOCALE=-DUSELOCALE 57 | 58 | # Set SIGVOID if signal routines are type void. 59 | # use: SIGVOID=-DSIGVOID for: 60 | # System 5.3, SunOS 4.X, VMS, BSD4.4 (reno), and ANSI C Compliant systems 61 | # use: SIGVOID= for: 62 | # BSD systems (excluding reno, BSD4.4), and the UNIXPC 'cc' 63 | #SIGVOID= 64 | SIGVOID=-DSIGVOID 65 | 66 | # Set IEEE_MATH if you need setsticky() calls in your signal handlers 67 | # 68 | #IEEE_MATH=-DIEEE_MATH 69 | IEEE_MATH= 70 | 71 | # The -ffloat-store compiler option is necessary for compiling interp.c to 72 | # prevent spurious "Still changing after x iterations" errors, intermittent 73 | # problems with the @round function, comparisons failing when they shouldn't, 74 | # and potentially other similar problems due to FPU registers having greater 75 | # precision than doubles in memory. This is known to be necessary for GCC 76 | # on x86 processors/FPUs, and probably others. 77 | #FLOAT_STORE=-ffloat-store 78 | 79 | # Set RINT=-DRINT if you do not have rint() in math.h 80 | # Set RINT= on/with (they have rint): 81 | # SunOS 4.0.3c compiler 82 | # BSD4.4 (reno) 83 | #RINT=-DRINT 84 | RINT= 85 | 86 | # If your system supports POSIX.2 regular expressions, REGEX should be 87 | # set to -DREGCOMP. Otherwise, set REGEX to -DREGCMP if you have the 88 | # regcmp/regex regular expression routines (most System V based systems 89 | # do) or to -DRE_COMP if you have the re_comp/re_exec regular expression 90 | # routines (most BSD based systems do). If your system has no support for 91 | # regular expressions, leave REGEX unset. 92 | #REGEX= 93 | #REGEX=-DREGCMP 94 | #REGEX=-DRE_COMP 95 | REGEX=-DREGCOMP 96 | 97 | # This is the name of a pager like "more". 98 | # "pg" may be appropriate for SYSV. 99 | #DFLT_PAGER=-DDFLT_PAGER=\"more\" # generic && reno 100 | DFLT_PAGER=-DDFLT_PAGER=\"less\" 101 | 102 | # this is the name to save back ups in 103 | SAVE=-DSAVENAME=\"$(NAME).SAVE\" 104 | 105 | # path to crypt, do not define if you don't have crypt 106 | # most systems 107 | #CRYPT=-DCRYPT_PATH=\"/bin/crypt\" 108 | # BSD 109 | # CRYPT=-DCRYPT_PATH=\"/usr/bin/crypt\" 110 | # other people? 111 | #CRYPT=-DCRYPT_PATH=\"/usr/local/bin/crypt\" 112 | 113 | # If you get errors about fmod being undefined when you try to 114 | # compile, then define NO_FMOD (most likely BSD4.3 and Mt Xinu). 115 | #FMOD=-DNO_FMOD 116 | FMOD= 117 | 118 | # buffer size of a single field. It defines the max string length that sc can process. 119 | # The default size is 1024. 120 | FBUF=-DFBUFLEN=10240 121 | #FBUF= 122 | 123 | # If your system doesn't have notimeout() in curses define NONOTIMEOUT 124 | NO_NOTIMEOUT=-DNONOTIMEOUT 125 | #NO_NOTIMEOUT= 126 | 127 | # flags for lint 128 | LINTFLAGS=-abchxv 129 | 130 | # Format of quick reference guide generated by $(name)qref 131 | # Leave undefined for normal text output. 132 | #QREF_FMT= 133 | QREF_FMT=-DTROFF 134 | 135 | # *** SPECIAL NOTES *** 136 | # For ULTRIX: define the BSD4.2 section and SIGVOID above 137 | # tdw@cl.cam.ac.uk tested on Ultrix 3.1C-0 138 | # HP-UX 7.0: Do NOT use -O 139 | # (known broken, try sc's boolean operators if you wish) 140 | # 141 | # **** SYSV curses bugs... **** 142 | # Try setting IDLOKBAD to fix (with an empty spreadsheet): 143 | # a) Redrawing the bottom half of the screen when you 144 | # move between row 9 <-> 10 145 | # b) the highlighted row labels being trash when you 146 | # move between row 9 <-> 10 147 | # c) On an xterm on Esix Rev. D+ from eating lines 148 | # -goto (or move) a few lines (or more) past the bottom 149 | # of the screen, goto (or move) to the top line on the 150 | # screen, move upward and the current line is deleted, the 151 | # others move up even when they should not, check by 152 | # noticing the rows become 2, 3, 40, 41, 42... (etc). 153 | # Known systems/terminfos w/ curses problems: 154 | # {Esix Rev. D+, AT&T SysV3.2.1}:at386-m,xterm, HP-UX7.0:(not sure) 155 | #IDLOKISBAD=-DIDLOKBAD 156 | IDLOKISBAD= 157 | 158 | # If you don't have idlok() in your curses define NOIDLOK 159 | #NO_IDLOK=-DNOIDLOK 160 | NO_IDLOK= 161 | 162 | # If moving right off the screen causes the screen to not redraw 163 | # properly, define RIGHT_CBUG to get around a curses problem on some 164 | # boxes, this forces screen redraws when going right off the screen 165 | #RIGHTBUG=-DRIGHT_CBUG 166 | RIGHTBUG= 167 | 168 | # IF you have problems w/ your yacc try bison, Berkeley yacc, or 169 | # some other yacc. Some systems don't allow you to 170 | # increase the number of terminals (mostly AT&T), SCO's does though. 171 | # YACC=yacc 172 | # NOTE: Do not use with bison 1.16! Get a new version.... 173 | #YACC=bison -y 174 | 175 | # MS-DOS needs y_tab instead of the normal y.tab 176 | #YTAB=y_tab 177 | YTAB=y.tab 178 | 179 | # Command to use to make temporary copies of some source files. 180 | LN=ln -s 181 | #LN=cp 182 | #LN=ln 183 | 184 | #### SYSTEM DEFINES #### 185 | 186 | ######################################### 187 | # Use this for system AIX V3.1 188 | #CFLAGS= -O -DSYSV2 -DCHTYPE=int -DNLS 189 | #LDFLAGS= 190 | #LDADD=-lm -lPW -lcurses 191 | 192 | ######################################### 193 | # Use this for system V.2 (includes: HP-UX 7.05, UNIXPC) 194 | #CFLAGS= -O -DSYSV2 195 | #LDFLAGS= 196 | #LDADD=-lm -lPW -lcurses 197 | # with gcc on a Sequent also use: 198 | #CC=att gcc 199 | #CFLAGS= -DSYSV2 -g -pipe -traditional 200 | 201 | ######################################### 202 | # Use this for system V.3 203 | #CFLAGS= -DSYSV3 -O 204 | #LDFLAGS= -s 205 | #CFLAGS= -DSYSV3 -g 206 | #LDFLAGS= -g 207 | #LDADD=-lm -lncurses -lfl 208 | # with gcc also use: 209 | #CC=gcc 210 | #CFLAGS= -DSYSV3 -O -pipe 211 | # debugging bison (bison 1.16 is broken) 212 | #CFLAGS= -DSYSV3 -g -pipe -traditional 213 | #YACC=bison -y -v -t -l 214 | 215 | ######################################### 216 | # Use this for system V.4 217 | #CFLAGS= -DSYSV4 -DSYSV3 -O 218 | #LDFLAGS= -s 219 | #LDADD=-lm -lcurses -lgen 220 | # with gcc also use: 221 | #CC=gcc 222 | #CFLAGS= -DSYSV3 -O -pipe 223 | 224 | ######################################### 225 | # Microport 226 | #CFLAGS= -DSYSV2 -O -DUPORT -Ml 227 | #LDFLAGS=-Ml 228 | #LDADD=-lm -lcurses -lPW 229 | 230 | ######################################### 231 | # Use this for BSD 4.2 232 | #CFLAGS= -O -DBSD42 233 | #LDFLAGS= 234 | #LDADD=-lm -lcurses -ltermcap 235 | # with gcc also use: 236 | #CC=gcc 237 | 238 | ######################################### 239 | # Use this for Sequent boxes 240 | #CC=atscc 241 | #CFLAGS=-O -DBSD42 242 | #LDFLAGS= 243 | #LDADD=-lm -lcurses -ltermcap 244 | #PSCLIB=-lseq 245 | # with gcc also use: 246 | #CC=gcc 247 | #CFLAGS= -O -DBSD42 -pipe 248 | 249 | ######################################### 250 | # Use this for BSD 4.3 251 | #CFLAGS= -O -DBSD43 #-O or -g 252 | #LDFLAGS= # -lg might help if -g used in CFLAGS 253 | #LDADD=-lm -lcurses -ltermcap 254 | 255 | ######################################### 256 | # Use this for SunOS 4.X if you have the System V package installed. 257 | # This will link with the System V curses which is preferable to the 258 | # BSD curses (especially helps scrolling on slow (9600bps or less) 259 | # serial lines). 260 | # 261 | # Be sure to define SIGVOID and REGEX (to -DRE_COMP) above. 262 | # 263 | #CC=/usr/5bin/cc 264 | #CFLAGS= -O -DSYSV3 265 | #LDFLAGS= 266 | #LDADD=-lm -lcurses 267 | 268 | ######################################### 269 | # Use this for system III (XENIX) 270 | #CFLAGS= -O -DSYSIII 271 | #LDFLAGS= -i 272 | #LDADD=-lm -lcurses -ltermcap 273 | 274 | ######################################### 275 | # Use this for XENIX Version 2.3 276 | #CFLAGS= -O -DSYSIII -DXENIX2_3 277 | #LDFLAGS= -i 278 | #LDADD=-lm -lcurses -ltermcap 279 | 280 | ######################################### 281 | # Use this for VENIX 282 | #CFLAGS= -DVENIX -DBSD42 -DV7 283 | #LDFLAGS= -z -i 284 | #LDADD=-lm -lcurses -ltermcap 285 | 286 | ######################################### 287 | # For SCO Unix V rel. 3.2.0 288 | # -compile using rcc, cc does not cope with gram.c 289 | # -edit /usr/include/curses.h, rcc does not understand #error 290 | # -link: make CC=cc, rcc's loader gets unresolved __cclass, __range 291 | # (rather strange,?) 292 | #CC=rcc 293 | #CC=cc 294 | #CC=gcc -fstrength-reduce 295 | #SIGVOID=-DSIGVOID 296 | #CFLAGS= -O -DSYSV3 297 | #LDFLAGS= 298 | #LDADD=-lm -lcurses -ltinfo -lPW 299 | #YACC=yacc -Sm10000 300 | 301 | ######################################### 302 | # Use this for SCO Unix 3.2.2 and ODT 1.1 303 | #CC=cc 304 | #CFLAGS= -O -DSYSV3 305 | #LDFLAGS= 306 | #LDADD=-lm -lcurses -lPW -lmalloc -lc_s 307 | #YACC=yacc -Sm10000 308 | 309 | ######################################### 310 | # Use this for MS-DOS, Microsoft C 5.1 and NDMAKE 311 | #CC=cl 312 | #CFLAGS= -AL -O -Fo$*.o 313 | #LDFLAGS=/noi /st:0x4000 314 | #LDADD=lcurses 315 | #YACC=bison -y 316 | # 317 | #.SUFFIXES : .o .c 318 | #.c.o: 319 | # $(CC) $(CFLAGS) -c $*.c 320 | 321 | ######################################### 322 | # Use this for MS-DOS with DJGPP 323 | # REGEX should also be undefined (see above) unless a separate REGEX library 324 | # is installed (gdb includes one, but may result in file conflicts with 325 | # existing DJGPP files). 326 | #CC=gcc 327 | # Only use -Wall for testing, since it produces warnings that are of no 328 | # real effect on the reliability of the program, but may concern some 329 | # people who don't understand them. 330 | #CFLAGS=-DSYSV3 -O2 -Wall -UMSDOS 331 | #CFLAGS=-DSYSV3 -O2 -UMSDOS 332 | #LDADD=-lm -lpdcurses 333 | 334 | ######################################### 335 | CPPFLAGS += -I$(SRCDIR) -I. 336 | _CFLAGS= $(CPPFLAGS) $(CFLAGS) $(INCDIR_CURSES) $(DEFINES) $(FBUF) $(__CDBG) $(__CLDBG) \ 337 | #-DTRACE='"/tmp/trace.txt"' 338 | _LDFLAGS=$(LDFLAGS) $(__CLDBG) -s 339 | LDADD=-lm $(LIBDIR_CURSES) $(LIB_CURSES) 340 | 341 | # All of the source files 342 | SRC=Makefile abbrev.c cmds.c color.c crypt.c eres.sed frame.c format.c gram.y \ 343 | help.c interp.c lex.c pipe.c psc.c range.c sc.c sc.h screen.c sort.c \ 344 | sres.sed version.c vi.c vmtbl.c xmalloc.c 345 | 346 | # The objects 347 | OBJS=abbrev.o cmds.o color.o crypt.o format.o frame.o gram.o help.o interp.o \ 348 | lex.o pipe.o range.o sc.o screen.o sort.o version.o vi.o vmtbl.o \ 349 | xmalloc.o compat.o 350 | 351 | # The documents in the Archive 352 | DOCS=CHANGES README sc.doc psc.doc tutorial.sc VMS_NOTES torev build.com 353 | 354 | all: $(name) p$(name) $(name)qref $(name).1 p$(name).1 $(name)qref.1 \ 355 | x$(name) x$(name).1 356 | 357 | $(name):$(PAR) $(OBJS) 358 | $(CC) $(_CFLAGS) ${_LDFLAGS} ${OBJS} $(RPATH_CURSES) -o $(name) \ 359 | ${LDADD} 360 | 361 | # Alternative link for MS-DOS 362 | #$(name): $(OBJS) 363 | # link ${_LDFLAGS} ${OBJS},$(name),,${LDADD}; 364 | 365 | gram.c: gram.y 366 | $(YACC) -d $< 367 | mv $(YTAB).c gram.c 368 | 369 | $(YTAB).h: gram.y 370 | 371 | p$(name): psc.c pvmtbl.o pxmalloc.o version.o 372 | $(CC) $(_CFLAGS) ${_LDFLAGS} -o p$(name) $< \ 373 | pvmtbl.o pxmalloc.o version.o ${PSCLIB} 374 | 375 | # Alternative link for MS-DOS (NB: MSC 5.1 has no getopt.c) 376 | #p$(name): psc.o pvmtbl.o pxmalloc.o getopt.o 377 | # link ${_LDFLAGS} psc.o pvmtbl.o pxmalloc.o getopt.o,p$(name); 378 | 379 | qhelp.c: help.c 380 | -$(RM) qhelp.c 381 | ${LN} $< qhelp.c 382 | 383 | $(name)qref: qhelp.c sc.h 384 | $(CC) $(_CFLAGS) $(_LDFLAGS) -DQREF $(QREF_FMT) \ 385 | -DSCNAME=\"$(NAME)\" -o $(name)qref $< 386 | 387 | # Alternative link for MS-DOS 388 | #$(name)qref: qhelp.c sc.h 389 | # $(CC) -AL -O -Foqhelp.o -c -DQREF -DSCNAME=\"$(name)\" qhelp.c 390 | # link ${_LDFLAGS} qhelp.o,$(name)qref; 391 | 392 | pvmtbl.c: vmtbl.c 393 | -$(RM) pvmtbl.c 394 | ${LN} $< pvmtbl.c 395 | 396 | pvmtbl.o: pvmtbl.c sc.h 397 | $(CC) $(_CFLAGS) -c -DPSC $< 398 | 399 | pxmalloc.c: xmalloc.c 400 | -$(RM) pxmalloc.c 401 | ${LN} $< pxmalloc.c 402 | 403 | # Objects 404 | 405 | abbrev.o: abbrev.c sc.h 406 | $(CC) $(_CFLAGS) ${DFLT_PAGER} -c $< 407 | 408 | cmds.o: cmds.c sc.h 409 | $(CC) $(_CFLAGS) ${CRYPT} -c $< 410 | 411 | color.o: color.c sc.h 412 | 413 | crypt.o: crypt.c sc.h 414 | $(CC) $(_CFLAGS) ${CRYPT} -c $< 415 | 416 | format.o: format.c 417 | 418 | frame.o: frame.c sc.h 419 | 420 | gram.o: gram.y sc.h $(YTAB).h gram.c sres.sed eres.sed 421 | sed < $< > experres.h -f $(filter %eres.sed, $^) 422 | sed < $< > statres.h -f $(filter %sres.sed, $^) 423 | $(CC) $(_CFLAGS) ${USELOCALE} -c $(filter %.c,$^) 424 | 425 | help.o: help.c sc.h 426 | $(CC) $(_CFLAGS) ${CRYPT} -c $< 427 | 428 | interp.o: interp.c sc.h 429 | $(CC) $(_CFLAGS) ${FLOAT_STORE} ${IEEE_MATH} \ 430 | ${SIGVOID} ${RINT} ${REGEX} ${FMOD} -c $< 431 | 432 | lex.o: sc.h $(YTAB).h gram.o lex.c 433 | $(CC) $(_CFLAGS) ${SIMPLE} ${IEEE_MATH} \ 434 | ${LIBRARY} ${SIGVOID} ${NO_NOTIMEOUT} -c $(filter %.c,$^) 435 | 436 | pipe.o: pipe.c sc.h 437 | 438 | pxmalloc.o: pxmalloc.c sc.h 439 | $(CC) $(_CFLAGS) -c -DPSC $< 440 | 441 | qhelp.o: qhelp.c sc.h 442 | $(CC) $(_CFLAGS) ${CRYPT} -c $< 443 | 444 | range.o: range.c sc.h 445 | 446 | sc.o: sc.c sc.h 447 | $(CC) $(_CFLAGS) ${DFLT_PAGER} ${SIGVOID} \ 448 | ${SAVE} -c $< 449 | 450 | screen.o: screen.c sc.h 451 | $(CC) $(_CFLAGS) ${BROKENCURSES} ${IDLOKISBAD} \ 452 | ${RIGHTBUG} ${SIGVOID} ${NO_IDLOK} -c $< 453 | 454 | sort.o: sort.c sc.h 455 | 456 | vi.o: vi.c sc.h 457 | $(CC) $(_CFLAGS) ${REGEX} ${HISTORY_FILE} -c $< 458 | 459 | # other stuff 460 | 461 | clean: 462 | $(RM) *.o *res.h $(YTAB).h debug core gram.c y.output pxmalloc.c \ 463 | pvmtbl.c qhelp.c tags 464 | 465 | clobber: clean 466 | $(RM) $(name) p$(name) $(name)qref $(name).1 p$(name).1 $(name)qref.1 \ 467 | x$(name) x$(name).1 468 | 469 | distclean: clean 470 | $(RM) $(name) p$(name) $(name)qref x$(name) Makefile config.log \ 471 | $(name).1 p$(name).1 $(name)qref.1 x$(name).1 compat.h 472 | 473 | shar: ${SRC} ${DOCS} 474 | shar -c -m 64000 -f shar ${DOCS} ${SRC} 475 | 476 | sshar: ${SRC} 477 | shar -c -m 1000000 -f shar ${SRC} 478 | 479 | lint: sc.h sc.c lex.c gram.c interp.c cmds.c color.c crypt.c frame.c pipe.c \ 480 | range.c help.c vi.c version.c xmalloc.c format.c vmtbl.c 481 | lint ${LINTFLAGS} $(_CFLAGS) ${SIMPLE} \ 482 | $(filter %.c,$^) \ 483 | $(LDADD) 484 | make lintqref 485 | 486 | lintqref: help.c 487 | lint ${LINTFLAGS} $(_CFLAGS) ${SIMPLE} -DQREF \ 488 | help.c 489 | 490 | lintpsc: psc.c vmtbl.c 491 | lint ${LINTFLAGS} $(_CFLAGS) ${SIMPLE} -DPSC \ 492 | psc.c vmtbl.c 493 | 494 | .SUFFIXES: .doc .1 495 | 496 | .c.o: 497 | $(CC) $(_CFLAGS) -c $< 498 | 499 | .doc.1: 500 | name=$(name) NAME=$(NAME) LIBDIR=$(LIBDIR) SRCDIR=$(SRCDIR) sh $(SRCDIR)/torev $< > $@ 501 | 502 | install: $(EXDIR)/$(name) $(EXDIR)/$(name)qref $(EXDIR)/p$(name) \ 503 | $(LIBDIR)/tutorial.$(name) $(MANDIR)/$(name).$(MANEXT) \ 504 | $(MANDIR)/p$(name).$(MANEXT) $(MANDIR)/$(name)qref.$(MANEXT) \ 505 | $(EXDIR)/x$(name) $(MANDIR)/x$(name).$(MANEXT) 506 | 507 | $(EXDIR)/$(name): $(name) $(EXDIR) 508 | install $(name) $(EXDIR)/ 509 | 510 | $(EXDIR)/$(name)qref: $(name)qref $(EXDIR) 511 | install $(name)qref $(EXDIR)/ 512 | 513 | $(EXDIR)/p$(name): p$(name) $(EXDIR) 514 | install p$(name) $(EXDIR)/ 515 | 516 | $(EXDIR)/x$(name): p$(name) $(EXDIR) 517 | install x$(name) $(EXDIR)/ 518 | 519 | x$(name): xsc.sh 520 | name=$(name) SRCDIR=$(SRCDIR) sh $(SRCDIR)/torev < $< > x$(name) 521 | 522 | $(LIBDIR)/tutorial.$(name): tutorial.sc $(LIBDIR) $(LIBDIR)/plugins 523 | install -m $(MANMODE) tutorial.sc $(LIBDIR)/tutorial.$(name) 524 | 525 | $(EXDIR): 526 | mkdir -p $(EXDIR) 527 | 528 | $(LIBDIR): 529 | mkdir -p $(LIBDIR) 530 | 531 | $(LIBDIR)/plugins: 532 | mkdir -p $(LIBDIR)/plugins 533 | 534 | $(MANDIR): 535 | mkdir -p $(MANDIR) 536 | 537 | $(MANDIR)/$(name).$(MANEXT): $(MANDIR) $(name).1 538 | install -m $(MANMODE) $(name).1 $@ 539 | 540 | $(MANDIR)/p$(name).$(MANEXT): $(MANDIR) p$(name).1 541 | install -m $(MANMODE) p$(name).1 $@ 542 | 543 | $(MANDIR)/x$(name).$(MANEXT): $(MANDIR) x$(name).1 544 | install -m $(MANMODE) x$(name).1 $@ 545 | 546 | $(MANDIR)/$(name)qref.$(MANEXT): $(MANDIR) $(name)qref.1 547 | install -m $(MANMODE) $(name)qref.1 $@ 548 | 549 | uninstall: 550 | $(RM) $(EXDIR)/$(name) 551 | $(RM) $(EXDIR)/$(name)qref 552 | $(RM) $(EXDIR)/p$(name) 553 | $(RM) $(EXDIR)/x$(name) 554 | $(RM) -r $(LIBDIR) 555 | $(RM) $(MANDIR)/$(name).$(MANEXT) 556 | $(RM) $(MANDIR)/p$(name).$(MANEXT) 557 | $(RM) $(MANDIR)/$(name)qref.$(MANEXT) 558 | 559 | files: 560 | @find $(DOCS) $(SRC) -print 561 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a much modified version of the public domain spread sheet sc, 2 | originally by James Gosling, and posted a number of years ago by Mark 3 | Weiser as vc. 4 | 5 | The current maintainer is Chuck Martin (nrocinu@myrealbox.com). I 6 | originally got involved with sc because I wanted a good text-based 7 | spreadsheet program, and nothing I could find seemed to suit my needs. 8 | After looking at several different programs, I settled on sc as the 9 | program with the most promise, especially since source code was available, 10 | which meant I could modify it to add the features I needed. Since it 11 | appeared that no one was maintaining it anymore, I decided to take up the 12 | cause myself, although I don't want to claim ownership of the program. I 13 | would like to thank those who have made their own contributions to making 14 | sc a better program. 15 | 16 | I apologize for taking so long to release this version. I've been wanting 17 | to do it for quite some time, but have been holding off until I could find 18 | the time to update the documentation properly, and other responsibilities 19 | have prevented me from doing that until recently. On the bright side, 20 | this version has been in use more extensively, and I believe it to be 21 | more stable and bug-free than any previous version. 22 | 23 | The CHANGES file lists the changes from 6.1 to 7.16. Although I've 24 | already added all of the "must have" features I needed, and then some, 25 | I'm willing to continue maintaining sc for as long as I'm able, and I'll 26 | certainly share any new features and bugfixes I come up with. If anyone 27 | else finds any bugs or would like to contribute patches, please send them 28 | to me. If they're useful and they work, I'll probably add them. I prefer 29 | to keep it simple, though, since that's what drew me to sc instead of some 30 | other "full-featured" spreadsheet in the first place. I like the Unix 31 | philosophy of making each program do one thing and do it well, and would 32 | rather leave all the fancy graphics and other features to other programs 33 | that are better suited for them. 34 | 35 | Many of the items in the TODO list were there before I took over maintaining 36 | sc, and although I won't be adding those features myself, I left them in 37 | the list in case someone else still wants to add them. I've added undo to 38 | the TODO list because I feel it is a much needed feature, but I won't make 39 | any promises as to when (or if) I will get to it. If anyone else would 40 | like to tackle it, feel free to do so. 41 | 42 | I've tried to avoid changing key bindings any more than necessary because 43 | it could be confusing to people who have been using sc for years if the 44 | keybindings suddenly change, but in version 7.13, I finally decided to 45 | change a few things for more compatibility with vi, so that it will be 46 | easier to move back and forth between the two programs. For example, 47 | the ^F and ^B keys now work like J and K (or PageDown/PageUp). Also, 48 | the " key is no longer used for entering centered labels, but for named 49 | delete buffers instead, as it does in vi. The \ key will take its place 50 | for entering centered labels. This will also make it easier to enter a 51 | so-called "wheel" for filling a cell with a character or string, since 52 | you'll begin such a string by pressing \ twice. Also, most keyboards have 53 | the "\" and "|" on the same key, which should make it easy to remember 54 | because | is already used for centering an existing string. I'm sure 55 | someone will let me know if this causes any problems. :) 56 | 57 | In version 7.16, I've added a few more changes in sc's key bindings. 58 | For one, the range commands now all begin with "r" instead of "/" because 59 | I intend to add a new search feature that will be more powerful than the 60 | goto command, and I want to use "/" for that feature. Also, "n" is now 61 | used to repeat the last search (the last goto, for now, but that will 62 | change when the new search feature is implemented). Since that conflicts 63 | with the former usage of "n", which was for the note commands, these 64 | commands now all begin with "*", and following a link to a note now 65 | requires that "*" be pressed twice in succession. 66 | 67 | I've started an announcement-only mailing list for those who would like 68 | to find out when new versions of sc are available. If anyone is interested 69 | in being added to this list, please let me know. This will not be an 70 | automated list. Everything will be done manually, and all names will be 71 | put in a "Bcc:" header, so there will be no danger of being added to 72 | someone's spam list. 73 | 74 | 75 | Problems with color: 76 | 77 | I'm no longer running ncurses 1.9.9g on any of my machines or machines 78 | I work with, since it seems to have bugs in the handling of color that 79 | I've been unable to find a work-around for, and upgrading to the latest 80 | version seems to eliminate them. If anyone else finds a way to work 81 | around these bugs, patches are welcome. 82 | 83 | If you have a problem getting highlighting to work when color is enabled, 84 | you may want to check the value of ncv in your terminfo file (this can 85 | be checked with the "tput ncv" command at the shell prompt). This value 86 | should be an even number in order for standout mode to work. If ncv is 87 | odd, try subtracting one and recompiling. See the man pages for tic and 88 | infocmp for how to do this. The linux terminfo file in some older versions 89 | of ncurses is known to have this problem, for example. I've also found the 90 | problem in some versions of the terminfo files for xterm and screen. 91 | 92 | 93 | Compiling the program: 94 | 95 | Before you compile, make sure to check the Makefile and uncomment the 96 | lines that pertain to your system and comment out the lines for Linux. 97 | If you run Linux, this step won't be necessary, since that's the default 98 | (since that's what I run). I haven't tried compiling or running sc on 99 | anything else, but I've used it on both Slackware 4.0 (with ncurses upgraded 100 | to version 5.2) and Slackware 7.1, so I hope I haven't broken anything for 101 | anyone else. If you get it to compile and run on something else, please 102 | let me know. If it doesn't work and you can fix it, please send me a patch. 103 | 104 | 105 | A couple of notes from the previous maintainer: 106 | 107 | 1) If you have problems with lex.c, and don't care about arrow keys, define 108 | SIMPLE (-DSIMPLE in the makefile). SIMPLE causes the arrow keys to not 109 | be used. 110 | 111 | 2) If you have problems with your yacc saying: too many terminals ...127... 112 | find a different yacc: bison, Berkeley yacc, Pd yacc, etc. AT&T's Sys V 113 | yacc has small, fixed sized tables. SCO will allow dynamic yacc tables 114 | when given the correct flags. 115 | 116 | 117 | After you get it built, if you aren't familiar with sc, you might want 118 | to try "sc tutorial.sc" for a simple introduction to the basic commands. 119 | Most of the key bindings are patterned after the vi text editor, so if 120 | you're familiar with that program or its variants, you shouldn't have 121 | any problems learning sc. The tutorial is a bit out-of-date, and doesn't 122 | include any of the new features that have been added since I began 123 | maintaining sc. If anyone would like to rectify this situation, feel 124 | free. The same goes for the built-in help system (available by pressing 125 | `?'), although the feature list has grown quite a bit, and that may not be 126 | easy to do without some major changes to the way the help system works. 127 | 128 | If you've used sc before, you may want to check out the CHANGES file 129 | to see what's changed, and read the man page for more details. 130 | 131 | To print a quick reference card, type the command: 132 | scqref | [your_printer_commmand] 133 | 134 | If you have the command 'file' that uses /etc/magic, and it isn't there 135 | already, you may want to add the following lines: 136 | 137 | # sc: file(1) magic for "sc" spreadsheet 138 | # 139 | 38 string Spreadsheet sc spreadsheet file 140 | 141 | Psc formats ascii files for use in the spreadsheet. If you don't have 142 | getopts, there is a public domain version by Henry Spencer hidden away in 143 | the VMS_NOTES file. 144 | 145 | If you'd like to rename the program to something different, just change 146 | "name=sc" and "NAME=SC" to "name=myfavoritename" and "NAME=MYFAVORITENAME" 147 | and try "make myfavoritename". (Does anyone need or use this? If so, 148 | please let me know. Otherwise, I may remove that capability in a future 149 | version, since it seems to me that it reduces confusion if everyone 150 | refers to the program by the same name. (I've been told that there is a 151 | program called Sunshine Commander that used the same name, but I may still 152 | drop this, since the sc Spreadsheet Calculator is much more well known)). 153 | 154 | Similarly, you can make the documentation with "make myfavoritename.man". 155 | "make install" will make and install the code in EXDIR. The installation 156 | steps and documentation all key off of the name. The makefile even changes 157 | the name in the nroffable man page. If you don't have nroff, you will 158 | have to change sc.man yourself. 159 | 160 | Uninstalling the program is now very easy, if you should want to do this. 161 | Just do "make uninstall". 162 | 163 | 164 | Finding the latest version: 165 | 166 | You should be able to ftp the lastest version of sc from ibiblio.org 167 | The directory where you should be able to find the latest version is 168 | /pub/Linux/apps/financial/spreadsheet. If you can't find it, e-mail me. 169 | I know this is a Linux specific source, but it's the only place I know 170 | of. If anyone knows of a more O/S-neutral location, please let me know. 171 | 172 | 173 | Guarantee: 174 | 175 | Since some people are wary of using a program that has no guarantee, I've 176 | decided to provide the following guarantee: 177 | 178 | It is a well-known fact that any non-trivial program has bugs. If 179 | you haven't found them, you just haven't stumbled upon the proper 180 | combinations of actions that will cause the bugs to manifest them- 181 | selves. Since sc stands for "Spreadsheet Calculator", and since a 182 | spreadsheet calculator is by definition a non-trivial program, sc is 183 | guaranteed to have bugs. 184 | 185 | 186 | Chuck Martin 187 | nrocinu@myrealbox.com 188 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### sc Spreadsheet Calculator 2 | 3 | `sc` is a free curses-based spreadsheet program that uses key bindings similar to vi and less. 4 | For more information on `sc` please see the 5 | [`README`](https://github.com/n-t-roff/sc/blob/master/README) 6 | file. 7 | This is a fork of the latest source code version 7.16 from September 2002 8 | which can be found at 9 | [http://www.ibiblio.org/pub/Linux/apps/financial/spreadsheet/sc-7.16.tar.gz](http://www.ibiblio.org/pub/Linux/apps/financial/spreadsheet/sc-7.16.tar.gz). 10 | The following 11 | [changes](https://github.com/n-t-roff/sc/blob/master/CHANGES-git) 12 | had been made: 13 | 14 | * Many bugs had been found, all of them are fixed now. 15 | (For reporting bugs please use the 16 | [issue list](https://github.com/n-t-roff/sc/issues).) 17 | * All `gcc` and most `clang` `-Wall` and `-Werror` compiler warnings fixed. 18 | * Made `UBSAN` and `ASAN` clean. 19 | * All `sprintf`, `strcpy`, and `strcat` replaced 20 | with `snprintf`, `strlcpy`, and `strlcat`. 21 | * `./configure` script added and tested on BSD, 22 | Linux, and Solaris. 23 | 24 | Functional extensions: 25 | 26 | * By default `sc` made a backup of the database file 27 | before overwriting it. 28 | This could only be changed at compile time. 29 | There are now options `backup` and `!backup` to control this. 30 | * Configured at compile time, `sc` always did update the history 31 | file `~/.sc_history`. 32 | It is now possible to change this filename with the `.scrc` 33 | command `histfile` or save no history at all with an empty 34 | command argument. 35 | * Command `set mouse` (e.g. in `.scrc`) enables 36 | 37 | * Selecting cells with the left mouse button 38 | * Vertical scrolling with the mouse wheel 39 | * Selecting the edit line position with the left mouse button 40 | 41 | (In this case the shift key needs to be pressed for 42 | ‘cut and paste’. 43 | All `sc` functions work well with NetBSD and Solaris curses 44 | but using the mouse requires ncurses. 45 | Using the mouse _wheel_ additionally requires 46 | ncurses version ≥ 6.) 47 | 48 | #### Documentation 49 | 50 | Documentation is provided in short form integrated in `sc` 51 | accessible with the `?` key. 52 | A complete documentation is available as a 53 | [manual page](https://github.com/n-t-roff/sc/blob/master/sc.doc). 54 | For better navigation 55 | [HTML](http://n-t-roff.github.io/sc.1.html) 56 | and 57 | [PDF](http://n-t-roff.github.io/sc.1.pdf) 58 | versions with table of contents and hyperlinks had been 59 | created (using the 60 | [-man](http://n-t-roff.github.io/heirloom/doctools/man.7.html) 61 | macros of 62 | [Heirloom troff](http://n-t-roff.github.io/heirloom/doctools.html)). 63 | 64 | #### Getting the source 65 | 66 | The source can be cloned with 67 | ```sh 68 | git clone https://github.com/n-t-roff/sc.git 69 | ``` 70 | and updated later with 71 | ```sh 72 | git pull 73 | ``` 74 | #### Compiling and Installation 75 | 76 | Defaults for compiling and installation are set in the 77 | [`Makefile.in`](https://github.com/n-t-roff/sc/blob/master/Makefile.in). 78 | A system dependent makefile is generated with 79 | ```sh 80 | ./configure 81 | ``` 82 | If you'd like to do an out-of-source build, and your version of make supports VPATH (eg GNU make) 83 | then you can do the following: 84 | ```sh 85 | cd /path/to/obj 86 | /path/to/source/configure # (full or relative path) 87 | ``` 88 | The source is compiled with 89 | ```sh 90 | make 91 | ``` 92 | (the `curses` or `ncurses` header files need to be installed, 93 | else `make` failes). 94 | 95 | If `make` failes it may be possible that `./configure` did not work 96 | correctly with the installed `/bin/sh`. 97 | If `ksh` is installed in such cases using 98 | ```sh 99 | make distclean 100 | ksh configure 101 | make 102 | ``` 103 | can solve the problem. 104 | (Alternatively `sh` in `configure`s first line can be changed to `ksh`.) 105 | 106 | The result is installed with 107 | ```sh 108 | make install 109 | ``` 110 | to the base directory `/usr/local`. 111 | This path can be changed in the 112 | [`Makefile.in`](https://github.com/n-t-roff/sc/blob/master/Makefile.in). 113 | All generated files are removed with 114 | ```sh 115 | make distclean 116 | ``` 117 | A new target, `clobber`, has been added, which removes all `make` generated targets (not the Makefile nor other `configure` output) 118 | ```sh 119 | make clobber 120 | ``` 121 | The package can be uninstalled with 122 | ```sh 123 | make uninstall 124 | ``` 125 | -------------------------------------------------------------------------------- /SC.MACROS: -------------------------------------------------------------------------------- 1 | One of the coolest features new to sc 7.3 is the ability to write advanced 2 | macros in your favorite language. I haven't had time to document this 3 | feature properly (I'm hoping to do a separate man page), but until I can, 4 | I decided to write a basic overview of how this feature works, and let 5 | people experiment with it. Any comments, questions, or suggestions are 6 | welcome. 7 | 8 | Basically, the way the new macros appear to sc is no different than the 9 | old style macros, apart from the additional commands. On the other side, 10 | however, they are as different as night and day. The old style macros are 11 | basically just text files containing sc commands in the same form that they 12 | would be stored in a plain spreadsheet file. There is no difference between 13 | reading a macro file and reading a spreadsheet file, and they can both 14 | contain the same commands. This is very limiting because there is no way 15 | to create a loop or branch to another part of the macro or execute certain 16 | commands only under specific conditions. 17 | 18 | Advanced macros allow you to do all this and more. An advanced macro is 19 | nothing more than an executable program that outputs sc commands on stdout 20 | and reads information back in on stdin. All decision-making, looping, etc. 21 | is done within the macro program, rather than within sc. This means that 22 | you have all the power of whatever language you prefer when programming 23 | macros. 24 | 25 | A few additional commands have been added to request specific data from 26 | sc. I call these "pipe commands", since they cause sc to pipe data back 27 | to the macro program. The pipe symbol (|) that used to precede these 28 | commands is no longer necessary, starting with version 7.13. The command 29 | is echoed or printed to stdout, and the result is read from stdin in the 30 | form of a newline-terminated string. If the result contains multiple 31 | values, they will be separated by spaces. Most of these commands take an 32 | optional argument specifying a cell or column you are requesting information 33 | from. If this argument is missing, the current cell or column will be used. 34 | 35 | A few more commands have been added to do things that are easily done from 36 | the keyboard, but which previously had no specific commands that could be 37 | used to do them from a macro file. These include such things as moving 38 | around the spreadsheet using h, j, k, l, or the cursor control keys, or 39 | forcing recalculation of the spreadsheet using @. Here is a list of the 40 | new commands, along with a description of each one: 41 | 42 | 43 | Pipe Commands: 44 | -------------- 45 | 46 | whereami 47 | 48 | This command tells sc that you would like to know where you currently 49 | are in the spreadsheet. The response will be the address of the cur- 50 | rent cell followed by the address of the cell in the upper left-hand 51 | corner of the screen, separated by a space. If this line is appended 52 | to the string "goto ", it can be used to restore the cell cursor to 53 | its original position. It can also be parsed to find out which row 54 | and column you're in, which can be used for whatever purpose you want. 55 | 56 | getnum 57 | 58 | This command tells sc that you would like the number contained in a 59 | given cell. Each cell in sc can contain both a numeric portion and a 60 | string portion, and one of those, but not both, can be in the form of 61 | an expression. This command requests the numeric portion. If the 62 | numeric portion is an expression, this will return the calculated 63 | value, rather than the expression. The result will be returned in the 64 | form of a newline terminated string formated with "%.15g", which is 65 | the same format that is used to store a numeric value in a spreadsheet 66 | file, unless it's in the form of an expression (remember, sc files are 67 | text files). When followed by a cell address (e.g., `getnum b23'), 68 | it will return the number from that cell. Specifying a range instead 69 | will return the number from each cell in the range, one row per line, 70 | with the values separated by tabs (an empty cell will be represented 71 | by two consecutive tabs with nothing between). With no arguments, 72 | the number from the current cell will be returned. If a cell contains 73 | an error, the string "ERROR" or "INVALID" will be returned. 74 | 75 | fgetnum 76 | 77 | This command works exactly like getnum, except that the format used 78 | to return the value is the same as that used to format it for display 79 | on the screen. In other words, if the cell uses a date format, a date 80 | will be returned. If the cell is formatted for scientific notation, 81 | that's what you'll get back. The only exception is that if the for- 82 | matted result happens to be wider than the cell, you won't get a string 83 | of *'s back. Instead, you'll get a result that is wider than the cell 84 | it's contained in. Like getnum, you can use this by itself to get the 85 | number from the current cell, or with a cell address or range as an 86 | argument. If a cell contains an error, the string "ERROR" or "INVALID" 87 | will be returned. 88 | 89 | getstring 90 | 91 | Like getnum and fgetnum above, this command requests data from sc. 92 | However, what is requested (and returned) is the string portion of 93 | the cell. If the string portion of the cell is an expression, it will 94 | be evaluated, and the result of that evaluation will be returned. 95 | getstring may be used to get the data from the current cell or from 96 | a specified cell or range, just like getnum and fgetnum above. 97 | 98 | getexp 99 | 100 | If either the numeric portion or the string portion of a cell is in the 101 | form of an expression, this will return that expression. 102 | 103 | getformat 104 | 105 | This command will return a string containing the three numeric values 106 | that specify the format of the given column, or the current column if 107 | none is given. This is the format specified by the f (format) command. 108 | 109 | getfmt 110 | 111 | This command will return the format string for the specified cell 112 | (or cells, if a range is specified), or for the current cell if no 113 | arguments are given. This is the format specified by the F (fmt) 114 | command. It may be either a standard numeric format or a date format. 115 | 116 | getframe 117 | 118 | This command will return the outer and inner ranges, respectively, 119 | of the framed range containing either the specified cell, if given, 120 | or the current cell, otherwise, separated by a space. If the cell 121 | is not inside a framed range, an empty string will be returned (in 122 | other words, just a lone newline). 123 | 124 | getrange 125 | 126 | This command takes a string argument and checks to see if a named range 127 | exists with that name. If it does, the actual range is returned. 128 | Otherwise, an empty string is returned. 129 | 130 | status 131 | 132 | This command will return a set of flags to show information about 133 | the current state of the program or the file. Currently, there are 134 | three flags implemented: 135 | 136 | m If the string returned contains an `m', the file currently 137 | in memory has been modified. If no `m' is present, the 138 | file has not been modified. 139 | 140 | i If the string returned contains an `i', stdin is currently 141 | connected to a terminal. Otherwise, stdin has been redirected 142 | to a file or pipe. 143 | 144 | o If the string returned contains an `o', stdout is currently 145 | connected to a terminal. Otherwise, stdout has been re- 146 | directed to a file or pipe. 147 | 148 | query 149 | 150 | This command can be used to obtain information from the user. An 151 | optional string argument will be displayed on the second line of 152 | the display to ask the user a question or present an informational 153 | message. For example, 'query "Please enter today's sales."' will 154 | display the message on the second line, and wait for the user to 155 | enter the appropriate information on the top line. If a second 156 | string argument is present, it will be used as a default response 157 | which the user can accept as is, or edit. The user may switch 158 | from insert mode to edit mode, navigate mode, etc., and may use any 159 | of the vi-style editing commands or operations that are available 160 | during input of regular sc commands, including the use of the 161 | command line history. 162 | 163 | getkey 164 | 165 | This command can be used to get a single key from the user. For 166 | special keys, such as Insert, Delete, function keys, cursor keys, 167 | etc., a NULL character will be returned, followed by a newline- 168 | terminated string naming the key that was pressed. This name is 169 | the same as that found in curses.h with the "KEY_" prefix and any 170 | embedded parentheses removed. For example, the cursor right key 171 | is "RIGHT", the Insert key is "IC", and the F4 function key is "F4". 172 | 173 | error 174 | 175 | Displays a specified string on the second line of the display. The 176 | string argument is required, but may be empty (""). This command 177 | is intended for displaying error messages from a macro, but may be 178 | used to display other informative messages as well. 179 | 180 | eval 181 | 182 | This can be used to send an expression directly to sc for evaluation 183 | without entering it into a cell. An optional second parameter can 184 | be used to specify formatting information. For example, the following 185 | line could be used in a shell script: 186 | 187 | echo eval a49-c53 \"0.00\" 188 | 189 | You can then read the result in from standard input. If you want to 190 | know the number of the current column without having to convert the 191 | column name yourself, you can let sc do it for you by sending the 192 | command "eval @mycol" and reading the answer back from sc. You can 193 | also use this in non-macro shell scripts. For example, the following 194 | line could be used to calculate the area of a circle to four decimal 195 | places: 196 | 197 | AREA=`echo eval @pi*$RADIUS^2 \"0.0000\" | sc -q` 198 | 199 | seval 200 | 201 | This works like eval, except that it evaluates string expressions 202 | instead of numeric expressions. For example, the following line 203 | could be used in a shell script to convert a column number to its 204 | name (e.g., 5 would be converted to F): 205 | 206 | echo "seval @coltoa($COLNUM)" 207 | 208 | The quotes are necessary in this case to prevent the shell from 209 | using the parentheses for its own purposes. 210 | 211 | 212 | Other Commands: 213 | --------------- 214 | 215 | up 216 | down 217 | left 218 | right 219 | 220 | These do just what you would expect. They move the cell cursor in 221 | the specified direction. You can also use an optional numeric argu- 222 | ment to move the specified number of cells in the given direction. 223 | For example, `down 7' will take you to the cell seven rows below the 224 | current cell. 225 | 226 | endup 227 | enddown 228 | endleft 229 | endright 230 | 231 | These also do what you would expect. For example, if you're in the 232 | middle of a long column of data, and you would like to jump to the 233 | bottom of the column, but you don't know where the column ends, using 234 | the enddown command will take you there. This works exactly like the 235 | END key (or ^E) followed by a cursor movement key. 236 | 237 | insertrow 238 | insertcol 239 | openrow 240 | opencol 241 | deleterow 242 | deletecol 243 | yankrow 244 | yankcol 245 | 246 | These commands insert, delete, or yank rows or columns, just as if 247 | the user had pressed `i', `o', `d', or `y'. If you want to insert, 248 | delete, or yank more than one row or column, follow the command with 249 | `*' and a number; e.g. `insertrow * 5' will insert five rows before 250 | the current row. 251 | 252 | pull 253 | pullmerge 254 | pullrows 255 | pullcols 256 | pullxchg 257 | pulltp 258 | pullfmt 259 | pullcopy 260 | 261 | These commands pull cells (or parts of cells in the case of the 262 | pullfmt command) from the delete buffer into the current location 263 | in the spreadsheet. They perform the same actions as the `pp' (pull), 264 | `pm' (pullmerge), `pr' (pullrows), `pc' (pullcols), `px' (pullxchg), 265 | `pt' (pulltp), `pf' (pullfmt), and `pC' (pullcopy) user commands. 266 | 267 | leftjustify 268 | rightjustify 269 | center 270 | 271 | These commands are used to justify or center the string(s) in a cell 272 | or range of cells. With no argument, all strings in the currently 273 | highlighted range, if one is highlighted, or the current cell, if not, 274 | will be justified/centered. Otherwise, a cell or range may be given 275 | as a single argument, which will define which strings are to be 276 | justified or centered. 277 | 278 | select 279 | 280 | This command takes a single string argument, whose first character 281 | is used to select a named buffer to be used for the next insertion, 282 | deletion, yank, or pull. It is the same as the interactive `"' 283 | command. 284 | 285 | recalc 286 | 287 | This works like the @ command. It forces recalculation of the 288 | spreadsheet. Note that automatic recalculation is turned off tem- 289 | porarily while executing a macro (for speed), so you will need to 290 | use this command if you want to present current data to the user 291 | before the macro is complete. You will also need to use the redraw 292 | command to write the recalculated data to the screen. Since recal- 293 | culation is turned back on after the macro is complete, this command 294 | will not be necessary at the end of a macro. 295 | 296 | redraw 297 | 298 | This command works like ^L, and redraws the screen. You may have 299 | to use the recalc command first if you want the data to be current. 300 | Note that screen updates are not performed during macros (for speed), 301 | so you'll have to use this command if the data have changed in any way, 302 | and you want the user to see those changes. If your macro writes 303 | directly to the screen at any time to display messages or otherwise 304 | interact with the user, you will need to use this command to restore 305 | the spreadsheet to the screen when the macro ends. 306 | 307 | quit 308 | 309 | This command causes sc to immediately exit. It does not prompt the 310 | user for confirmation or ask if the data should be saved if it has 311 | been modified. You will need to do that from the macro, if necessary. 312 | Use this command with caution. 313 | 314 | 315 | Now that you understand the new commands (and hopefully the old ones, too, 316 | although you'll have to figure those out on your own; hint: watch the top 317 | of the screen as you enter data and execute other commands, and look at 318 | the contents of a few spreadsheet files), a few hints are in order. 319 | 320 | First, it is perfectly okay to write directly to the screen, although, 321 | since stdin and stdout have been redirected, you'll have to use another 322 | method of doing this. From a shell script, for example, you can redirect 323 | stdin and/or stdout to /dev/tty on a command by command basis. Remember 324 | that even a command like clear sends special codes to do its job, so you'll 325 | need to use redirection to make it work. For example, to clear the screen, 326 | use `clear >/dev/tty'. 327 | 328 | If you have the dialog or cdialog program, you can use these to interact 329 | with the user. Just redirect stdin and stdout with `<>/dev/tty' for each 330 | dialog command (or what might be better is to open a file descriptor once 331 | with something like `exec 3<> /dev/tty' and use that for communicating 332 | with the user). You can also use the tput, echo, and read commands with 333 | redirection to read and write the top two lines of the screen for inter- 334 | action with the user. For example, `(tput cup 0 0; tput el) >/dev/tty' 335 | will position the cursor on the top line and clear the line. You can then 336 | use the echo and read commands to ask the user a question and read the 337 | answer. Just remember to redraw the screen after using any commands 338 | that write directly to the screen (now that the query command has been 339 | implemented, you probably won't be doing it this way, but the capability 340 | is there, anyway). 341 | 342 | Although the examples above are for shell scripts, similar methods can be 343 | used from any language. I'll leave the exact implementation for various 344 | other languages as an exercise for the reader. 345 | 346 | Testing macros outside of sc in most cases is very easy, since they read 347 | and write stdin and stdout. All you have to do is run the program and 348 | feed it information from the keyboard that it would otherwise get from 349 | sc. 350 | 351 | Once you've written and tested your macro, you can try it from within sc. 352 | Make sure the file is executable, and then use the R command to run it. 353 | Make sure you precede the name with a `|'. You can use D to define 354 | the macro directory, although this no longer needs to actually be a 355 | directory. It can be the name of your macro file, including the path, 356 | preceded by a `|' so that it will be executed as a program. If you 357 | include a trailing space, you can then add command line arguments or 358 | options when running it with R. This allows you to include several 359 | macros in the same file, and use the command line to determine which 360 | macro to run. Alternatively, you could use the whereami command to 361 | determine where the user is at in the spreadsheet, and run a different 362 | macro depending on which region of the spreadsheet the macro is being 363 | run from. Use your imagination. 364 | 365 | Since the macro is a program, you can import data from any source you 366 | want. You could get information from the Internet, read it from custom 367 | hardware connected to the serial or parallel port (or your own custom 368 | interface), or pull it from a file created by another program. You 369 | could cause your macro to react to the phase of the moon or whether the 370 | date is even or odd, if you want (although your users might not like 371 | that very well). Basically, you can do anything you want. I'd be 372 | interested in hearing of some creative uses of macros. 373 | 374 | Here's some additional information about the pipe commands. Although it 375 | is no longer necessary to include the pipe symbol at the beginning of the 376 | "pipe" commands, you may still append it to any of these commands, 377 | follosed by file descriptor as before (e.g. `whereami | fd', where fd is 378 | a file descriptor). I've used this for testing by using a file descriptor 379 | of 1, which will write the information to the screen, or a file descriptor 380 | of 2, which will write the information to stderr, which I then redirect 381 | to another virtual terminal or a file. This may also be used in a pipe- 382 | line to pass data from sc on to the next command (or to a file, through 383 | redirection). For example, if you create an sc spreadsheet on the fly 384 | and pipe it to sc, you could add the following lines to the end of the 385 | spreadsheet: 386 | 387 | getfnum D49:G73 | 1 388 | quit 389 | 390 | This will cause the formatted numeric data from the range D49:G73 to be 391 | piped to the next command, tab-delimited, one row per line. Also, if 392 | you're using simple macros (the old-style "list of sc commands in a text 393 | file"), no pipes are created, and the default file descriptor for the pipe 394 | commands is 1 (or stdout). Make sure you include the quit command, or sc 395 | will become interactive after receiving all of the data from the pipeline. 396 | 397 | If anyone finds another use for this way of using the pipe commands, 398 | please let me know, and I'll add it to the documentation in the next 399 | version. 400 | 401 | I'm hoping to eventually include better documentation for macros, preferably 402 | in a man page. In the meantime, enjoy the new capability, and send me any 403 | comments or suggestions for the next release. 404 | 405 | Chuck 406 | nrocinu@myrealbox.com 407 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | todo: 3 | 1) autobackup of things typed in. 4 | idea: each cell change output to a stdio open file 5 | in the save format, fflush() every so often... 6 | (diffs w/r to the original file) 7 | 2) make sure ISVALID should be used in place of checkbounds 8 | in interp.c 9 | 3) hide range 10 | 4) block moving into range 11 | 5) chain cells w/ equations into a linked list or dependency tree 12 | -have a top level eval, eval and UPDATE all lower nodes 13 | 6) an option to go into a ^R like 14 | ++data entry fields (highlight entry cells).... 15 | ++only allow entry in these cells.... 16 | 7) don't redraw the whole screen all the time 17 | (only cells that change, (in addition to what is in 'fixed #9')) 18 | (Note: there was no #9 when I took this over, and I've renumbered 19 | things since then, so I'm not sure what this is referring to - CRM) 20 | 8) add uemacs keybinding stuff 21 | 9) add uemacs macro language 22 | 10) add uemacs command completion 23 | 11) add undo 24 | 12) rewrite update() function in screen.c from scratch in a more sane manner 25 | (the current one is buggy and a headache to debug) 26 | 13) add a command line option (possibly -g) to use sc as a sort of grep for 27 | formatted or unformatted data in a file or list of files which will 28 | output the whole row in which a given number or string is found, 29 | formatted as with the write command. 30 | -------------------------------------------------------------------------------- /VMS_NOTES: -------------------------------------------------------------------------------- 1 | From: ihnp4!gargoyle!oddjob!noao!arizona!naucse!jdc (John Campbell) 2 | To: arizona!noao!oddjob!gargoyle!ihnp4!nsc!nscpdc!rgb 3 | Subject: VMS SC 4 | 5 | VMS USERS: 6 | 7 | Bob Bond has been generous enough to give me free rein in adding what I 8 | think is needed to make SC run on VMS. Any problems with VMS should be 9 | directed to me--they are not Bob's fault. 10 | 11 | The VMS SC is "SIMPLE" for the most part, except that the arrow keys 12 | (instead of hjkl) will move you around the cells. The VMS version of SC 13 | will not interact with the Bourne shell (obviously), which means that CRYPT 14 | and EXTERNAL FUNCTIONS will not be available. 15 | 16 | If you have a 'C' compiler and GNU Bison then you should be able to get 17 | SC running on VMS by following the instructions below. 18 | 19 | Step 1: Get all the files 20 | 21 | I've heard of a few sites that can unpack unix shar files directly on 22 | VMS. Most people, however, will need access to a unix machine to get 23 | the original distribution unpacked. At this time you should also build 24 | experres.h and statres.h and perhaps run the man pages off if you need 25 | to port the documentation. To build the two "missing" hearder files: 26 | sed experres.h -f eres.sed 27 | sed statres.h -f sres.sed 28 | 29 | Step 2: Cut out BUILD.COM and GETOPT.C 30 | 31 | At the end of this file are two other pieces: BUILD.COM and GETOPT.C. After 32 | you've moved everything to VMS, cut BUILD.COM and GETOPT.C out of here and 33 | put them in the same directory as the rest of the SC distribution. 34 | 35 | Step 3: Build it 36 | 37 | Theoretically all you now need to do is @BUILD and SC (as well as PSC) 38 | will be running on VMS. If you have problems feel free to contact me 39 | at ...!arizona!naucse!jdc (or even call at 602-523-6259). 40 | 41 | ---------------------cut here for BUILD.COM-------------------------- 42 | $! VMS command file to build SC and PSC (requires bison) 43 | $! SC: 44 | $ bison -d gram.y 45 | $ ren gram_tab.c gram.c 46 | $ cc /define=("SIMPLE","SIGVOID") sc.c 47 | $ cc /define=("SIMPLE","SIGVOID") gram.c 48 | $ cc /define=("SIMPLE","SIGVOID") lex.c 49 | $ cc /define=("SIMPLE","SIGVOID") interp 50 | $ cc /define=("SIMPLE","SIGVOID") cmds 51 | $ cc /define=("SIMPLE","SIGVOID") xmalloc 52 | $ cc /define=("SIMPLE","SIGVOID") range 53 | $ cc /define=("SIMPLE","SIGVOID") help 54 | $ link sc.obj,lex.obj,gram.obj,interp.obj,cmds.obj,xmalloc.obj,- 55 | range.obj,help.obj,sys$library:vaxcrtl.olb/lib 56 | $ ! 57 | $ ! Create VMS foreign command symbol to test SC 58 | $ ! 59 | $ sc == "$" + f$logical("SYS$DISK") + f$directory() + "SC.EXE" 60 | $! 61 | $! Now PSC 62 | $! 63 | $ cc psc.c 64 | $ cc getopt.c 65 | $ link psc,getopt,sys$library:vaxcrtl.olb/lib 66 | $ ! 67 | $ ! Create VMS foreign command symbol to test PSC (Note that 68 | $ ! PSC reads SYS$INPUT and writes to SYS$OUTPUT, so use 69 | $ ! DEFINE/USER to redirect.) 70 | $ ! 71 | $ psc == "$" + f$logical("SYS$DISK") + f$directory() + "PSC.EXE" 72 | 73 | ---------------------cut here for GETOPT.C------------------------ 74 | /* 75 | * getopt - get option letter from argv 76 | * This software is in the public domain 77 | * Originally written by Henry Spencer at the U. of Toronto 78 | */ 79 | 80 | #include 81 | 82 | char *optarg; /* Global argument pointer. */ 83 | int optind = 0; /* Global argv index. */ 84 | 85 | static char *scan = NULL; /* Private scan pointer. */ 86 | 87 | /* extern char *index(); obsolete, used strchr (JDC). */ 88 | 89 | int 90 | getopt(argc, argv, optstring) 91 | int argc; 92 | char *argv[]; 93 | char *optstring; 94 | { 95 | register char c; 96 | register char *place; 97 | 98 | optarg = NULL; 99 | 100 | if (scan == NULL || *scan == '\0') { 101 | if (optind == 0) 102 | optind++; 103 | 104 | if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') 105 | return(EOF); 106 | if (strcmp(argv[optind], "--")==0) { 107 | optind++; 108 | return(EOF); 109 | } 110 | 111 | scan = argv[optind]+1; 112 | optind++; 113 | } 114 | 115 | c = *scan++; 116 | place = strchr(optstring, c); 117 | 118 | if (place == NULL || c == ':') { 119 | fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); 120 | return('?'); 121 | } 122 | 123 | place++; 124 | if (*place == ':') { 125 | if (*scan != '\0') { 126 | optarg = scan; 127 | scan = NULL; 128 | } else { 129 | optarg = argv[optind]; 130 | optind++; 131 | } 132 | } 133 | 134 | return(c); 135 | } 136 | -------------------------------------------------------------------------------- /abbrev.c: -------------------------------------------------------------------------------- 1 | /* SC A Spreadsheet Calculator 2 | * Abbreviations 3 | * 4 | * Chuck Martin 5 | * Originally created: November, 2001 6 | * 7 | * $Revision: 7.16 $ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "compat.h" 18 | #include "sc.h" 19 | 20 | static int are_abbrevs(void); 21 | 22 | static struct abbrev *abbr_base; 23 | 24 | void 25 | add_abbr(char *string) 26 | { 27 | struct abbrev *a; 28 | register char *p; 29 | struct abbrev *prev = NULL; 30 | char *expansion; 31 | 32 | if (!string || *string == '\0') { 33 | if (!are_abbrevs()) { 34 | error("No abbreviations defined"); 35 | return; 36 | } else { 37 | FILE *f; 38 | int pid; 39 | char px[MAXCMD]; 40 | char *pager; 41 | struct abbrev *a; 42 | struct abbrev *nexta; 43 | 44 | strlcpy(px, "| ", sizeof px); 45 | if (!(pager = getenv("PAGER"))) 46 | pager = DFLT_PAGER; 47 | strlcat(px, pager, sizeof px); 48 | f = openfile(px, sizeof px, &pid, NULL); 49 | if (!f) { 50 | error("Can't open pipe to %s", pager); 51 | return; 52 | } 53 | (void) fprintf(f, "\n%-15s %s\n","Abbreviation","Expanded"); 54 | if (!brokenpipe) (void) fprintf(f, "%-15s %s\n", "------------", 55 | "--------"); 56 | 57 | for (a = nexta = abbr_base; nexta; a = nexta, nexta = a->a_next) 58 | ; 59 | while (a) { 60 | (void) fprintf(f, "%-15s %s\n", a->abbr, a->exp); 61 | if (brokenpipe) return; 62 | a = a->a_prev; 63 | } 64 | closefile(f, pid, 0); 65 | return; 66 | } 67 | } 68 | 69 | if ((expansion = strchr(string, ' '))) 70 | *expansion++ = '\0'; 71 | 72 | if (isalpha((int)*string) || isdigit((int)*string) || *string == '_') { 73 | for (p = string; *p; p++) 74 | if (!(isalpha((int)*p) || isdigit((int)*p) || *p == '_')) { 75 | error("Invalid abbreviation: %s", string); 76 | scxfree(string); 77 | return; 78 | } 79 | } else { 80 | for (p = string; *p; p++) 81 | if ((isalpha((int)*p) || isdigit((int)*p) || *p == '_') && *(p+1)) { 82 | error("Invalid abbreviation: %s", string); 83 | scxfree(string); 84 | return; 85 | } 86 | } 87 | 88 | if (expansion == NULL) { 89 | if ((a = find_abbr(string, strlen(string), &prev))) { 90 | error("abbrev \"%s %s\"", a->abbr, a->exp); 91 | return; 92 | } else { 93 | error("abreviation \"%s\" doesn't exist", string); 94 | return; 95 | } 96 | } 97 | 98 | if (find_abbr(string, strlen(string), &prev)) 99 | del_abbr(string); 100 | 101 | a = scxmalloc(sizeof(struct abbrev)); 102 | a->abbr = string; 103 | a->exp = expansion; 104 | 105 | if (prev) { 106 | a->a_next = prev->a_next; 107 | a->a_prev = prev; 108 | prev->a_next = a; 109 | if (a->a_next) 110 | a->a_next->a_prev = a; 111 | } else { 112 | a->a_next = abbr_base; 113 | a->a_prev = NULL; 114 | if (abbr_base) 115 | abbr_base->a_prev = a; 116 | abbr_base = a; 117 | } 118 | } 119 | 120 | void 121 | del_abbr(char *abbrev) 122 | { 123 | struct abbrev *a; 124 | struct abbrev *prev; 125 | 126 | if (!(a = find_abbr(abbrev, strlen(abbrev), &prev))) 127 | return; 128 | 129 | if (a->a_next) 130 | a->a_next->a_prev = a->a_prev; 131 | if (a->a_prev) 132 | a->a_prev->a_next = a->a_next; 133 | else 134 | abbr_base = a->a_next; 135 | scxfree((char *)(a->abbr)); 136 | scxfree((char *)a); 137 | } 138 | 139 | struct abbrev * 140 | find_abbr(char *abbrev, int len, struct abbrev **prev) 141 | { 142 | struct abbrev *a; 143 | int cmp; 144 | int exact = TRUE; 145 | 146 | if (len < 0) { 147 | exact = FALSE; 148 | len = -len; 149 | } 150 | 151 | for (a = abbr_base; a; a = a->a_next) { 152 | if ((cmp = strncmp(abbrev, a->abbr, len)) > 0) 153 | return (NULL); 154 | *prev = a; 155 | if (cmp == 0) 156 | if (!exact || strlen(a->abbr) == (unsigned int)len) 157 | return (a); 158 | } 159 | return NULL; 160 | } 161 | 162 | void 163 | write_abbrevs(FILE *f) 164 | { 165 | register struct abbrev *a; 166 | register struct abbrev *nexta; 167 | 168 | for (a = nexta = abbr_base; nexta; a = nexta, nexta = a->a_next) /* */ ; 169 | while (a) { 170 | (void) fprintf(f, "abbrev \"%s\" \"%s\"\n", a->abbr, a->exp); 171 | a = a->a_prev; 172 | } 173 | } 174 | 175 | static int 176 | are_abbrevs(void) 177 | { 178 | return (abbr_base != 0); 179 | } 180 | -------------------------------------------------------------------------------- /build.com: -------------------------------------------------------------------------------- 1 | $! VMS command file to build SC and PSC (requires bison) on VMS 2 | $! SC: 3 | $! $Revision: 7.16 $ 4 | $! bison -d gram.y 5 | $! ren gram_tab.c gram.c 6 | $ cc'p1' /define=("SIMPLE","SIGVOID") sc.c 7 | $ cc'p1' /define=("SIMPLE","SIGVOID") gram.c 8 | $ cc'p1' /define=("SIMPLE","SIGVOID") lex.c 9 | $ cc'p1' /define=("SIMPLE","SIGVOID","RINT") interp 10 | $ cc'p1' /define=("SIMPLE","SIGVOID") cmds 11 | $ cc'p1' /define=("SIMPLE","SIGVOID") xmalloc 12 | $ cc'p1' /define=("SIMPLE","SIGVOID") range 13 | $ cc'p1' /define=("SIMPLE","SIGVOID") help 14 | $ cc'p1' /define=("SIMPLE","SIGVOID") vmtbl 15 | $ cc'p1' /define=("SIMPLE","SIGVOID") screen 16 | $ cc'p1' /define=("SIMPLE","SIGVOID") vi 17 | $ cc'p1' /define=("SIMPLE","SIGVOID") format 18 | $ link'p1' sc.obj,lex.obj,gram.obj,interp.obj,cmds.obj,xmalloc.obj,- 19 | range.obj,help.obj,vmtbl.obj,screen.obj,vi.obj,format.obj,- 20 | sys$library:vaxccurse.olb/lib,- 21 | sys$library:vaxcrtl/shar 22 | $ ! 23 | $ ! Create VMS foreign command symbol to test SC 24 | $ ! 25 | $ sc == "$" + f$logical("SYS$DISK") + f$directory() + "SC.EXE" 26 | $! 27 | $! Now PSC 28 | $! 29 | !$ cc'p1' psc.c 30 | !$ cc'p1' getopt.c 31 | $ link'p1' psc,getopt,vmtbl.obj,xmalloc.obj,screen.obj,vi.obj,format.obj,- 32 | sys$library:vaxccurse.olb/lib,- 33 | sys$library:vaxcrtl/shar 34 | $ ! 35 | $ ! Create VMS foreign command symbol to test PSC (Note that 36 | $ ! PSC reads SYS$INPUT and writes to SYS$OUTPUT, so use 37 | $ ! DEFINE/USER to redirect.) 38 | $ ! 39 | $ psc == "$" + f$logical("SYS$DISK") + f$directory() + "PSC.EXE" 40 | -------------------------------------------------------------------------------- /color.c: -------------------------------------------------------------------------------- 1 | 2 | /* SC A Spreadsheet Calculator 3 | * Color manipulation routines 4 | * 5 | * Chuck Martin 6 | * Original Version Created: January, 2001 7 | * 8 | * $Revision: 7.16 $ 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "compat.h" 17 | #include "sc.h" 18 | 19 | /* a linked list of free [struct ent]'s, uses .next as the pointer */ 20 | extern struct ent *freeents; 21 | 22 | struct colorpair *cpairs[8]; 23 | static struct crange *color_base; 24 | 25 | void 26 | initcolor(int colornum) 27 | { 28 | if (!colornum) { 29 | int i; 30 | 31 | for (i = 0; i < 8; i++) cpairs[i] = 32 | scxmalloc(sizeof(struct colorpair)); 33 | } 34 | 35 | /* default colors */ 36 | if (!colornum || colornum == 1) { 37 | cpairs[0]->fg = COLOR_WHITE; 38 | cpairs[0]->bg = COLOR_BLUE; 39 | cpairs[0]->expr = NULL; 40 | init_pair(1, cpairs[0]->fg, cpairs[0]->bg); 41 | } 42 | 43 | /* default for negative numbers */ 44 | if (!colornum || colornum == 2) { 45 | cpairs[1]->fg = COLOR_RED; 46 | cpairs[1]->bg = COLOR_WHITE; 47 | cpairs[1]->expr = NULL; 48 | init_pair(2, cpairs[1]->fg, cpairs[1]->bg); 49 | } 50 | 51 | /* default for cells with errors */ 52 | if (!colornum || colornum == 3) { 53 | cpairs[2]->fg = COLOR_WHITE; 54 | cpairs[2]->bg = COLOR_RED; 55 | cpairs[2]->expr = NULL; 56 | init_pair(3, cpairs[2]->fg, cpairs[2]->bg); 57 | } 58 | 59 | /* default for '*' marking cells with attached notes */ 60 | if (!colornum || colornum == 4) { 61 | cpairs[3]->fg = COLOR_BLACK; 62 | cpairs[3]->bg = COLOR_YELLOW; 63 | cpairs[3]->expr = NULL; 64 | init_pair(4, cpairs[3]->fg, cpairs[3]->bg); 65 | } 66 | 67 | if (!colornum || colornum == 5) { 68 | cpairs[4]->fg = COLOR_BLACK; 69 | cpairs[4]->bg = COLOR_CYAN; 70 | cpairs[4]->expr = NULL; 71 | init_pair(5, cpairs[4]->fg, cpairs[4]->bg); 72 | } 73 | 74 | if (!colornum || colornum == 6) { 75 | cpairs[5]->fg = COLOR_RED; 76 | cpairs[5]->bg = COLOR_CYAN; 77 | cpairs[5]->expr = NULL; 78 | init_pair(6, cpairs[5]->fg, cpairs[5]->bg); 79 | } 80 | 81 | if (!colornum || colornum == 7) { 82 | cpairs[6]->fg = COLOR_WHITE; 83 | cpairs[6]->bg = COLOR_BLACK; 84 | cpairs[6]->expr = NULL; 85 | init_pair(7, cpairs[6]->fg, cpairs[6]->bg); 86 | } 87 | 88 | if (!colornum || colornum == 8) { 89 | cpairs[7]->fg = COLOR_RED; 90 | cpairs[7]->bg = COLOR_BLACK; 91 | cpairs[7]->expr = NULL; 92 | init_pair(8, cpairs[7]->fg, cpairs[7]->bg); 93 | } 94 | 95 | if (color && has_colors()) 96 | color_set(1, NULL); 97 | } 98 | 99 | void 100 | change_color(int pair, struct enode *e) 101 | { 102 | int v; 103 | 104 | if ((--pair) < 0 || pair > 7) { 105 | error("Invalid color number"); 106 | return; 107 | } 108 | 109 | v = (int) eval(e); 110 | 111 | if (!cpairs[pair]) 112 | cpairs[pair] = 113 | scxmalloc(sizeof(struct colorpair)); 114 | cpairs[pair]->fg = v & 7; 115 | cpairs[pair]->bg = (v >> 3) & 7; 116 | cpairs[pair]->expr = e; 117 | if (color && has_colors()) 118 | init_pair(pair + 1, cpairs[pair]->fg, cpairs[pair]->bg); 119 | 120 | modflg++; 121 | FullUpdate++; 122 | } 123 | 124 | void 125 | add_crange(struct ent *r_left, struct ent *r_right, int pair) 126 | { 127 | struct crange *r; 128 | int minr, minc, maxr, maxc; 129 | 130 | minr = r_left->row < r_right->row ? r_left->row : r_right->row; 131 | minc = r_left->col < r_right->col ? r_left->col : r_right->col; 132 | maxr = r_left->row > r_right->row ? r_left->row : r_right->row; 133 | maxc = r_left->col > r_right->col ? r_left->col : r_right->col; 134 | 135 | if (!pair) { 136 | if (color_base) 137 | for (r = color_base; r; r = r->r_next) 138 | if ( (r->r_left->row == r_left->row) && 139 | (r->r_left->col == r_left->col) && 140 | (r->r_right->row == r_right->row) && 141 | (r->r_right->col == r_right->col)) { 142 | if (r->r_next) 143 | r->r_next->r_prev = r->r_prev; 144 | if (r->r_prev) 145 | r->r_prev->r_next = r->r_next; 146 | else 147 | color_base = r->r_next; 148 | scxfree((char *)r); 149 | modflg++; 150 | FullUpdate++; 151 | return; 152 | } 153 | error("Color range not defined"); 154 | return; 155 | } 156 | 157 | r = scxmalloc(sizeof(struct crange)); 158 | r->r_left = lookat(minr, minc); 159 | r->r_right = lookat(maxr, maxc); 160 | r->r_color = pair; 161 | 162 | r->r_next = color_base; 163 | r->r_prev = (struct crange *)0; 164 | if (color_base) 165 | color_base->r_prev = r; 166 | color_base = r; 167 | 168 | modflg++; 169 | FullUpdate++; 170 | } 171 | 172 | void 173 | clean_crange(void) { 174 | register struct crange *cr; 175 | register struct crange *nextcr; 176 | 177 | cr = color_base; 178 | color_base = (struct crange *)0; 179 | 180 | while (cr) { 181 | nextcr = cr->r_next; 182 | scxfree((char *)cr); 183 | cr = nextcr; 184 | } 185 | } 186 | 187 | struct crange * 188 | find_crange(int row, int col) 189 | { 190 | struct crange *r; 191 | 192 | if (color_base) 193 | for (r = color_base; r; r = r->r_next) { 194 | if ((r->r_left->row <= row) && (r->r_left->col <= col) && 195 | (r->r_right->row >= row) && (r->r_right->col >= col)) 196 | return r; 197 | } 198 | return 0; 199 | } 200 | 201 | void 202 | sync_cranges(void) 203 | { 204 | struct crange *cr; 205 | 206 | cr = color_base; 207 | while (cr) { 208 | cr->r_left = lookat(cr->r_left->row, cr->r_left->col); 209 | cr->r_right = lookat(cr->r_right->row, cr->r_right->col); 210 | cr = cr->r_next; 211 | } 212 | } 213 | 214 | void 215 | write_cranges(FILE *f) 216 | { 217 | register struct crange *r; 218 | register struct crange *nextr; 219 | 220 | for (r = nextr = color_base; nextr; r = nextr, nextr = r->r_next) /**/ ; 221 | while (r) { 222 | fprintf(f, "color %s", v_name(r->r_left->row, r->r_left->col)); 223 | fprintf(f, ":%s", v_name(r->r_right->row, r->r_right->col)); 224 | fprintf(f, " %d\n", r->r_color); 225 | 226 | r = r->r_prev; 227 | } 228 | } 229 | 230 | void 231 | write_colors(FILE *f, int indent) 232 | { 233 | int i, c = 0; 234 | 235 | for (i = 0; i < 8; i++) { 236 | if (cpairs[i] && cpairs[i]->expr) { 237 | snprintf(line, sizeof line, "color %d = ", i + 1); 238 | linelim = strlen(line); 239 | decompile(cpairs[i]->expr, 0); 240 | line[linelim] = '\0'; 241 | fprintf(f, "%*s%s\n", indent, "", line); 242 | if (brokenpipe) return; 243 | c++; 244 | } 245 | } 246 | if (indent && c) fprintf(f, "\n"); 247 | } 248 | 249 | void 250 | list_colors(FILE *f) 251 | { 252 | struct crange *r; 253 | struct crange *nextr; 254 | 255 | write_colors(f, 2); 256 | linelim = -1; 257 | if (brokenpipe) return; 258 | 259 | if (!are_colors()) { 260 | fprintf(f, " No color ranges"); 261 | return; 262 | } 263 | 264 | fprintf(f, " %-30s %s\n","Range", "Color"); 265 | if (!brokenpipe) fprintf(f, " %-30s %s\n","-----", "-----"); 266 | 267 | for (r = nextr = color_base; nextr; r = nextr, nextr = r->r_next) /* */ ; 268 | while (r) { 269 | fprintf(f, " %-32s %d\n", r_name(r->r_left->row, r->r_left->col, 270 | r->r_right->row, r->r_right->col), r->r_color); 271 | if (brokenpipe) return; 272 | r = r->r_prev; 273 | } 274 | } 275 | 276 | int 277 | are_colors(void) { 278 | return (color_base != 0); 279 | } 280 | 281 | void 282 | fix_colors(int row1, int col1, int row2, int col2, int delta1, int delta2) 283 | { 284 | int r1, c1, r2, c2; 285 | struct crange *cr, *ncr; 286 | struct frange *fr; 287 | 288 | fr = find_frange(currow, curcol); 289 | 290 | if (color_base) 291 | for (cr = color_base; cr; cr = ncr) { 292 | ncr = cr->r_next; 293 | r1 = cr->r_left->row; 294 | c1 = cr->r_left->col; 295 | r2 = cr->r_right->row; 296 | c2 = cr->r_right->col; 297 | 298 | if (!(fr && (c1 < fr->or_left->col || c1 > fr->or_right->col))) { 299 | if (r1 != r2 && r1 >= row1 && r1 <= row2) r1 = row2 - delta1; 300 | if (c1 != c2 && c1 >= col1 && c1 <= col2) c1 = col2 - delta1; 301 | } 302 | 303 | if (!(fr && (c2 < fr->or_left->col || c2 > fr->or_right->col))) { 304 | if (r1 != r2 && r2 >= row1 && r2 <= row2) r2 = row1 + delta2; 305 | if (c1 != c2 && c2 >= col1 && c2 <= col2) c2 = col1 + delta2; 306 | } 307 | 308 | if (r1 > r2 || c1 > c2 || 309 | (row1 >= 0 && row2 >= 0 && row1 <= r1 && row2 >= r2) || 310 | (col1 >= 0 && col2 >= 0 && col1 <= c1 && col2 >= c2)) { 311 | /* the 0 means delete color range */ 312 | add_crange(cr->r_left, cr->r_right, 0); 313 | } else { 314 | cr->r_left = lookat(r1, c1); 315 | cr->r_right = lookat(r2, c2); 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /compat.c: -------------------------------------------------------------------------------- 1 | /* Carsten Kunze, 2016 */ 2 | 3 | #include 4 | 5 | #ifndef HAVE_STRLCPY 6 | size_t 7 | strlcpy(char *dst, const char *src, size_t dstsize) { 8 | size_t srcsize; 9 | /* Not conform to strlcpy, but avoids to access illegal memory in case 10 | * of unterminated strings */ 11 | for (srcsize = 0; srcsize < dstsize; srcsize++) 12 | if (!src[srcsize]) 13 | break; 14 | if (dstsize > srcsize) 15 | dstsize = srcsize; 16 | else if (dstsize) 17 | dstsize--; 18 | if (dstsize) 19 | /* assumes non-overlapping buffers */ 20 | memcpy(dst, src, dstsize); 21 | dst[dstsize] = 0; 22 | return srcsize; 23 | } 24 | #endif 25 | 26 | #ifndef HAVE_STRLCAT 27 | size_t 28 | strlcat(char *dst, const char *src, size_t dstsize) { 29 | size_t ld, ls; 30 | for (ld = 0; ld < dstsize - 1; ld++) 31 | if (!dst[ld]) 32 | break; 33 | dst += ld; 34 | dstsize -= ld; 35 | for (ls = 0; ls < dstsize; ls++) 36 | if (!src[ls]) 37 | break; 38 | if (dstsize > ls) 39 | dstsize = ls; 40 | else if (dstsize) 41 | dstsize--; 42 | if (dstsize) 43 | memcpy(dst, src, dstsize); 44 | dst[dstsize] = 0; 45 | return ld + ls; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (c) 2016-2018, Carsten Kunze 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 | # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 | # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 14 | # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | # PERFORMANCE OF THIS SOFTWARE. 16 | 17 | usage () { 18 | echo "Usage: $0 [-s]" 19 | echo " -s Silence output" 20 | exit $1 21 | } 22 | 23 | SRCDIR=$(dirname $0) 24 | SFLAG= 25 | MAKE= 26 | DEFS= 27 | LIB_LEX= 28 | LIB_CURSES= 29 | cat /dev/null > compat.h 30 | 31 | while [ $# -gt 0 ]; do 32 | case $1 in 33 | -s) SFLAG=1;; 34 | *) 35 | echo "$0: $1: Unknown option" >&2 36 | usage 1;; 37 | esac 38 | shift 39 | done 40 | 41 | check_for () { 42 | [ -e $LOG ] && cat <>$LOG 43 | 44 | ================================================================================ 45 | 46 | EOT 47 | A="Checking for $1 ... " 48 | printf "$A\n\n" >>$LOG 49 | [ -z "$SFLAG" ] && printf "$A" 50 | } 51 | 52 | compile () { 53 | rm -f ${TMPNAM}.o $TMPNAM $OUT $ERR 54 | $MAKE -f $OUTMK $TMPNAM > $OUT 2> $ERR 55 | RESULT=$? 56 | cat $OUT $ERR >> $LOG 57 | if [ $RESULT -eq 0 ]; then true; else false; fi 58 | } 59 | 60 | test_result () { 61 | RESULT=$? 62 | RESULT_TEXT=${1:-0} # 1: omit "no", 2: say nothing 63 | if [ $RESULT -eq 0 ]; then 64 | echo success >>$LOG 65 | [ -z "$SFLAG" -a $RESULT_TEXT -lt 2 ] && \ 66 | echo "yes$PASS_TEXT" 67 | PASS_TEXT= 68 | [ -e $TMPC ] && rm -f $TMPC 69 | true 70 | else 71 | [ -z "$SFLAG" -a $RESULT_TEXT -lt 1 ] && echo no 72 | if [ -e $TMPC ]; then 73 | echo "Failed program:" >>$LOG 74 | pr -n -t $TMPC >>$LOG 75 | rm -f $TMPC 76 | fi 77 | false 78 | fi 79 | } 80 | 81 | gen_mk () { 82 | [ $# -eq 0 ] && rm -f $OUTMK 83 | [ -n "$LEX" ] && echo "LEX=$LEX" >> $OUTMK 84 | [ -n "$FLOAT_STORE" ] && echo "FLOAT_STORE=$FLOAT_STORE" >> $OUTMK 85 | [ -n "$DEFS" ] && echo "DEFINES=$DEFS" >> $OUTMK 86 | [ -n "$INCDIR_CURSES" ] && echo "INCDIR_CURSES=$INCDIR_CURSES" >> $OUTMK 87 | [ -n "$RPATH_CURSES" ] && echo "RPATH_CURSES=$RPATH_CURSES" >> $OUTMK 88 | [ -n "$LIBDIR_CURSES" ] && echo "LIBDIR_CURSES=$LIBDIR_CURSES" \ 89 | >> $OUTMK 90 | [ -n "$LIB_CURSES" ] && echo "LIB_CURSES=$LIB_CURSES" >> $OUTMK 91 | [ -n "$LIB_AVLBST" ] && echo "LIB_AVLBST=$LIB_AVLBST" >> $OUTMK 92 | [ -n "$LIB_LEX" ] && echo "LIB_LEX=$LIB_LEX" >> $OUTMK 93 | [ -n "$__CDBG" ] && echo "__CDBG=$__CDBG" >> $OUTMK 94 | [ -n "$__CXXDBG" ] && echo "__CXXDBG=$__CXXDBG" >> $OUTMK 95 | [ -n "$__CLDBG" ] && echo "__CLDBG=$__CLDBG" >> $OUTMK 96 | [ -n "$__CLXXDBG" ] && echo "__CLXXDBG=$__CLXXDBG" >> $OUTMK 97 | sed -e /SRCDIR=\$/s:\$:$SRCDIR: $INMK >> $OUTMK || exit 1 98 | } 99 | check_make () { 100 | check_for "make(1)" 101 | 102 | cat <$TMPMK 103 | all: 104 | true 105 | EOT 106 | make -f $TMPMK >> $LOG 2>&1 107 | test_result && { 108 | MAKE=make 109 | return 110 | } 111 | 112 | echo "Failed makefile:" >>$LOG 113 | pr -n -t $TMPMK >>$LOG 114 | 115 | check_for "bmake(1)" 116 | 117 | cat <$TMPMK 118 | all: 119 | true 120 | EOT 121 | bmake -f $TMPMK >> $LOG 2>&1 122 | test_result && MAKE=bmake 123 | } 124 | check_make_vpath () { 125 | check_for "make supports VPATH" 126 | mkdir subdir 127 | > subdir/subfile.c 128 | cat < $TMPMK 129 | VPATH=subdir 130 | all: subfile.c 131 | @echo $<;test "$<" = subdir/subfile.c 132 | EOT 133 | $MAKE -f $TMPMK >> $LOG 2>&1 134 | test_result && SUPPORTS_VPATH=1 135 | rm -rf subdir 136 | } 137 | check_Sanitizer () { 138 | check_for "CC Sanitizer" 139 | 140 | # C only 141 | __CDBG= 142 | __CLDBG= 143 | __CCXXDBG= 144 | # C++ only 145 | __CXXDBG= 146 | __CLXXDBG= 147 | __CDBG="$__CDBG -Wmissing-prototypes" 148 | __CDBG="$__CDBG -Wstrict-prototypes" 149 | __CCXXDBG="$__CCXXDBG -g -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls" 150 | __CCXXDBG="$__CCXXDBG -Wall" 151 | __CCXXDBG="$__CCXXDBG -Wextra" 152 | __CCXXDBG="$__CCXXDBG -Wsign-compare" 153 | __CCXXDBG="$__CCXXDBG -Wcast-align" 154 | __CCXXDBG="$__CCXXDBG -Wcast-qual" 155 | __CCXXDBG="$__CCXXDBG -Wunused-parameter" 156 | __CCXXDBG="$__CCXXDBG -Wunused-function" 157 | __CCXXDBG="$__CCXXDBG -Wshadow" 158 | __CCXXDBG="$__CCXXDBG -Wwrite-strings" 159 | __CLXXDBG="$__CLXXDBG -fno-common -fsanitize=address -fsanitize=undefined" 160 | #__CLXXDBG="$__CLXXDBG -fsanitize-recover=all" 161 | 162 | [ -n "$CC" ] || CC=cc 163 | VER=`$CC --version` 164 | 165 | if echo $VER | grep -iq gcc || echo $VER | \ 166 | grep -iq 'Free Software Foundation'; then 167 | [ -z "$SFLAG" ] && printf "(gcc) " 168 | #__CLXXDBG="$__CLXXDBG -fprofile-arcs -ftest-coverage" 169 | __CLXXDBG="$__CLXXDBG -fsanitize=float-divide-by-zero" 170 | __CLXXDBG="$__CLXXDBG -fsanitize=float-cast-overflow" 171 | elif echo $VER | grep -q clang; then 172 | [ -z "$SFLAG" ] && printf "(clang) " 173 | __CCXXDBG="$__CCXXDBG -Wincompatible-pointer-types-discards-qualifiers" 174 | __CCXXDBG="$__CCXXDBG -Wmissing-variable-declarations" 175 | __CXXDBG="$__CXXDBG -Wunused-private-field" 176 | __CLXXDBG="$__CLXXDBG -fsanitize=unsigned-integer-overflow" 177 | else 178 | [ -z "$SFLAG" ] && echo "Unknown compiler" 179 | return 180 | fi 181 | 182 | # Most C++ options can be used for C too 183 | __CDBG="$__CDBG $__CCXXDBG" 184 | __CLDBG="$__CLDBG $__CLXXDBG" 185 | __CXXDBG="$__CXXDBG $__CCXXDBG" 186 | cat <$TMPC 187 | int 188 | main() { 189 | return 0; 190 | } 191 | EOT 192 | gen_mk 193 | cat <>$OUTMK 194 | $TMPNAM: ${TMPNAM}.o 195 | \$(CC) \$(__CDBG) \$(__CLDBG) -o \$@ ${TMPNAM}.o 196 | EOT 197 | compile 198 | test_result || { 199 | __CLDBG= 200 | __CLXXDBG= 201 | } 202 | } 203 | check_float_store () { 204 | FLOAT_STORE=-ffloat-store 205 | check_for "$FLOAT_STORE" 206 | cat <$TMPC 207 | int 208 | main() { 209 | return 0; 210 | } 211 | EOT 212 | gen_mk 213 | cat <>$OUTMK 214 | ${TMPNAM}.o: 215 | \$(CC) $FLOAT_STORE -c $TMPC 216 | EOT 217 | rm -f ${TMPNAM}.o 218 | $MAKE -f $OUTMK ${TMPNAM}.o >> $LOG 2> $TMPNAM 219 | cat $TMPNAM >> $LOG 220 | if [ -s $TMPNAM ]; then 221 | if grep -e $FLOAT_STORE $TMPNAM | grep -q 'not supported' 222 | then 223 | false 224 | elif grep -e $FLOAT_STORE $TMPNAM | grep -q 'argument unused' 225 | then 226 | false 227 | else 228 | true 229 | fi 230 | else 231 | true 232 | fi 233 | test_result || FLOAT_STORE= 234 | } 235 | check_strlcpy () { 236 | check_for "strlcpy(3)" 237 | 238 | cat <$TMPC 239 | #include 240 | int 241 | main(int argc, char **argv) { 242 | char a[10]; 243 | (void)argc; 244 | strlcpy(a, *argv, sizeof a); 245 | return 0; 246 | } 247 | EOT 248 | compile 249 | if test_result; then 250 | DEFS="$DEFS -DHAVE_STRLCPY" 251 | else 252 | H=compat.h 253 | grep -q '' $H 2>/dev/null || cat <>$H 254 | #include 255 | EOT 256 | cat <>$H 257 | size_t strlcpy(char *, const char *, size_t); 258 | EOT 259 | fi 260 | } 261 | check_strlcat () { 262 | check_for "strlcat(3)" 263 | 264 | cat <$TMPC 265 | #include 266 | int 267 | main(int argc, char **argv) { 268 | char a[10]; 269 | (void)argc; 270 | *a = 0; 271 | strlcat(a, *argv, sizeof a); 272 | return 0; 273 | } 274 | EOT 275 | compile 276 | if test_result; then 277 | DEFS="$DEFS -DHAVE_STRLCAT" 278 | else 279 | H=compat.h 280 | grep -q '' $H 2>/dev/null || cat <>$H 281 | #include 282 | EOT 283 | cat <>$H 284 | size_t strlcat(char *, const char *, size_t); 285 | EOT 286 | fi 287 | } 288 | check_fixterm () { 289 | check_for 'fixterm(3)' 290 | 291 | cat <$TMPC 292 | #include "compat.h" 293 | int 294 | main() { 295 | fixterm(); 296 | return 0; 297 | } 298 | EOT 299 | gen_mk 300 | cat <>$OUTMK 301 | $TMPNAM: ${TMPNAM}.o 302 | \$(CC) \$(_CFLAGS) \$(_LDFLAGS) \$(RPATH_CURSES) -o \$@ ${TMPNAM}.o \$(LDADD) 303 | EOT 304 | compile 305 | test_result && DEFS="$DEFS -DHAVE_FIXTERM" 306 | } 307 | 308 | check_resetterm () { 309 | check_for 'resetterm(3)' 310 | 311 | cat <$TMPC 312 | #include "compat.h" 313 | int 314 | main() { 315 | resetterm(); 316 | return 0; 317 | } 318 | EOT 319 | gen_mk 320 | cat <>$OUTMK 321 | $TMPNAM: ${TMPNAM}.o 322 | \$(CC) \$(_CFLAGS) \$(_LDFLAGS) \$(RPATH_CURSES) -o \$@ ${TMPNAM}.o \$(LDADD) 323 | EOT 324 | compile 325 | test_result && DEFS="$DEFS -DHAVE_RESETTERM" 326 | } 327 | 328 | compile_curses () { 329 | cat <$TMPC 330 | #include "compat.h" 331 | int 332 | main() { 333 | return 0; 334 | } 335 | EOT 336 | gen_mk 337 | cat <>$OUTMK 338 | $TMPNAM: ${TMPNAM}.o 339 | \$(CC) \$(_CFLAGS) \$(_LDFLAGS) \$(RPATH_CURSES) -o \$@ ${TMPNAM}.o \$(LDADD) 340 | EOT 341 | compile 342 | test_result 1 343 | } 344 | 345 | test_curses () { 346 | compile_curses && return 347 | [ $# -gt 0 ] && for i in $*; do 348 | compile_curses $i && return 349 | done 350 | } 351 | 352 | check_ncursesw () { 353 | LIB_CURSES="-lncursesw" 354 | check_for $LIB_CURSES 355 | ODEFS=$DEFS 356 | 357 | # At first test for specific ncursesw.h to not used -lncursesw with 358 | # traditional curses.h if both curses systems are installed. 359 | 360 | DEFS="$DEFS -DHAVE_NCURSESW_CURSES_H" 361 | INCDIR_CURSES="-I/usr/include/ncurses6" 362 | RPATH_CURSES="-Wl,-rpath,/usr/lib64/ncurses6" 363 | LIBDIR_CURSES="-L/usr/lib64/ncurses6" 364 | PASS_TEXT=" (#include , -I/usr/include/ncurses6, \ 365 | -L/usr/lib64/ncurses6)" 366 | test_curses && return # Linux NC6 367 | 368 | INCDIR_CURSES= 369 | RPATH_CURSES= 370 | LIBDIR_CURSES= 371 | PASS_TEXT=" (#include )" 372 | test_curses && return # Linux 373 | 374 | INCDIR_CURSES="-I/usr/pkg/include" 375 | RPATH_CURSES="-Wl,-rpath,/usr/pkg/lib" 376 | LIBDIR_CURSES="-L/usr/pkg/lib" 377 | PASS_TEXT=" (#include , -I/usr/pkg/include, \ 378 | -L/usr/pkg/lib)" 379 | test_curses && return # NetBSD 380 | 381 | DEFS=$ODEFS 382 | INCDIR_CURSES= 383 | RPATH_CURSES= 384 | LIBDIR_CURSES= 385 | PASS_TEXT= 386 | test_curses && return # OpenBSD, FreeBSD 387 | 388 | [ -z "$SFLAG" ] && echo no 389 | false 390 | } 391 | 392 | check_ncurses () { 393 | LIB_CURSES="-lncurses" 394 | check_for $LIB_CURSES 395 | ODEFS=$DEFS 396 | 397 | DEFS="$DEFS -DHAVE_NCURSES_CURSES_H" 398 | PASS_TEXT=" (#include )" 399 | test_curses && return # OpenIndiana 400 | 401 | DEFS="$DEFS -DHAVE_NCURSES_CURSES_H" 402 | INCDIR_CURSES="-I/usr/pkg/include" 403 | RPATH_CURSES="-Wl,-rpath,/usr/pkg/lib" 404 | LIBDIR_CURSES="-L/usr/pkg/lib" 405 | PASS_TEXT=" (#include , -I/usr/pkg/include, \ 406 | -L/usr/pkg/lib)" 407 | test_curses && return # NetBSD 408 | 409 | DEFS=$ODEFS 410 | INCDIR_CURSES= 411 | RPATH_CURSES= 412 | LIBDIR_CURSES= 413 | PASS_TEXT= 414 | test_curses && return 415 | 416 | [ -z "$SFLAG" ] && echo no 417 | false 418 | } 419 | 420 | check_curses () { 421 | LIB_CURSES="-lcurses" 422 | check_for $LIB_CURSES 423 | test_curses || { 424 | [ -z "$SFLAG" ] && echo no 425 | false 426 | return 427 | } 428 | 429 | check_for attr_t 430 | cat <$TMPC 431 | #include "compat.h" 432 | int 433 | main(int argc, char **argv) { 434 | (void)argv; 435 | attr_t c = argc + '0'; 436 | return (int)c; 437 | } 438 | EOT 439 | compile 440 | test_result && DEFS="$DEFS -DHAVE_ATTR_T" 441 | 442 | check_for 'attr_get(3)' 443 | cat <$TMPC 444 | #include "compat.h" 445 | int 446 | main() { 447 | return attr_get(NULL, NULL, NULL); 448 | } 449 | EOT 450 | gen_mk 451 | cat <>$OUTMK 452 | $TMPNAM: ${TMPNAM}.o 453 | \$(CC) \$(_CFLAGS) -o \$@ ${TMPNAM}.o \$(LDADD) 454 | EOT 455 | compile 456 | test_result && DEFS="$DEFS -DHAVE_ATTR_GET" 457 | 458 | check_fixterm 459 | check_resetterm 460 | true 461 | } 462 | 463 | curses_mk_compat_h () { 464 | cat <>compat.h 465 | #ifndef _XOPEN_SOURCE_EXTENDED 466 | # define _XOPEN_SOURCE_EXTENDED 467 | #endif 468 | 469 | #if defined(HAVE_NCURSESW_CURSES_H) 470 | # include 471 | #elif defined(HAVE_NCURSES_CURSES_H) 472 | # include 473 | #else 474 | # include 475 | 476 | # ifndef false 477 | # define false 0 478 | # endif 479 | 480 | # ifndef true 481 | # define true 1 482 | # endif 483 | #endif 484 | EOT 485 | } 486 | 487 | check_lib_curses () { 488 | curses_mk_compat_h 489 | DEFS0=$DEFS 490 | DEFS="$DEFS -DHAVE_ATTR_T -DHAVE_ATTR_GET -DHAVE_FIXTERM \ 491 | -DHAVE_RESETTERM" 492 | check_ncursesw && return 493 | check_ncurses && return 494 | DEFS=$DEFS0 495 | check_curses && return 496 | } 497 | 498 | check_netbsd_curses () { 499 | curses_mk_compat_h 500 | [ `uname` = "NetBSD" ] && check_curses && return 501 | DEFS0=$DEFS 502 | DEFS="$DEFS -DHAVE_ATTR_T -DHAVE_ATTR_GET -DHAVE_FIXTERM \ 503 | -DHAVE_RESETTERM" 504 | check_ncursesw && return 505 | check_ncurses && return 506 | DEFS=$DEFS0 507 | check_curses && return 508 | } 509 | check_curses_wch () { 510 | check_for "wins_wch(3)" 511 | 512 | cat <$TMPC 513 | #include "compat.h" 514 | int 515 | main() { 516 | cchar_t c; 517 | wins_wch(stdscr, &c); 518 | return 0; 519 | } 520 | EOT 521 | gen_mk 522 | cat <>$OUTMK 523 | $TMPNAM: ${TMPNAM}.o 524 | \$(CC) \$(_CFLAGS) \$(_LDFLAGS) \$(RPATH_CURSES) -o \$@ ${TMPNAM}.o \$(LDADD) 525 | EOT 526 | compile 527 | test_result || return; 528 | 529 | DEFS="$DEFS -DHAVE_CURSES_WCH" 530 | } 531 | check_curses_keyname () { 532 | check_for "keyname(3)" 533 | 534 | cat <$TMPC 535 | #include "compat.h" 536 | int 537 | main(int argc, char **argv) { 538 | (void)argv; 539 | puts(keyname(argc)); 540 | return 0; 541 | } 542 | EOT 543 | gen_mk 544 | cat <>$OUTMK 545 | $TMPNAM: ${TMPNAM}.o 546 | \$(CC) \$(_CFLAGS) \$(_LDFLAGS) \$(RPATH_CURSES) -o \$@ ${TMPNAM}.o \$(LDADD) 547 | EOT 548 | compile 549 | test_result || return; 550 | 551 | DEFS="$DEFS -DHAVE_CURSES_KEYNAME" 552 | } 553 | check_isfinite () { 554 | check_for "isfinite(3)" 555 | 556 | cat <$TMPC 557 | #include 558 | int 559 | main(int argc, char **argv) { 560 | (void)argv; 561 | return isfinite((double)argc); 562 | } 563 | EOT 564 | compile 565 | test_result && { 566 | DEFS="$DEFS -DHAVE_ISFINITE" 567 | return 568 | } 569 | 570 | check_for "finite(3)" 571 | 572 | cat <$TMPC 573 | #include 574 | int 575 | main(int argc, char **argv) { 576 | (void)argv; 577 | return finite((double)argc); 578 | } 579 | EOT 580 | compile 581 | test_result 2 && { 582 | [ -s $ERR ] || 583 | grep -iq implicite $ERR || 584 | grep -iq warning $ERR || { 585 | [ -z "$SFLAG" ] && echo yes 586 | return 587 | } 588 | } 589 | 590 | cat <$TMPC 591 | #include 592 | #include 593 | int 594 | main(int argc, char **argv) { 595 | (void)argv; 596 | return finite(argc); 597 | } 598 | EOT 599 | PASS_TEXT=" (#include )" 600 | compile 601 | test_result && DEFS="$DEFS -DUSE_IEEEFP_H" 602 | PASS_TEXT= 603 | } 604 | check_sc_attr_get () { 605 | check_for "sc(1) attr_get(3)" 606 | cat <$TMPC 607 | #include 608 | #include "compat.h" 609 | #include "sc.h" 610 | int 611 | main() { 612 | attr_get(NULL, NULL, NULL); 613 | return 0; 614 | } 615 | EOT 616 | gen_mk 617 | cat <>$OUTMK 618 | $TMPNAM: ${TMPNAM}.o 619 | \$(CC) \$(_CFLAGS) -o \$@ ${TMPNAM}.o \$(LDADD) 620 | EOT 621 | compile 622 | test_result || DEFS="$DEFS -DNO_ATTR_GET" 623 | } 624 | check_stdbool_h () { 625 | check_for "" 626 | 627 | cat <$TMPC 628 | #include 629 | int 630 | main() { 631 | return 0; 632 | } 633 | EOT 634 | compile 635 | test_result && DEFS="$DEFS -DHAVE_STDBOOL_H" 636 | } 637 | [ ! -s compat.h ] && rm compat.h 638 | OUTMK=Makefile 639 | INMK=${SRCDIR}/${OUTMK}.in 640 | CFG=config 641 | TMPNAM=.$CFG 642 | TMPMK=${TMPNAM}.mk 643 | TMPC=${TMPNAM}.c 644 | OUT=${TMPNAM}.out 645 | ERR=${TMPNAM}.err 646 | LOG=${CFG}.log 647 | SUPPORTS_VPATH=0 648 | rm -f $LOG 649 | gen_mk 650 | 651 | check_make 652 | check_make_vpath 653 | test $SUPPORTS_VPATH = 1 && INMK=${SRCDIR}/${OUTMK}.in.vpath 654 | #check_Sanitizer 655 | check_float_store 656 | check_strlcpy 657 | check_strlcat 658 | check_lib_curses 659 | check_curses_wch 660 | check_curses_keyname 661 | check_isfinite 662 | check_sc_attr_get 663 | check_stdbool_h 664 | 665 | gen_mk 666 | rm -f $TMPNAM* 667 | 668 | echo "#define _COMPAT_H" >>compat.h 669 | -------------------------------------------------------------------------------- /crypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Encryption utilites 3 | * Bradley Williams 4 | * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams 5 | * $Revision: 7.16 $ 6 | */ 7 | 8 | #if !defined(VMS) && !defined(MSDOS) && defined(CRYPT_PATH) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "compat.h" 17 | #include "sc.h" 18 | 19 | int Crypt = 0; 20 | #define MAXKEYWORDSIZE 30 21 | char KeyWord[MAXKEYWORDSIZE] = {""}; 22 | 23 | void 24 | creadfile(char *save, int eraseflg) 25 | { 26 | register FILE *f; 27 | int pipefd[2]; 28 | int fildes; 29 | int pid; 30 | 31 | if (eraseflg && strcmp(save, curfile) && modcheck(" first")) return; 32 | 33 | if ((fildes = open(findhome(save), O_RDONLY, 0)) < 0) { 34 | error ("Can't read file \"%s\"", save); 35 | return; 36 | } 37 | 38 | if (eraseflg) erasedb(); 39 | 40 | if (pipe(pipefd) < 0) { 41 | error("Can't make pipe to child"); 42 | return; 43 | } 44 | 45 | deraw(1); 46 | strlcpy(KeyWord, getpass("Enter key:"), sizeof KeyWord); 47 | goraw(); 48 | 49 | if ((pid=fork()) == 0) { /* if child */ 50 | (void) close(0); /* close stdin */ 51 | (void) close(1); /* close stdout */ 52 | (void) close(pipefd[0]); /* close pipe input */ 53 | (void) dup(fildes); /* standard in from file */ 54 | (void) dup(pipefd[1]); /* connect to pipe */ 55 | (void) fprintf(stderr, " "); 56 | (void) execl(CRYPT_PATH, "crypt", KeyWord, 0); 57 | (void) fprintf(stderr, "execl(%s, \"crypt\", %s, 0) in creadfile() failed", 58 | CRYPT_PATH, KeyWord); 59 | exit(-127); 60 | } else { /* else parent */ 61 | (void) close(fildes); 62 | (void) close(pipefd[1]); /* close pipe output */ 63 | if ((f = fdopen(pipefd[0], "r")) == (FILE *)0) { 64 | (void) kill(pid, 9); 65 | error("Can't fdopen file \"%s\"", save); 66 | (void)close(pipefd[0]); 67 | return; 68 | } 69 | } 70 | 71 | loading++; 72 | while (fgets(line, sizeof(line), f)) { 73 | linelim = 0; 74 | if (line[0] != '#') (void) yyparse(); 75 | } 76 | --loading; 77 | if (fclose(f) == EOF) { 78 | error("fclose(pipefd): %s", strerror(errno)); 79 | } 80 | (void) close(pipefd[0]); 81 | while (pid != wait(&fildes)) /**/; 82 | linelim = -1; 83 | if (eraseflg) { 84 | strlcpy(curfile, save, sizeof curfile); 85 | modflg = 0; 86 | } 87 | } 88 | 89 | int 90 | cwritefile(char *fname, int r0, int c0, int rn, int cn) 91 | { 92 | register FILE *f; 93 | int pipefd[2]; 94 | int fildes; 95 | int pid; 96 | char save[PATHLEN]; 97 | char *fn; 98 | char *busave; 99 | 100 | if (*fname == '\0') fname = &curfile[0]; 101 | 102 | fn = fname; 103 | while (*fn && (*fn == ' ')) /* Skip leading blanks */ 104 | fn++; 105 | 106 | if (*fn == '|') { 107 | error("Can't have encrypted pipe"); 108 | return (-1); 109 | } 110 | 111 | strlcpy(save, fname, sizeof save); 112 | 113 | busave = findhome(save); 114 | if (dobackups && !backup_file(busave) && 115 | (yn_ask("Could not create backup copy, Save anyway?: (y,n)") != 1)) 116 | return (0); 117 | if ((fildes = open (busave, O_TRUNC|O_WRONLY|O_CREAT, 0600)) < 0) { 118 | error("Can't create file \"%s\"", save); 119 | return (-1); 120 | } 121 | 122 | if (pipe(pipefd) < 0) { 123 | error("Can't make pipe to child\n"); 124 | return (-1); 125 | } 126 | 127 | if (KeyWord[0] == '\0') { 128 | deraw(1); 129 | strlcpy(KeyWord, getpass("Enter key:"), sizeof KeyWord); 130 | goraw(); 131 | } 132 | 133 | if ((pid=fork()) == 0) { /* if child */ 134 | (void) close(0); /* close stdin */ 135 | (void) close(1); /* close stdout */ 136 | (void) close(pipefd[1]); /* close pipe output */ 137 | (void) dup(pipefd[0]); /* connect to pipe input */ 138 | (void) dup(fildes); /* standard out to file */ 139 | (void) fprintf(stderr, " "); 140 | (void) execl(CRYPT_PATH, "crypt", KeyWord, 0); 141 | (void) fprintf(stderr, "execl(%s, \"crypt\", %s, 0) in cwritefile() failed", 142 | CRYPT_PATH, KeyWord); 143 | exit (-127); 144 | } 145 | else { /* else parent */ 146 | (void) close(fildes); 147 | (void) close(pipefd[0]); /* close pipe input */ 148 | f = fdopen(pipefd[1], "w"); 149 | if (f == 0) { 150 | (void) kill(pid, -9); 151 | error("Can't fdopen file \"%s\"", save); 152 | (void) close(pipefd[1]); 153 | return (-1); 154 | } 155 | } 156 | 157 | write_fd(f, r0, c0, rn, cn); 158 | 159 | if (fclose(f) == EOF) { 160 | error("fclose(pipefd): %s", strerror(errno)); 161 | } 162 | (void) close(pipefd[1]); 163 | while (pid != wait(&fildes)) /**/; 164 | strlcpy(curfile, save, sizeof curfile); 165 | 166 | modflg = 0; 167 | error("File \"%s\" written (encrypted).", curfile); 168 | return (0); 169 | } 170 | 171 | #endif /* CRYPT_PATH */ 172 | -------------------------------------------------------------------------------- /eres.sed: -------------------------------------------------------------------------------- 1 | /%token.*K_/!d 2 | /%token.*K_\(.*\)/s// { "\1", K_\1 },/ 3 | -------------------------------------------------------------------------------- /format.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * Mark Nagel 4 | * 20 July 1989 5 | * 6 | * $Revision: 7.16 $ 7 | * 8 | * bool 9 | * format(fmt, precision, num, buf, buflen) 10 | * char *fmt; 11 | * double num; 12 | * char buf[]; 13 | * int buflen; 14 | * 15 | * The format function will produce a string representation of a number 16 | * given a _format_ (described below) and a double value. The result is 17 | * written into the passed buffer -- if the resulting string is too 18 | * long to fit into the passed buffer, the function returns false. 19 | * Otherwise the function returns true. 20 | * 21 | * The fmt parameter contains the format to use to convert the number. 22 | * 23 | * # Digit placeholder. If the number has fewer digits on either 24 | * side of the decimal point than there are '#' characters in 25 | * the format, the extra '#' characters are ignored. The number 26 | * is rounded to the number of digit placeholders as there are 27 | * to the right of the decimal point. If there are more digits 28 | * in the number than there are digit placeholders on the left 29 | * side of the decimal point, then those digits are displayed. 30 | * 31 | * 0 Digit placeholder. Same as for '#' except that the number 32 | * is padded with zeroes on either side of the decimal point. 33 | * The number of zeroes used in padding is determined by the 34 | * number of digit placeholders after the '0' for digits on 35 | * the left side of the decimal point and by the number of 36 | * digit placeholders before the '0' for digits on the right 37 | * side of the decimal point. 38 | * 39 | * . Decimal point. Determines how many digits are placed on 40 | * the right and left sides of the decimal point in the number. 41 | * Note that numbers smaller than 1 will begin with a decimal 42 | * point if the left side of the decimal point contains only 43 | * a '#' digit placeholder. Use a '0' placeholder to get a 44 | * leading zero in decimal formats. 45 | * 46 | * % Percentage. For each '%' character in the format, the actual 47 | * number gets multiplied by 100 (only for purposes of formatting 48 | * -- the original number is left unmodified) and the '%' character 49 | * is placed in the same position as it is in the format. 50 | * 51 | * , Thousands separator. The presence of a ',' in the format 52 | * (multiple commas are treated as one) will cause the number 53 | * to be formatted with a ',' separating each set of three digits 54 | * in the integer part of the number with numbering beginning 55 | * from the right end of the integer. 56 | * 57 | * & Precision. When this character is present in the fractional 58 | * part of the number, it is equavalent to a number of 0's equal 59 | * to the precision specified in the column format command. For 60 | * example, if the precision is 3, "&" is equivalent to "000". 61 | * 62 | * \ Quote. This character causes the next character to be 63 | * inserted into the formatted string directly with no 64 | * special interpretation. 65 | * 66 | * E- E+ e- e+ 67 | * Scientific format. Causes the number to formatted in scientific 68 | * notation. The case of the 'E' or 'e' given is preserved. If 69 | * the format uses a '+', then the sign is always given for the 70 | * exponent value. If the format uses a '-', then the sign is 71 | * only given when the exponent value is negative. Note that if 72 | * there is no digit placeholder following the '+' or '-', then 73 | * that part of the formatted number is left out. In general, 74 | * there should be one or more digit placeholders after the '+' 75 | * or '-'. 76 | * 77 | * ; Format selector. Use this character to separate the format 78 | * into two distinct formats. The format to the left of the 79 | * ';' character will be used if the number given is zero or 80 | * positive. The format to the right of the ';' character is 81 | * used if the number given is negative. 82 | * 83 | * Any 84 | * Self insert. Any other character will be inserted directly 85 | * into the formatted number with no change made to the actual 86 | * number. 87 | * 88 | *****************************************************************************/ 89 | 90 | /*****************************************************************************/ 91 | 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include "compat.h" 99 | #include "sc.h" 100 | 101 | #define EOS '\0' 102 | #define MAXBUF 256 103 | 104 | static char *fmt_int(char *val, char *fmt, bool comma, bool negative); 105 | static char *fmt_frac(char *val, char *fmt, int lprecision); 106 | static char *fmt_exp(int val, char *fmt); 107 | 108 | static void reverse(register char *buf); 109 | 110 | char *colformat[COLFORMATS]; 111 | 112 | /*****************************************************************************/ 113 | 114 | bool 115 | format(char *fmt, int lprecision, double val, char *buf, size_t buflen) 116 | { 117 | register char *cp; 118 | char *tmp, *tp; 119 | bool comma = false, negative = false; 120 | char *integer = NULL, *decimal = NULL; 121 | char *exponent = NULL; 122 | int exp_val = 0; 123 | int width; 124 | char prtfmt[32]; 125 | static char *mantissa = NULL; 126 | static char *tmpfmt1 = NULL, *tmpfmt2 = NULL, *exptmp = NULL; 127 | static unsigned mantlen = 0, fmtlen = 0; 128 | char *fraction = NULL; 129 | int zero_pad = 0; 130 | 131 | if (fmt == NULL) 132 | return(true); 133 | 134 | if (strlen(fmt) + 1 > fmtlen) { 135 | fmtlen = strlen(fmt) + 40; 136 | tmpfmt1 = scxrealloc(tmpfmt1, fmtlen); 137 | tmpfmt2 = scxrealloc(tmpfmt2, fmtlen); 138 | exptmp = scxrealloc(exptmp, fmtlen); 139 | } 140 | strlcpy(tmpfmt1, fmt, fmtlen); 141 | fmt = tmpfmt1; 142 | if (buflen + 1 > mantlen) { 143 | mantlen = buflen + 40; 144 | mantissa = scxrealloc(mantissa, mantlen); 145 | } 146 | 147 | /* 148 | * select positive or negative format if necessary 149 | */ 150 | for (cp = fmt; *cp != ';' && *cp != EOS; cp++) { 151 | if (*cp == '\\') 152 | cp++; 153 | } 154 | if (*cp == ';') { 155 | if (val < 0.0) { 156 | val = -val; /* format should provide sign if desired */ 157 | fmt = cp + 1; 158 | } else 159 | *cp = EOS; 160 | } 161 | 162 | /* 163 | * extract other information from format and produce a 164 | * format string stored in tmpfmt2 also scxmalloc()'d above 165 | */ 166 | tmp = tmpfmt2; 167 | for (cp = fmt, tp = tmp; *cp != EOS; cp++) { 168 | switch (*cp) { 169 | case '\\': 170 | *tp++ = *cp++; 171 | *tp++ = *cp; 172 | break; 173 | 174 | case ',': 175 | comma = true; 176 | break; 177 | 178 | case '.': 179 | if (decimal == NULL) 180 | decimal = tp; 181 | *tp++ = *cp; 182 | break; 183 | 184 | case '%': 185 | val *= 100.0; 186 | *tp++ = *cp; 187 | break; 188 | 189 | default: 190 | *tp++ = *cp; 191 | break; 192 | } 193 | } 194 | *tp = EOS; 195 | fmt = tmpfmt2; 196 | 197 | /* The following line was necessary due to problems with the gcc 198 | * compiler and val being a negative zero. Thanks to Mike Novack for 199 | * the suggestion. - CRM 200 | */ 201 | val = (val + 1.0) - 1.0; 202 | if (val < 0.0) { 203 | negative = true; 204 | val = -val; 205 | } 206 | /* 207 | * extract the exponent from the format if present 208 | */ 209 | for (cp = fmt; *cp != EOS; cp++) { 210 | if (*cp == '\\') 211 | cp++; 212 | else if (*cp == 'e' || *cp == 'E') { 213 | if (cp[1] == '+' || cp[1] == '-') { 214 | strlcpy(exptmp, cp, fmtlen); 215 | exponent = exptmp; 216 | *cp = EOS; 217 | if (val != 0.0) { 218 | while (val < 1.0) { 219 | val *= 10.0; 220 | exp_val--; 221 | } 222 | while (val >= 10.0) { 223 | val /= 10.0; 224 | exp_val++; 225 | } 226 | } 227 | break; 228 | } 229 | } 230 | } 231 | 232 | /* 233 | * determine maximum decimal places and use sprintf 234 | * to build initial character form of formatted value. 235 | */ 236 | width = 0; 237 | if (decimal) { 238 | *decimal++ = EOS; 239 | for (cp = decimal; *cp != EOS; cp++) { 240 | switch (*cp) { 241 | case '\\': 242 | cp++; 243 | break; 244 | 245 | case '#': 246 | width++; 247 | break; 248 | 249 | case '0': 250 | zero_pad = ++width; 251 | break; 252 | 253 | case '&': 254 | width += lprecision; 255 | zero_pad = width; 256 | break; 257 | } 258 | } 259 | zero_pad = strlen(decimal) - zero_pad; 260 | } 261 | snprintf(prtfmt, sizeof prtfmt, "%%.%dlf", width); 262 | snprintf(mantissa, mantlen, prtfmt, val); 263 | for (cp = integer = mantissa; *cp != dpoint && *cp != EOS; cp++) { 264 | if (*integer == '0') 265 | integer++; 266 | } 267 | if (*cp == dpoint) { 268 | fraction = cp + 1; 269 | *cp = EOS; 270 | cp = fraction + strlen(fraction) - 1; 271 | for (; zero_pad > 0; zero_pad--, cp--) { 272 | if (*cp == '0') 273 | *cp = EOS; 274 | else 275 | break; 276 | } 277 | } else 278 | fraction = ""; 279 | 280 | /* 281 | * format the puppy 282 | */ 283 | { 284 | static char *citmp = NULL, *cftmp = NULL; 285 | static unsigned cilen = 0, cflen = 0; 286 | char *ci, *cf, *ce; 287 | unsigned int len_ci, len_cf, len_ce; 288 | bool ret = false; 289 | 290 | ci = fmt_int(integer, fmt, comma, negative); 291 | len_ci = strlen(ci); 292 | if (len_ci >= cilen) { 293 | cilen = len_ci + 40; 294 | citmp = scxrealloc(citmp, cilen); 295 | } 296 | strlcpy(citmp, ci, cilen); 297 | ci = citmp; 298 | 299 | cf = decimal ? fmt_frac(fraction, decimal, lprecision) : ""; 300 | len_cf = strlen(cf); 301 | if (len_cf >= cflen) { 302 | cflen = len_cf + 40; 303 | cftmp = scxrealloc(cftmp, cilen); 304 | } 305 | strlcpy(cftmp, cf, cilen); 306 | cf = cftmp; 307 | 308 | ce = (exponent) ? fmt_exp(exp_val, exponent) : ""; 309 | len_ce = strlen(ce); 310 | /* 311 | * Skip copy assuming sprintf doesn't call our format functions 312 | * ce = strcpy(scxmalloc((unsigned)((len_ce = strlen(ce)) + 1)), ce); 313 | */ 314 | if (len_ci + len_cf + len_ce < buflen) { 315 | snprintf(buf, buflen, "%s%s%s", ci, cf, ce); 316 | ret = true; 317 | } 318 | 319 | return (ret); 320 | } 321 | } 322 | 323 | /*****************************************************************************/ 324 | 325 | static char * 326 | fmt_int(char *val, /* integer part of the value to be formatted */ 327 | char *fmt, /* integer part of the format */ 328 | bool comma, /* true if we should comma-ify the value */ 329 | bool negative) /* true if the value is actually negative */ 330 | { 331 | int digit, f, v; 332 | int thousands = 0; 333 | char *cp; 334 | static char buf[MAXBUF]; 335 | char *bufptr = buf; 336 | 337 | /* 338 | * locate the leftmost digit placeholder 339 | */ 340 | for (cp = fmt; *cp != EOS; cp++) { 341 | if (*cp == '\\') 342 | cp++; 343 | else if (*cp == '#' || *cp == '0') 344 | break; 345 | } 346 | digit = (*cp == EOS) ? -1 : cp - fmt; 347 | 348 | /* 349 | * format the value 350 | */ 351 | f = strlen(fmt) - 1; 352 | v = (digit >= 0) ? (ssize_t)strlen(val) - 1 : -1; 353 | while (f >= 0 || v >= 0) { 354 | if (f > 0 && fmt[f-1] == '\\') { 355 | *bufptr++ = fmt[f--]; 356 | } else if (f >= 0 && (fmt[f] == '#' || fmt[f] == '0')) { 357 | if (v >= 0 || fmt[f] == '0') { 358 | *bufptr++ = v < 0 ? '0' : val[v]; 359 | if (comma && (thousands = (thousands + 1) % 3) == 0 && 360 | v > 0 && thsep != '\0') 361 | *bufptr++ = thsep; 362 | v--; 363 | } 364 | } else if (f >= 0) { 365 | *bufptr++ = fmt[f]; 366 | } 367 | if (v >= 0 && f == digit) { 368 | continue; 369 | } 370 | f--; 371 | } 372 | 373 | if (negative && digit >= 0) 374 | *bufptr++ = '-'; 375 | *bufptr = EOS; 376 | reverse(buf); 377 | 378 | return (buf); 379 | } 380 | 381 | /*****************************************************************************/ 382 | 383 | static char * 384 | fmt_frac(char *val, /* fractional part of the value to be formatted */ 385 | char *fmt, /* fractional portion of format */ 386 | int lprecision) /* precision, for interpreting the "&" */ 387 | { 388 | static char buf[MAXBUF]; 389 | register char *bufptr = buf; 390 | register char *fmtptr = fmt, *valptr = val; 391 | 392 | *bufptr++ = dpoint; 393 | while (*fmtptr != EOS) { 394 | if (*fmtptr == '&') { 395 | int i; 396 | for (i = 0; i < lprecision; i++) 397 | *bufptr++ = (*valptr != EOS) ? *valptr++ : '0'; 398 | } else if (*fmtptr == '\\') 399 | *bufptr++ = *++fmtptr; 400 | else if (*fmtptr == '#' || *fmtptr == '0') { 401 | if (*valptr != EOS || *fmtptr == '0') 402 | *bufptr++ = (*valptr != EOS) ? *valptr++ : '0'; 403 | } else 404 | *bufptr++ = *fmtptr; 405 | fmtptr++; 406 | } 407 | *bufptr = EOS; 408 | 409 | if (buf[1] < '0' || buf[1] > '9') 410 | return (buf + 1); 411 | else 412 | return (buf); 413 | } 414 | 415 | /*****************************************************************************/ 416 | 417 | static char * 418 | fmt_exp(int val, /* value of the exponent */ 419 | char *fmt) /* exponent part of the format */ 420 | { 421 | static char buf[MAXBUF]; 422 | register char *bufptr = buf; 423 | char valbuf[64]; 424 | bool negative = false; 425 | 426 | *bufptr++ = *fmt++; 427 | if (*fmt == '+') 428 | *bufptr++ = (val < 0) ? '-' : '+'; 429 | else if (val < 0) 430 | *bufptr++ = '-'; 431 | fmt++; 432 | *bufptr = EOS; 433 | 434 | if (val < 0) { 435 | val = -val; 436 | negative = false; 437 | } 438 | snprintf(valbuf, sizeof valbuf, "%d", val); 439 | 440 | strlcat(buf, fmt_int(valbuf, fmt, false, negative), sizeof buf); 441 | return (buf); 442 | } 443 | 444 | /*****************************************************************************/ 445 | 446 | static void 447 | reverse(register char *buf) 448 | { 449 | register char *cp = buf + strlen(buf) - 1; 450 | register char tmp; 451 | 452 | while (buf < cp) { 453 | tmp = *cp; 454 | *cp-- = *buf; 455 | *buf++ = tmp; 456 | } 457 | } 458 | 459 | /*****************************************************************************/ 460 | /* 461 | * Tom Anderson 462 | * 10/14/90 463 | * 464 | * This routine takes a value and formats it using fixed, scientific, 465 | * or engineering notation. The format command 'f' determines which 466 | * format is used. The formats are: example 467 | * 0: Fixed point (default) 0.00010 468 | * 1: Scientific 1.00E-04 469 | * 2: Engineering 100.00e-06 470 | * 471 | * The format command 'f' now uses three values. The first two are the 472 | * width and precision, and the last one is the format value 0, 1, or 2 as 473 | * described above. The format value is passed in the variable fmt. 474 | * 475 | * This formatted value is written into the passed buffer. if the 476 | * resulting string is too long to fit into the passed buffer, the 477 | * function returns false. Otherwise the function returns true. 478 | * 479 | * When a number is formatted as engineering and is outside of the range, 480 | * the format reverts to scientific. 481 | * 482 | * To preserve compatability with old spreadsheet files, the third value 483 | * may be missing, and the default will be fixed point (format 0). 484 | * 485 | * When an old style sheet is saved, the third value will be stored. 486 | * 487 | */ 488 | 489 | /* defined in sc.h */ 490 | #ifndef REFMTFIX 491 | #define REFMTFIX 0 492 | #define REFMTFLT 1 493 | #define REFMTENG 2 494 | #define REFMTDATE 3 495 | #define REFMTLDATE 4 496 | #endif 497 | 498 | bool 499 | engformat(int fmt, int width, int lprecision, double val, char *buf, int buflen) 500 | { 501 | 502 | static char *engmult[] = { 503 | "-18", "-15", "-12", "-09", "-06", "-03", 504 | "+00", 505 | "+03", "+06", "+09", "+12", "+15", "+18" 506 | }; 507 | int engind = 0; 508 | double engmant, engabs, engexp; 509 | 510 | if (buflen < width) return (false); 511 | if (fmt >= 0 && fmt < COLFORMATS && colformat[fmt]) 512 | return (format(colformat[fmt], lprecision, val, buf, buflen)); 513 | if (fmt == REFMTFIX) 514 | snprintf(buf, buflen, "%*.*f", width, lprecision, val); 515 | if (fmt == REFMTFLT) 516 | snprintf(buf, buflen, "%*.*E", width, lprecision, val); 517 | if (fmt == REFMTENG) { 518 | if (val == 0e0) { /* Hack to get zeroes to line up in engr fmt */ 519 | snprintf(buf - 1, buflen, "%*.*f ", width, lprecision, val); 520 | } else { 521 | engabs = (val); 522 | if ( engabs < 0e0) engabs = -engabs; 523 | if ((engabs >= 1e-18) && (engabs < 1e-15)) engind=0; 524 | if ((engabs >= 1e-15) && (engabs < 1e-12)) engind=1; 525 | if ((engabs >= 1e-12) && (engabs < 1e-9 )) engind=2; 526 | if ((engabs >= 1e-9) && (engabs < 1e-6 )) engind=3; 527 | if ((engabs >= 1e-6) && (engabs < 1e-3 )) engind=4; 528 | if ((engabs >= 1e-3) && (engabs < 1 )) engind=5; 529 | if ((engabs >= 1) && (engabs < 1e3 )) engind=6; 530 | if ((engabs >= 1e3) && (engabs < 1e6 )) engind=7; 531 | if ((engabs >= 1e6) && (engabs < 1e9 )) engind=8; 532 | if ((engabs >= 1e9) && (engabs < 1e12 )) engind=9; 533 | if ((engabs >= 1e12) && (engabs < 1e15 )) engind=10; 534 | if ((engabs >= 1e15) && (engabs < 1e18 )) engind=11; 535 | if ((engabs >= 1e18) && (engabs < 1e21 )) engind=12; 536 | if ((engabs < 1e-18) || (engabs >= 1e21 )) { 537 | /* Revert to floating point */ 538 | snprintf(buf, buflen, "%*.*E", width, lprecision, val); 539 | } else { 540 | engexp = (double) (engind-6)*3; 541 | engmant = val/pow(10.0e0,engexp); 542 | snprintf(buf, buflen, "%*.*fe%s", width-4, 543 | lprecision, engmant, engmult[engind]); 544 | } 545 | } 546 | } 547 | if (fmt == REFMTDATE) { 548 | int i; 549 | time_t secs; 550 | 551 | if (buflen < 9) { 552 | for (i = 0; i < width; i++) buf[i] = '*'; 553 | buf[i] = '\0'; 554 | } else { 555 | secs = (time_t)val; 556 | strftime(buf,buflen,"%e %b %y",localtime(&secs)); 557 | for (i = 9; i < width; i++) buf[i] = ' '; 558 | buf[i] = '\0'; 559 | } 560 | } 561 | if (fmt == REFMTLDATE) { 562 | int i; 563 | time_t secs; 564 | 565 | if (buflen < 11) { 566 | for (i = 0; i < width; i++) buf[i] = '*'; 567 | buf[i] = '\0'; 568 | } else { 569 | secs = (time_t)val; 570 | strftime(buf,buflen,"%e %b %Y",localtime(&secs)); 571 | for (i = 11; i < width; i++) buf[i] = ' '; 572 | buf[i] = '\0'; 573 | } 574 | } 575 | return (true); 576 | } 577 | -------------------------------------------------------------------------------- /frame.c: -------------------------------------------------------------------------------- 1 | /* SC A Spreadsheet Calculator 2 | * Framed range manipulation 3 | * 4 | * Chuck Martin 5 | * Originally created: December, 2000 6 | * 7 | * $Revision: 7.16 $ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "compat.h" 17 | #include "sc.h" 18 | 19 | static struct frange *frame_base; 20 | extern struct frange *lastfr; 21 | 22 | void 23 | add_frange(struct ent *or_left, struct ent *or_right, struct ent *ir_left, 24 | struct ent *ir_right, int toprows, int bottomrows, int leftcols, 25 | int rightcols) 26 | { 27 | struct frange *r; 28 | int minr, minc, maxr, maxc; 29 | 30 | minr = or_left->row < or_right->row ? or_left->row : or_right->row; 31 | minc = or_left->col < or_right->col ? or_left->col : or_right->col; 32 | maxr = or_left->row > or_right->row ? or_left->row : or_right->row; 33 | maxc = or_left->col > or_right->col ? or_left->col : or_right->col; 34 | 35 | or_left = lookat(minr, minc); 36 | or_right = lookat(maxr, maxc); 37 | 38 | if (ir_left) { 39 | minr = ir_left->row < ir_right->row ? ir_left->row : ir_right->row; 40 | minc = ir_left->col < ir_right->col ? ir_left->col : ir_right->col; 41 | maxr = ir_left->row > ir_right->row ? ir_left->row : ir_right->row; 42 | maxc = ir_left->col > ir_right->col ? ir_left->col : ir_right->col; 43 | 44 | ir_left = lookat(minr, minc); 45 | ir_right = lookat(maxr, maxc); 46 | 47 | if (ir_left->row < or_left->row || 48 | ir_left->col < or_left->col || 49 | ir_right->row > or_right->row || 50 | ir_right->col > or_right->col) { 51 | error("Invalid parameters"); 52 | return; 53 | } 54 | } 55 | 56 | if (frame_base) { 57 | /* 58 | * Has this frange already been created? If so, any negative 59 | * parameters mean "don't change this value." 60 | */ 61 | for (r = frame_base; r; r = r->r_next) { 62 | if ((r->or_left == or_left) && (r->or_right == or_right)) { 63 | if (ir_left) { 64 | r->ir_left = ir_left; 65 | r->ir_right = ir_right; 66 | } else { 67 | if (toprows < 0) 68 | toprows = r->ir_left->row - r->or_left->row; 69 | if (bottomrows < 0) 70 | bottomrows = r->or_right->row - r->ir_right->row; 71 | if (leftcols < 0) 72 | leftcols = r->ir_left->col - r->or_left->col; 73 | if (rightcols < 0) 74 | rightcols = r->or_right->col - r->ir_right->col; 75 | r->ir_left = lookat(r->or_left->row + toprows, 76 | r->or_left->col + leftcols); 77 | r->ir_right = lookat(r->or_right->row - bottomrows, 78 | r->or_right->col - rightcols); 79 | } 80 | 81 | /* If all frame sides are 0, delete the frange */ 82 | if (r->ir_left == r->or_left && r->ir_right == r->or_right) { 83 | if (r->r_next) 84 | r->r_next->r_prev = r->r_prev; 85 | if (r->r_prev) 86 | r->r_prev->r_next = r->r_next; 87 | else 88 | frame_base = r->r_next; 89 | scxfree((char *)r); 90 | if (lastfr == r) lastfr = NULL; 91 | } 92 | modflg++; 93 | FullUpdate++; 94 | return; 95 | } 96 | } 97 | /* 98 | * See if the specified range overlaps any previously created frange. 99 | */ 100 | for (r = frame_base; r; r = r->r_next) { 101 | if ( !(r->or_left->row > or_right->row || 102 | r->or_right->row < or_left->row || 103 | r->or_left->col > or_right->col || 104 | r->or_right->col < or_left->col)) { 105 | error("Framed ranges may not be nested or overlapping"); 106 | return; 107 | } 108 | } 109 | } 110 | 111 | if (ir_left != or_left || ir_right != or_right) { 112 | r = scxmalloc(sizeof(struct frange)); 113 | r->or_left = or_left; 114 | r->or_right = or_right; 115 | 116 | if (ir_left) { 117 | r->ir_left = ir_left; 118 | r->ir_right = ir_right; 119 | } else { 120 | if (toprows < 0) toprows = 0; 121 | if (bottomrows < 0) bottomrows = 0; 122 | if (leftcols < 0) leftcols = 0; 123 | if (rightcols < 0) rightcols = 0; 124 | r->ir_left = lookat(r->or_left->row + toprows, 125 | r->or_left->col + leftcols); 126 | r->ir_right = lookat(r->or_right->row - bottomrows, 127 | r->or_right->col - rightcols); 128 | } 129 | 130 | r->r_next = frame_base; 131 | r->r_prev = NULL; 132 | if (frame_base) 133 | frame_base->r_prev = r; 134 | frame_base = r; 135 | modflg++; 136 | FullUpdate++; 137 | } 138 | } 139 | 140 | void 141 | clean_frange(void) { 142 | register struct frange *fr; 143 | register struct frange *nextfr; 144 | 145 | fr = frame_base; 146 | frame_base = NULL; 147 | 148 | while (fr) { 149 | nextfr = fr->r_next; 150 | scxfree((char *)fr); 151 | fr = nextfr; 152 | } 153 | lastfr = NULL; 154 | } 155 | 156 | struct frange * 157 | find_frange(int row, int col) 158 | { 159 | struct frange *r; 160 | 161 | if (frame_base) 162 | for (r = frame_base; r; r = r->r_next) { 163 | if ((r->or_left->row <= row) && (r->or_left->col <= col) && 164 | (r->or_right->row >= row) && (r->or_right->col >= col)) 165 | return r; 166 | } 167 | return 0; 168 | } 169 | 170 | void 171 | sync_franges(void) 172 | { 173 | struct frange *fr; 174 | 175 | fr = frame_base; 176 | while (fr) { 177 | fr->or_left = lookat(fr->or_left->row, fr->or_left->col); 178 | fr->or_right = lookat(fr->or_right->row, fr->or_right->col); 179 | fr->ir_left = lookat(fr->ir_left->row, fr->ir_left->col); 180 | fr->ir_right = lookat(fr->ir_right->row, fr->ir_right->col); 181 | fr = fr->r_next; 182 | } 183 | } 184 | 185 | void 186 | write_franges(FILE *f) 187 | { 188 | register struct frange *r; 189 | register struct frange *nextr; 190 | 191 | for (r = nextr = frame_base; nextr; r = nextr, nextr = r->r_next) /**/ ; 192 | while (r) { 193 | fprintf(f, "frame %s", v_name(r->or_left->row, r->or_left->col)); 194 | fprintf(f, ":%s", v_name(r->or_right->row, r->or_right->col)); 195 | fprintf(f, " %s", v_name(r->ir_left->row, r->ir_left->col)); 196 | fprintf(f, ":%s\n", v_name(r->ir_right->row, r->ir_right->col)); 197 | 198 | r = r->r_prev; 199 | } 200 | } 201 | 202 | void 203 | list_frames(FILE *f) { 204 | register struct frange *r; 205 | register struct frange *nextr; 206 | 207 | if (!are_frames()) { 208 | fprintf(f, " No frames"); 209 | return; 210 | } 211 | 212 | (void) fprintf(f, " %-30s %s\n","Outer Range","Inner Range"); 213 | if (!brokenpipe) 214 | (void) fprintf(f, " %-30s %s\n","-----------","-----------"); 215 | 216 | for (r = nextr = frame_base; nextr; r = nextr, nextr = r->r_next) /* */ ; 217 | while (r) { 218 | fprintf(f, " %-30s", r_name(r->or_left->row, r->or_left->col, 219 | r->or_right->row, r->or_right->col)); 220 | fprintf(f, " %s\n", r_name(r->ir_left->row, r->ir_left->col, 221 | r->ir_right->row, r->ir_right->col)); 222 | if (brokenpipe) return; 223 | r = r->r_prev; 224 | } 225 | } 226 | 227 | int 228 | are_frames(void) { 229 | return (frame_base != 0); 230 | } 231 | 232 | void 233 | fix_frames(int row1, int col1, int row2, int col2, int delta1, int delta2) 234 | { 235 | int r1, r2, c1, c2; 236 | struct frange *fr, *cfr; 237 | 238 | cfr = find_frange(currow, curcol); 239 | if (frame_base) 240 | for (fr = frame_base; fr; fr = fr->r_next) { 241 | r1 = fr->or_left->row; 242 | c1 = fr->or_left->col; 243 | r2 = fr->or_right->row; 244 | c2 = fr->or_right->col; 245 | 246 | if (!(cfr && (c1 < cfr->or_left->col || c1 > cfr->or_right->col))) { 247 | if (r1 >= row1 && r1 <= row2) r1 = row2 - delta1; 248 | if (c1 >= col1 && c1 <= col2) c1 = col2 - delta1; 249 | } 250 | 251 | if (!(cfr && (c2 < cfr->or_left->col || c2 > cfr->or_right->col))) { 252 | if (r2 >= row1 && r2 <= row2) r2 = row1 + delta2; 253 | if (c2 >= col1 && c2 <= col2) c2 = col1 + delta2; 254 | } 255 | 256 | fr->or_left = lookat(r1, c1); 257 | fr->or_right = lookat(r2, c2); 258 | 259 | r1 = fr->ir_left->row; 260 | c1 = fr->ir_left->col; 261 | r2 = fr->ir_right->row; 262 | c2 = fr->ir_right->col; 263 | 264 | if (!(cfr && (c1 < cfr->or_left->col || c1 > cfr->or_right->col))) { 265 | if (r1 >= row1 && r1 <= row2) r1 = row2 - delta1; 266 | if (c1 >= col1 && c1 <= col2) c1 = col2 - delta1; 267 | } 268 | 269 | if (!(cfr && (c2 < cfr->or_left->col || c2 > cfr->or_right->col))) { 270 | if (r2 >= row1 && r2 <= row2) r2 = row1 + delta2; 271 | if (c2 >= col1 && c2 <= col2) c2 = col1 + delta2; 272 | } 273 | 274 | fr->ir_left = lookat(r1, c1); 275 | fr->ir_right = lookat(r2, c2); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /lex.c: -------------------------------------------------------------------------------- 1 | /* SC A Spreadsheet Calculator 2 | * Lexical analyser 3 | * 4 | * original by James Gosling, September 1982 5 | * modifications by Mark Weiser and Bruce Israel, 6 | * University of Maryland 7 | * 8 | * More mods Robert Bond, 12/86 9 | * More mods by Alan Silverstein, 3/88, see list of changes. 10 | * $Revision: 7.16 $ 11 | * 12 | */ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if defined(BSD42) || defined(BSD43) 21 | #include 22 | #endif 23 | 24 | #ifdef USE_IEEEFP_H 25 | # include 26 | #endif 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "compat.h" 35 | #include "sc.h" 36 | 37 | static void fpe_trap(int); 38 | 39 | #ifdef VMS 40 | # include "gram_tab.h" 41 | typedef union { 42 | int ival; 43 | double fval; 44 | struct ent *ent; 45 | struct enode *enode; 46 | char *sval; 47 | struct range_s rval; 48 | } YYSTYPE; 49 | extern YYSTYPE yylval; 50 | extern int VMS_read_raw; /*sigh*/ 51 | #else /* VMS */ 52 | # if defined(MSDOS) 53 | # include "y_tab.h" 54 | # else 55 | # include "y.tab.h" 56 | # endif /* MSDOS */ 57 | #endif /* VMS */ 58 | 59 | #ifdef hpux 60 | extern YYSTYPE yylval; 61 | #endif /* hpux */ 62 | 63 | jmp_buf wakeup; 64 | jmp_buf fpe_buf; 65 | 66 | bool decimal = FALSE; 67 | 68 | static void 69 | fpe_trap(int signo) 70 | { 71 | (void)signo; 72 | #if defined(i386) && !defined(M_XENIX) 73 | asm(" fnclex"); 74 | asm(" fwait"); 75 | #else 76 | # ifdef IEEE_MATH 77 | (void)fpsetsticky((fp_except)0); /* Clear exception */ 78 | # endif /* IEEE_MATH */ 79 | # ifdef PC 80 | _fpreset(); 81 | # endif 82 | #endif 83 | longjmp(fpe_buf, 1); 84 | } 85 | 86 | struct key { 87 | char *key; 88 | int val; 89 | }; 90 | 91 | struct key experres[] = { 92 | #include "experres.h" 93 | { 0, 0 } 94 | }; 95 | 96 | struct key statres[] = { 97 | #include "statres.h" 98 | { 0, 0 } 99 | }; 100 | 101 | int 102 | yylex(void) 103 | { 104 | char *p = line + linelim; 105 | int ret = -1; 106 | static int isfunc = 0; 107 | static bool isgoto = 0; 108 | static bool colstate = 0; 109 | static int dateflag; 110 | static char *tokenst = NULL; 111 | static size_t tokenl; 112 | 113 | while (isspace((int)*p)) p++; 114 | if (*p == '\0') { 115 | isfunc = isgoto = 0; 116 | ret = -1; 117 | } else if (isalpha((int)*p) || (*p == '_')) { 118 | register char *la; /* lookahead pointer */ 119 | register struct key *tblp; 120 | 121 | if (!tokenst) { 122 | tokenst = p; 123 | tokenl = 0; 124 | } 125 | /* 126 | * This picks up either 1 or 2 alpha characters (a column) or 127 | * tokens made up of alphanumeric chars and '_' (a function or 128 | * token or command or a range name) 129 | */ 130 | while (isalpha((int)*p) && isascii((int)*p)) { 131 | p++; 132 | tokenl++; 133 | } 134 | la = p; 135 | while (isdigit((int)*la) || (*la == '$')) 136 | la++; 137 | /* 138 | * A COL is 1 or 2 char alpha with nothing but digits following 139 | * (no alpha or '_') 140 | */ 141 | if (!isdigit((int)*tokenst) && tokenl && tokenl <= 2 && (colstate || 142 | (isdigit((int)*(la-1)) && !(isalpha((int)*la) || (*la == '_'))))) { 143 | ret = COL; 144 | yylval.ival = atocol(tokenst, tokenl); 145 | } else { 146 | while (isalpha((int)*p) || (*p == '_') || isdigit((int)*p)) { 147 | p++; 148 | tokenl++; 149 | } 150 | ret = WORD; 151 | if (!linelim || isfunc) { 152 | if (isfunc) isfunc--; 153 | for (tblp = linelim ? experres : statres; tblp->key; tblp++) 154 | if (((tblp->key[0] ^ tokenst[0]) & 0x5F) == 0) { 155 | /* Commenting the following line makes the search slower */ 156 | /* but avoids access outside valid memory. A BST would */ 157 | /* be the better alternative. */ 158 | /* && tblp->key[tokenl] == 0) { */ 159 | unsigned int i = 1; 160 | while (i < tokenl && ((tokenst[i] ^ tblp->key[i]) & 0x5F) == 0) 161 | i++; 162 | if (i >= tokenl) { 163 | ret = tblp->val; 164 | colstate = (ret <= S_FORMAT); 165 | if (isgoto) { 166 | isfunc = isgoto = 0; 167 | if (ret != K_ERROR && ret != K_INVALID) 168 | ret = WORD; 169 | } 170 | break; 171 | } 172 | } 173 | } 174 | if (ret == WORD) { 175 | struct range *r; 176 | char *path; 177 | if (!find_range(tokenst, tokenl, NULL, NULL, &r)) { 178 | yylval.rval.left = r->r_left; 179 | yylval.rval.right = r->r_right; 180 | if (r->r_is_range) 181 | ret = RANGE; 182 | else 183 | ret = VAR; 184 | } else if ((path = scxmalloc(PATHLEN)) && 185 | plugin_exists(tokenst, tokenl, path)) { 186 | strlcat(path, p, PATHLEN); 187 | yylval.sval = path; 188 | ret = PLUGIN; 189 | } else { 190 | scxfree(path); 191 | linelim = p-line; 192 | yyerror("Unintelligible word"); 193 | } 194 | } 195 | } 196 | } else if ((*p == '.') || isdigit((int)*p)) { 197 | #ifdef SIGVOID 198 | void (*sig_save)(int signum); 199 | #else 200 | int (*sig_save)(int signum); 201 | #endif 202 | double v = 0.0; 203 | int temp; 204 | char *nstart = p; 205 | 206 | sig_save = signal(SIGFPE, fpe_trap); 207 | if (setjmp(fpe_buf)) { 208 | (void) signal(SIGFPE, sig_save); 209 | yylval.fval = v; 210 | error("Floating point exception\n"); 211 | isfunc = isgoto = 0; 212 | tokenst = NULL; 213 | return FNUMBER; 214 | } 215 | 216 | if (*p=='.' && dateflag) { /* .'s in dates are returned as tokens. */ 217 | ret = *p++; 218 | dateflag--; 219 | } else { 220 | if (*p != '.') { 221 | tokenst = p; 222 | tokenl = 0; 223 | do { 224 | v = v*10.0 + (double) ((unsigned) *p - '0'); 225 | tokenl++; 226 | } while (isdigit((int)*++p)); 227 | if (dateflag) { 228 | ret = NUMBER; 229 | yylval.ival = (int)v; 230 | /* 231 | * If a string of digits is followed by two .'s separated by 232 | * one or two digits, assume this is a date and return the 233 | * .'s as tokens instead of interpreting them as decimal 234 | * points. dateflag counts the .'s as they're returned. 235 | */ 236 | } else if (*p=='.' && isdigit((int)*(p+1)) && (*(p+2)=='.' || 237 | (isdigit((int)*(p+2)) && *(p+3)=='.'))) { 238 | ret = NUMBER; 239 | yylval.ival = (int)v; 240 | dateflag = 2; 241 | } else if (*p == 'e' || *p == 'E') { 242 | while (isdigit((int)*++p)) /* */; 243 | if (isalpha((int)*p) || *p == '_') { 244 | linelim = p - line; 245 | return (yylex()); 246 | } else 247 | ret = FNUMBER; 248 | } else if (isalpha((int)*p) || *p == '_') { 249 | linelim = p - line; 250 | return (yylex()); 251 | } 252 | } 253 | if ((!dateflag && *p=='.') || ret == FNUMBER) { 254 | ret = FNUMBER; 255 | yylval.fval = strtod(nstart, &p); 256 | if (p == nstart) 257 | p++; 258 | else if (! 259 | #ifdef HAVE_ISFINITE 260 | isfinite( 261 | #else 262 | finite( 263 | #endif 264 | yylval.fval)) 265 | ret = K_ERR; 266 | else 267 | decimal = TRUE; 268 | } else { 269 | /* A NUMBER must hold at least MAXROW and MAXCOL */ 270 | /* This is consistent with a short row and col in struct ent */ 271 | if (v > (double)32767 || v < (double)-32768) { 272 | ret = FNUMBER; 273 | yylval.fval = v; 274 | } else { 275 | temp = (int)v; 276 | if((double)temp != v) { 277 | ret = FNUMBER; 278 | yylval.fval = v; 279 | } else { 280 | ret = NUMBER; 281 | yylval.ival = temp; 282 | } 283 | } 284 | } 285 | } 286 | (void) signal(SIGFPE, sig_save); 287 | } else if (*p=='"') { 288 | char *ptr; 289 | ptr = p+1; /* "string" or "string\"quoted\"" */ 290 | while (*ptr && ((*ptr != '"') || (*(ptr-1) == '\\'))) 291 | ptr++; 292 | ptr = scxmalloc(ptr-p); 293 | yylval.sval = ptr; 294 | p++; 295 | while (*p && ((*p != '"') || 296 | (*(p-1) == '\\' && *(p+1) != '\0' && *(p+1) != '\n'))) 297 | *ptr++ = *p++; 298 | *ptr = '\0'; 299 | if (*p) 300 | p++; 301 | ret = STRING; 302 | } else if (*p=='[') { 303 | while (*p && *p!=']') 304 | p++; 305 | if (*p) 306 | p++; 307 | linelim = p-line; 308 | tokenst = NULL; 309 | return yylex(); 310 | } else ret = *p++; 311 | linelim = p-line; 312 | if (!isfunc) isfunc = ((ret == '@') + (ret == S_GOTO) - (ret == S_SET)); 313 | if (ret == S_GOTO) isgoto = TRUE; 314 | tokenst = NULL; 315 | return ret; 316 | } 317 | 318 | /* 319 | * This is a very simpleminded test for plugins: does the file merely exist 320 | * in the plugin directories. Perhaps should test for it being executable 321 | */ 322 | 323 | int 324 | plugin_exists(char *name, size_t len, char *path) 325 | { 326 | #ifndef MSDOS 327 | struct stat sb; 328 | static char *homedir; 329 | 330 | if ((homedir = getenv("HOME"))) { 331 | if (strlcpy(path, homedir, len) >= len 332 | || strlcat(path, "/.sc/plugins/", len) >= len 333 | || strlcat(path, name, len) >= len) 334 | return 0; 335 | if (!stat(path, &sb)) 336 | return 1; 337 | } 338 | if (strlcpy(path, LIBDIR, len) >= len 339 | || strlcat(path, "/plugins/", len) >= len 340 | || strlcat(path, name, len) >= len) 341 | return 0; 342 | if (!stat(path, &sb)) 343 | return 1; 344 | #endif 345 | return 0; 346 | } 347 | 348 | /* 349 | * Given a token string starting with a symbolic column name and its valid 350 | * length, convert column name ("A"-"Z" or "AA"-"ZZ") to a column number (0-N). 351 | * Never mind if the column number is illegal (too high). The procedure's name 352 | * and function are the inverse of coltoa(). 353 | * 354 | * Case-insensitivity is done crudely, by ignoring the 040 bit. 355 | */ 356 | 357 | int 358 | atocol(char *string, int len) 359 | { 360 | register int col; 361 | 362 | col = (toupper((int)string[0])) - 'A'; 363 | 364 | if (len == 2) /* has second char */ 365 | col = ((col + 1) * 26) + ((toupper((int)string[1])) - 'A'); 366 | 367 | return (col); 368 | } 369 | 370 | 371 | #ifdef SIMPLE 372 | 373 | void 374 | initkbd(void) 375 | {} 376 | 377 | void 378 | kbd_again(void) 379 | {} 380 | 381 | void 382 | resetkbd(void) 383 | {} 384 | 385 | # ifndef VMS 386 | 387 | int 388 | nmgetch(void) 389 | { 390 | return (getchar()); 391 | } 392 | 393 | # else /* VMS */ 394 | 395 | int 396 | nmgetch(void) 397 | /* 398 | This is not perfect, it doesn't move the cursor when goraw changes 399 | over to deraw, but it works well enough since the whole sc package 400 | is incredibly stable (loop constantly positions cursor). 401 | 402 | Question, why didn't the VMS people just implement cbreak? 403 | 404 | NOTE: During testing it was discovered that the DEBUGGER and curses 405 | and this method of reading would collide (the screen was not updated 406 | when continuing from screen mode in the debugger). 407 | */ 408 | { 409 | short c; 410 | static int key_id=0; 411 | int status; 412 | # define VMScheck(a) {if (~(status = (a)) & 1) VMS_MSG (status);} 413 | 414 | if (VMS_read_raw) { 415 | VMScheck(smg$read_keystroke (&stdkb->_id, &c, 0, 0, 0)); 416 | } else 417 | c = getchar(); 418 | 419 | switch (c) { 420 | case SMG$K_TRM_LEFT: c = KEY_LEFT; break; 421 | case SMG$K_TRM_RIGHT: c = KEY_RIGHT; break; 422 | case SMG$K_TRM_UP: c = ctl('p'); break; 423 | case SMG$K_TRM_DOWN: c = ctl('n'); break; 424 | default: c = c & A_CHARTEXT; 425 | } 426 | return (c); 427 | } 428 | 429 | 430 | VMS_MSG (int status) 431 | /* 432 | Routine to put out the VMS operating system error (if one occurs). 433 | */ 434 | { 435 | # include 436 | char errstr[81], buf[120]; 437 | $DESCRIPTOR(errdesc, errstr); 438 | short length; 439 | # define err_out(msg) fprintf (stderr,msg) 440 | 441 | /* Check for no error or standard error */ 442 | 443 | if (~status & 1) { 444 | status = status & 0x8000 ? status & 0xFFFFFFF : status & 0xFFFF; 445 | if (SYS$GETMSG(status, &length, &errdesc, 1, 0) == SS$_NORMAL) { 446 | errstr[length] = '\0'; 447 | snprintf(buf, sizeof buf, "<0x%x> %s", status, 448 | errdesc.dsc$a_pointer); 449 | err_out(buf); 450 | } else 451 | err_out("System error"); 452 | } 453 | } 454 | # endif /* VMS */ 455 | 456 | #else /*SIMPLE*/ 457 | 458 | # if defined(BSD42) || defined (SYSIII) || defined(BSD43) 459 | 460 | # define N_KEY 4 461 | 462 | struct key_map { 463 | char *k_str; 464 | int k_val; 465 | char k_index; 466 | }; 467 | 468 | struct key_map km[N_KEY]; 469 | 470 | char keyarea[N_KEY*30]; 471 | 472 | char *ks; 473 | char ks_buf[20]; 474 | char *ke; 475 | char ke_buf[20]; 476 | 477 | # ifdef TIOCSLTC 478 | struct ltchars old_chars, new_chars; 479 | # endif 480 | 481 | char dont_use[] = { 482 | ctl('['), ctl('a'), ctl('b'), ctl('c'), ctl('e'), ctl('f'), ctl('g'), 483 | ctl('h'), ctl('i'), ctl('j'), ctl('l'), ctl('m'), ctl('n'), ctl('p'), 484 | ctl('q'), ctl('r'), ctl('s'), ctl('t'), ctl('u'), ctl('v'), ctl('w'), 485 | ctl('x'), ctl('z'), 0 486 | }; 487 | 488 | int 489 | charout(int c) { 490 | return putchar(c); 491 | } 492 | 493 | void 494 | initkbd(void) 495 | { 496 | register struct key_map *kp; 497 | register i,j; 498 | char *p = keyarea; 499 | char *ktmp; 500 | static char buf[1024]; /* Why do I have to do this again? */ 501 | 502 | if (!(ktmp = getenv("TERM"))) { 503 | (void) fprintf(stderr, "TERM environment variable not set\n"); 504 | exit (1); 505 | } 506 | if (tgetent(buf, ktmp) <= 0) 507 | return; 508 | 509 | km[0].k_str = tgetstr("kl", &p); km[0].k_val = KEY_LEFT; 510 | km[1].k_str = tgetstr("kr", &p); km[1].k_val = KEY_RIGHT; 511 | km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl('p'); 512 | km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl('n'); 513 | 514 | ktmp = tgetstr("ks",&p); 515 | if (ktmp) { 516 | strlcpy(ks_buf, ktmp, sizeof ks_buf); 517 | ks = ks_buf; 518 | tputs(ks, 1, charout); 519 | } 520 | ktmp = tgetstr("ke",&p); 521 | if (ktmp) { 522 | strlcpy(ke_buf, ktmp, sizeof ke_buf); 523 | ke = ke_buf; 524 | } 525 | 526 | /* Unmap arrow keys which conflict with our ctl keys */ 527 | /* Ignore unset, longer than length 1, and 1-1 mapped keys */ 528 | 529 | for (i = 0; i < N_KEY; i++) { 530 | kp = &km[i]; 531 | if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val)) 532 | for (j = 0; dont_use[j] != 0; j++) 533 | if (kp->k_str[0] == dont_use[j]) { 534 | kp->k_str = (char *)0; 535 | break; 536 | } 537 | } 538 | 539 | 540 | # ifdef TIOCSLTC 541 | (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars); 542 | new_chars = old_chars; 543 | if (old_chars.t_lnextc == ctl('v')) 544 | new_chars.t_lnextc = -1; 545 | if (old_chars.t_rprntc == ctl('r')) 546 | new_chars.t_rprntc = -1; 547 | (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars); 548 | # endif 549 | } 550 | 551 | void 552 | kbd_again(void) 553 | { 554 | if (ks) 555 | tputs(ks, 1, charout); 556 | 557 | # ifdef TIOCSLTC 558 | (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars); 559 | # endif 560 | } 561 | 562 | void 563 | resetkbd(void) 564 | { 565 | if (ke) 566 | tputs(ke, 1, charout); 567 | 568 | # ifdef TIOCSLTC 569 | (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars); 570 | # endif 571 | } 572 | 573 | int 574 | nmgetch(void) { 575 | register int c; 576 | register struct key_map *kp; 577 | register struct key_map *biggest; 578 | register int i; 579 | int almost; 580 | int maybe; 581 | 582 | static char dumpbuf[10]; 583 | static char *dumpindex; 584 | 585 | # ifdef SIGVOID 586 | void time_out(int); 587 | # else 588 | int time_out(int); 589 | # endif 590 | 591 | if (dumpindex && *dumpindex) 592 | return (*dumpindex++); 593 | 594 | c = getchar(); 595 | biggest = 0; 596 | almost = 0; 597 | 598 | for (kp = &km[0]; kp < &km[N_KEY]; kp++) { 599 | if (!kp->k_str) 600 | continue; 601 | if (c == kp->k_str[kp->k_index]) { 602 | almost = 1; 603 | kp->k_index++; 604 | if (kp->k_str[kp->k_index] == 0) { 605 | c = kp->k_val; 606 | for (kp = &km[0]; kp < &km[N_KEY]; kp++) 607 | kp->k_index = 0; 608 | return (c); 609 | } 610 | } 611 | if (!biggest && kp->k_index) 612 | biggest = kp; 613 | else if (kp->k_index && biggest->k_index < kp->k_index) 614 | biggest = kp; 615 | } 616 | 617 | if (almost) { 618 | (void) signal(SIGALRM, time_out); 619 | (void) alarm(1); 620 | 621 | if (setjmp(wakeup) == 0) { 622 | maybe = nmgetch(); 623 | (void) alarm(0); 624 | return (maybe); 625 | } 626 | } 627 | 628 | if (biggest) { 629 | for (i = 0; ik_index; i++) 630 | dumpbuf[i] = biggest->k_str[i]; 631 | if (!almost) 632 | dumpbuf[i++] = c; 633 | dumpbuf[i] = '\0'; 634 | dumpindex = &dumpbuf[1]; 635 | for (kp = &km[0]; kp < &km[N_KEY]; kp++) 636 | kp->k_index = 0; 637 | return (dumpbuf[0]); 638 | } 639 | 640 | return(c); 641 | } 642 | 643 | # endif /* if defined(BSD42) || defined (SYSIII) || defined(BSD43) */ 644 | 645 | void 646 | initkbd(void) 647 | { 648 | keypad(stdscr, TRUE); 649 | #ifndef NONOTIMEOUT 650 | notimeout(stdscr,TRUE); 651 | #endif 652 | } 653 | 654 | void 655 | kbd_again(void) 656 | { 657 | keypad(stdscr, TRUE); 658 | #ifndef NONOTIMEOUT 659 | notimeout(stdscr,TRUE); 660 | #endif 661 | } 662 | 663 | void 664 | resetkbd(void) 665 | { 666 | keypad(stdscr, FALSE); 667 | #ifndef NONOTIMEOUT 668 | notimeout(stdscr, FALSE); 669 | #endif 670 | } 671 | 672 | int 673 | nmgetch(void) { 674 | register int c; 675 | 676 | c = getch(); 677 | switch (c) { 678 | # ifdef KEY_SELECT 679 | case KEY_SELECT: c = 'm'; break; 680 | # endif 681 | # ifdef KEY_C1 682 | /* This stuff works for a wyse wy75 in ANSI mode under 5.3. Good luck. */ 683 | /* It is supposed to map the curses keypad back to the numeric equiv. */ 684 | 685 | /* I had to disable this to make programmable function keys work. I'm 686 | * not familiar with the wyse wy75 terminal. Does anyone know how to 687 | * make this work without causing problems with programmable function 688 | * keys on everything else? - CRM 689 | 690 | case KEY_C1: c = '0'; break; 691 | case KEY_A1: c = '1'; break; 692 | case KEY_B2: c = '2'; break; 693 | case KEY_A3: c = '3'; break; 694 | case KEY_F(5): c = '4'; break; 695 | case KEY_F(6): c = '5'; break; 696 | case KEY_F(7): c = '6'; break; 697 | case KEY_F(9): c = '7'; break; 698 | case KEY_F(10): c = '8'; break; 699 | case KEY_F0: c = '9'; break; 700 | case KEY_C3: c = '.'; break; 701 | case KEY_ENTER: c = ctl('m'); break; 702 | 703 | * 704 | * 705 | */ 706 | # endif 707 | default: break; 708 | } 709 | return (c); 710 | } 711 | 712 | #endif /* SIMPLE */ 713 | 714 | #ifdef SIGVOID 715 | void 716 | #else 717 | int 718 | #endif 719 | time_out(int signo) 720 | { 721 | (void)signo; 722 | longjmp(wakeup, 1); 723 | } 724 | -------------------------------------------------------------------------------- /pipe.c: -------------------------------------------------------------------------------- 1 | /* SC A Spreadsheet Calculator 2 | * Routines for piping data to and from an external macro program 3 | * 4 | * Chuck Martin 5 | * Original Version Created: June, 2000 6 | * 7 | * $Revision: 7.16 $ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "compat.h" 15 | #include "sc.h" 16 | 17 | void 18 | getnum(int r0, int c0, int rn, int cn, int fd) 19 | { 20 | struct ent **pp; 21 | struct ent *p; 22 | int r, c; 23 | 24 | for (r = r0; r <= rn; r++) { 25 | for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { 26 | *line = '\0'; 27 | p = *pp; 28 | if (p) { 29 | if (p->cellerror) 30 | snprintf(line, sizeof line, "%s", (*pp)->cellerror == CELLERROR ? 31 | "ERROR" : "INVALID"); 32 | else if (p->flags & IS_VALID) 33 | snprintf(line, sizeof line, "%.15g", p->v); 34 | } 35 | if (c < cn) 36 | strlcat(line, "\t", sizeof line); 37 | else 38 | strlcat(line, "\n", sizeof line); 39 | write(fd, line, strlen(line)); 40 | if (brokenpipe) { 41 | linelim = -1; 42 | return; 43 | } 44 | } 45 | } 46 | linelim = -1; 47 | } 48 | 49 | void 50 | fgetnum(int r0, int c0, int rn, int cn, int fd) 51 | { 52 | struct ent **pp; 53 | struct ent *p; 54 | int r, c; 55 | 56 | for (r = r0; r <= rn; r++) { 57 | for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { 58 | *line = '\0'; 59 | p = *pp; 60 | if (p) { 61 | if (p->cellerror) 62 | snprintf(line, sizeof line, "%s", p->cellerror == CELLERROR ? 63 | "ERROR" : "INVALID"); 64 | else if (p->flags & IS_VALID) { 65 | if (p->format) { 66 | if (*(p->format) == ctl('d')) { 67 | time_t i = (time_t) (p->v); 68 | strftime(line, sizeof(line), (p->format)+1, 69 | localtime(&i)); 70 | } else 71 | format(p->format, precision[c], p->v, line, 72 | sizeof(line)); 73 | } else 74 | engformat(realfmt[c], fwidth[c], precision[c], 75 | p->v, line, sizeof(line)); 76 | } 77 | } 78 | if (c < cn) 79 | strlcat(line, "\t", sizeof line); 80 | else 81 | strlcat(line, "\n", sizeof line); 82 | write(fd, line, strlen(line)); 83 | if (brokenpipe) { 84 | linelim = -1; 85 | return; 86 | } 87 | } 88 | } 89 | linelim = -1; 90 | } 91 | 92 | void 93 | getstring(int r0, int c0, int rn, int cn, int fd) 94 | { 95 | struct ent **pp; 96 | int r, c; 97 | 98 | for (r = r0; r <= rn; r++) { 99 | for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { 100 | *line = '\0'; 101 | if (*pp && (*pp)->label) 102 | snprintf(line, sizeof line, "%s", (*pp)->label); 103 | if (c < cn) 104 | strlcat(line, "\t", sizeof line); 105 | else 106 | strlcat(line, "\n", sizeof line); 107 | write(fd, line, strlen(line)); 108 | if (brokenpipe) { 109 | linelim = -1; 110 | return; 111 | } 112 | } 113 | } 114 | linelim = -1; 115 | } 116 | 117 | void 118 | getexp(int r0, int c0, int rn, int cn, int fd) 119 | { 120 | struct ent **pp; 121 | struct ent *p; 122 | int r, c; 123 | 124 | for (r = r0; r <= rn; r++) { 125 | for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { 126 | *line = '\0'; 127 | p = *pp; 128 | if (p && p->expr) { 129 | linelim = 0; 130 | decompile(p->expr, 0); /* set line to expr */ 131 | line[linelim] = '\0'; 132 | if (*line == '?') 133 | *line = '\0'; 134 | } 135 | if (c < cn) 136 | strlcat(line, "\t", sizeof line); 137 | else 138 | strlcat(line, "\n", sizeof line); 139 | write(fd, line, strlen(line)); 140 | if (brokenpipe) { 141 | linelim = -1; 142 | return; 143 | } 144 | } 145 | } 146 | linelim = -1; 147 | } 148 | 149 | void 150 | getformat(int col, int fd) 151 | { 152 | snprintf(line, sizeof line, "%d %d %d\n", fwidth[col], precision[col], realfmt[col]); 153 | write(fd, line, strlen(line)); 154 | linelim = -1; 155 | } 156 | 157 | void 158 | getfmt(int r0, int c0, int rn, int cn, int fd) 159 | { 160 | struct ent **pp; 161 | int r, c; 162 | 163 | for (r = r0; r <= rn; r++) { 164 | for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { 165 | *line = '\0'; 166 | if (*pp && (*pp)->format) 167 | snprintf(line, sizeof line, "%s", (*pp)->format); 168 | if (c < cn) 169 | strlcat(line, "\t", sizeof line); 170 | else 171 | strlcat(line, "\n", sizeof line); 172 | write(fd, line, strlen(line)); 173 | if (brokenpipe) { 174 | linelim = -1; 175 | return; 176 | } 177 | } 178 | } 179 | linelim = -1; 180 | } 181 | 182 | void 183 | getframe(int fd) 184 | { 185 | struct frange *fr; 186 | size_t l; 187 | 188 | *line = '\0'; 189 | if ((fr = find_frange(currow, curcol))) { 190 | snprintf(line, sizeof line, "%s", r_name(fr->or_left->row, fr->or_left->col, 191 | fr->or_right->row, fr->or_right->col)); 192 | strlcat(line, " ", sizeof line); 193 | l = strlen(line); 194 | snprintf(line + l, sizeof(line) - l, "%s", r_name(fr->ir_left->row, 195 | fr->ir_left->col, fr->ir_right->row, fr->ir_right->col)); 196 | } 197 | strlcat(line, "\n", sizeof line); 198 | write(fd, line, strlen(line)); 199 | linelim = -1; 200 | } 201 | 202 | void 203 | getrange(char *name, int fd) 204 | { 205 | struct range *r; 206 | char *p; 207 | 208 | *line = '\0'; 209 | if (!find_range(name, strlen(name), (struct ent *)0, (struct ent *)0, &r)) { 210 | snprintf(line, sizeof line, "%s%s%s%d", 211 | r->r_left.vf & FIX_COL ? "$" : "", 212 | coltoa(r->r_left.vp->col), 213 | r->r_left.vf & FIX_ROW ? "$" : "", 214 | r->r_left.vp->row); 215 | if (r->r_is_range) { 216 | p = line; 217 | while (*p) 218 | p++; 219 | snprintf(p, sizeof(line) - (p - line), ":%s%s%s%d", 220 | r->r_right.vf & FIX_COL ? "$" : "", 221 | coltoa(r->r_right.vp->col), 222 | r->r_right.vf & FIX_ROW ? "$" : "", 223 | r->r_right.vp->row); 224 | } 225 | /************************************************/ 226 | /* */ 227 | /* if(r->r_is_range) */ 228 | /* sprintf(line,"%d:%d:%d:%d", */ 229 | /* r->r_left.vp->col, */ 230 | /* r->r_left.vp->row, */ 231 | /* r->r_right.vp->col, */ 232 | /* r->r_right.vp->row); */ 233 | /* else */ 234 | /* sprintf(line,"%d:%d", */ 235 | /* r->r_left.vp->col, */ 236 | /* r->r_left.vp->row); */ 237 | /* */ 238 | /************************************************/ 239 | } 240 | strlcat(line, "\n", sizeof line); 241 | write(fd, line, strlen(line)); 242 | linelim = -1; 243 | } 244 | 245 | void 246 | doeval(struct enode *e, char *fmt, int row, int col, int fd) 247 | { 248 | double v; 249 | 250 | gmyrow = row; 251 | gmycol = col; 252 | 253 | v = eval(e); 254 | if (fmt) { 255 | if (*fmt == ctl('d')) { 256 | time_t tv = v; 257 | strftime(line, FBUFLEN, fmt + 1, localtime(&tv)); 258 | } else 259 | format(fmt, precision[col], v, line, FBUFLEN); 260 | } else 261 | snprintf(line, sizeof line, "%.15g", v); 262 | strlcat(line, "\n", sizeof line); 263 | write(fd, line, strlen(line)); 264 | linelim = -1; 265 | 266 | efree(e); 267 | if (fmt) scxfree(fmt); 268 | } 269 | 270 | void 271 | doseval(struct enode *e, int row, int col, int fd) 272 | { 273 | char *s; 274 | 275 | gmyrow = row; 276 | gmycol = col; 277 | 278 | s = seval(e); 279 | if (s) 280 | write(fd, s, strlen(s)); 281 | write(fd, "\n", 1); 282 | linelim = -1; 283 | 284 | efree(e); 285 | if (s) 286 | scxfree(s); 287 | } 288 | 289 | 290 | void 291 | doquery(char *s, char *data, int fd) 292 | { 293 | goraw(); 294 | query(s, data); 295 | deraw(0); 296 | if (linelim >= 0) { 297 | write(fd, line, strlen(line)); 298 | write(fd, "\n", 1); 299 | } 300 | 301 | line[0] = '\0'; 302 | linelim = -1; 303 | CLEAR_LINE; 304 | update(0); 305 | 306 | if (s) scxfree(s); 307 | } 308 | 309 | void 310 | dogetkey(void) { 311 | int c, len; 312 | 313 | goraw(); 314 | c = nmgetch(); 315 | deraw(0); 316 | 317 | if (c < 256) { 318 | snprintf(line, sizeof line, "%c", c); 319 | len = 1; 320 | #ifdef HAVE_CURSES_KEYNAME 321 | } else if (c >= KEY_MIN && c <= KEY_MAX) { 322 | int i, j; 323 | line[0] = '\0'; 324 | snprintf(line + 1, sizeof(line) - 1, "%s\n", keyname(c)); 325 | for (i = 1, j = 5; line[j-1]; ) { 326 | if (line[j] == '(' || line[j] == ')') 327 | j++; 328 | else 329 | line[i++] = line[j++]; 330 | } 331 | len = strlen(line + 1) + 1; 332 | #endif 333 | } else { 334 | line[0] = '0'; 335 | snprintf(line + 1, sizeof(line) - 1, "UNKNOWN KEY"); 336 | len = strlen(line + 1) + 1; 337 | } 338 | 339 | 340 | write(macrofd, line, len); 341 | } 342 | 343 | void 344 | dostat(int fd) 345 | { 346 | *line = '\0'; 347 | if (modflg) snprintf(line, sizeof line, "m"); 348 | if (isatty(STDIN_FILENO)) strlcat(line, "i", sizeof line); 349 | if (isatty(STDOUT_FILENO)) strlcat(line, "o", sizeof line); 350 | strlcat(line, "\n", sizeof line); 351 | write(fd, line, strlen(line)); 352 | linelim = -1; 353 | } 354 | -------------------------------------------------------------------------------- /psc.c: -------------------------------------------------------------------------------- 1 | /* Sc parse routine 2 | * 3 | * usage psc options 4 | * options: 5 | * -L Left justify strings. Default is right justify. 6 | * -r Assemble data into rows first, not columns. 7 | * -R n Increment by n between rows 8 | * -C n Increment by n between columns 9 | * -n n Length of the row (column) should be n. 10 | * -s v Top left location in the spreadsheet should be v; eg, k5 11 | * -d c Use c as the delimiter between the fields. 12 | * -k Keep all delimiters - Default is strip multiple delimiters to 1. 13 | * -f suppress 'format' lines in output 14 | * -S Use strings vs numbers for numbers 15 | * -P Use numbers only when there is no [-+eE] (plain numbers only) 16 | * 17 | * Author: Robert Bond 18 | * Adjustments: Jeff Buhrt, Eric Putz and Chuck Martin 19 | */ 20 | 21 | #include "version.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifdef HAVE_STDBOOL_H 28 | # include 29 | #else 30 | # if !HAVE__BOOL 31 | # define _Bool int 32 | # endif 33 | # define bool _Bool 34 | # define true 1 35 | # define false 0 36 | #endif 37 | #include 38 | #include 39 | #include 40 | #include "sc.h" 41 | 42 | #define END 0 43 | #define NUM 1 44 | #define ALPHA 2 45 | #define SPACE 3 46 | #define EOL 4 47 | 48 | #define PRINTF_CMD_ERR(x) ": Writing command \"" x "\": %s\n" 49 | 50 | char *coltoa(int col); 51 | char *progname; 52 | int getrow(char *p); 53 | int getcol(char *p); 54 | static int scan(void); 55 | 56 | int *fwidth; 57 | int *precision; 58 | int maxcols; 59 | int *realfmt; 60 | 61 | static int curlen; 62 | int curcol; 63 | static int coff; 64 | int currow; 65 | static int roff; 66 | static int first; 67 | static int effr, effc; 68 | static int exit_status = EXIT_SUCCESS; 69 | 70 | /* option flags reset */ 71 | static int colfirst = FALSE; 72 | static int leftadj = FALSE; 73 | static int r0 = 0; 74 | static int c0 = 0; 75 | static int rinc = 1; 76 | static int cinc = 1; 77 | static int len = 20000; 78 | static char delim1 = ' '; 79 | static char delim2 = '\t'; 80 | static int strip_delim = TRUE; 81 | static int drop_format = FALSE; 82 | static int strnums = FALSE; 83 | static int plainnums = FALSE; 84 | 85 | static char token[1000]; 86 | 87 | int 88 | main(int argc, char **argv) 89 | { 90 | int c; 91 | int i, j; 92 | register char *p; 93 | 94 | progname = argv[0]; 95 | while ((c = getopt(argc, argv, "rfLks:R:C:n:d:SPv")) != EOF) { 96 | switch (c) { 97 | case 'r': 98 | colfirst = TRUE; 99 | break; 100 | case 'L': 101 | leftadj = TRUE; 102 | break; 103 | case 's': 104 | c0 = getcol(optarg); 105 | r0 = getrow(optarg); 106 | break; 107 | case 'R': 108 | rinc = atoi(optarg); 109 | break; 110 | case 'C': 111 | cinc = atoi(optarg); 112 | break; 113 | case 'n': 114 | len = atoi(optarg); 115 | break; 116 | case 'd': 117 | delim1 = optarg[0]; 118 | delim2 = '\0'; 119 | break; 120 | case 'k': 121 | strip_delim = FALSE; 122 | break; 123 | case 'f': 124 | drop_format = TRUE; 125 | break; 126 | case 'S': 127 | strnums = TRUE; 128 | break; 129 | case 'P': 130 | plainnums = TRUE; 131 | break; 132 | case 'v': 133 | fprintf(stderr,"%s: %s\n", progname, rev); 134 | return 0; 135 | default: 136 | exit(EXIT_FAILURE); 137 | } 138 | } 139 | 140 | if (optind < argc) { 141 | fprintf(stderr, "%s: %d more argument(s) than expected\n", 142 | progname, argc - optind); 143 | exit(EXIT_FAILURE); 144 | } 145 | 146 | /* setup the spreadsheet arrays */ 147 | if (!growtbl(GROWNEW, 0, 0)) 148 | exit(EXIT_FAILURE); 149 | 150 | curlen = 0; 151 | curcol = c0; coff = 0; 152 | currow = r0; roff = 0; 153 | first = TRUE; 154 | 155 | while (1) { 156 | 157 | effr = currow+roff; 158 | effc = curcol+coff; 159 | 160 | switch (scan()) { 161 | case END: 162 | if (drop_format) exit(exit_status); 163 | 164 | for (i = 0; i= maxcols - 1) { 187 | if (!growtbl(GROWCOL, 0, effc)) { 188 | fprintf(stderr, "Invalid column used: %s\n", coltoa(effc)); 189 | exit_status = EXIT_FAILURE; 190 | continue; 191 | } 192 | } 193 | 194 | i = 0; 195 | j = 0; 196 | p = token; 197 | 198 | while (*p && *p != '.') { 199 | p++; i++; 200 | } 201 | 202 | if (*p) { 203 | p++; i++; 204 | } 205 | 206 | while (*p) { 207 | p++; i++; j++; 208 | } 209 | 210 | { 211 | int ow, nw; 212 | 213 | ow = fwidth[effc] - precision[effc]; 214 | 215 | if (precision[effc] < j) 216 | precision[effc] = j; 217 | 218 | if (fwidth[effc] < i) 219 | fwidth[effc] = i; 220 | 221 | /* now make sure: 222 | * 1234.567890 (format 11 6) 223 | * 1234567.890 (format 11 3) 224 | * both show (format 14 6) 225 | * (really it uses 15 6 to separate columns) 226 | */ 227 | if ((nw = i - j) > ow) 228 | fwidth[effc] += nw - (fwidth[effc] - precision[effc]); 229 | } 230 | break; 231 | case ALPHA: 232 | first = FALSE; 233 | 234 | { 235 | const char *cmd = leftadj ? "leftstring" : "rightstring"; 236 | 237 | if (printf("%s %s%d = \"%s\"\n", cmd, coltoa(effc),effr,token) < 0) { 238 | fprintf(stderr, "%s: Writing command \"%s\": %s\n", progname, 239 | cmd, strerror(errno)); 240 | exit_status = EXIT_FAILURE; 241 | } 242 | } 243 | 244 | if (effc >= maxcols - 1 && !growtbl(GROWCOL, 0, effc)) { 245 | fprintf(stderr, "Invalid column used: %s\n", coltoa(effc)); 246 | exit_status = EXIT_FAILURE; 247 | continue; 248 | } 249 | 250 | i = strlen(token); 251 | 252 | if (i > fwidth[effc]) { 253 | fwidth[effc] = i; 254 | } 255 | 256 | break; 257 | case SPACE: 258 | if (first && strip_delim) 259 | break; 260 | if (colfirst) 261 | roff++; 262 | else 263 | coff++; 264 | break; 265 | case EOL: 266 | curlen++; 267 | roff = 0; 268 | coff = 0; 269 | first = TRUE; 270 | if (colfirst) { 271 | if (curlen >= len) { 272 | curcol = c0; 273 | currow += rinc; 274 | curlen = 0; 275 | } else { 276 | curcol += cinc; 277 | } 278 | } else { 279 | if (curlen >= len) { 280 | currow = r0; 281 | curcol += cinc; 282 | curlen = 0; 283 | } else { 284 | currow += rinc; 285 | } 286 | } 287 | break; 288 | } 289 | } 290 | } 291 | 292 | static int 293 | scan(void) { 294 | register int c; 295 | register char *p; 296 | register int founddigit; 297 | 298 | p = token; 299 | c = getchar(); 300 | 301 | if (c == EOF) 302 | return (END); 303 | 304 | if (c == '\n') 305 | return (EOL); 306 | 307 | if (c == delim1 || c == delim2) { 308 | if (strip_delim) { 309 | while ((c = getchar()) && (c == delim1 || c == delim2)) 310 | ; 311 | (void)ungetc(c, stdin); 312 | } 313 | return (SPACE); 314 | } 315 | 316 | if (c == '\"') { 317 | while ((c = getchar()) && c != '\"' && c != '\n' && c != EOF) 318 | *p++ = c; 319 | if (c != '\"') 320 | (void)ungetc(c, stdin); 321 | *p = '\0'; 322 | return (ALPHA); 323 | } 324 | 325 | while (c != delim1 && c != delim2 && c!= '\n' && c != EOF) { 326 | *p++ = c; 327 | c = getchar(); 328 | } 329 | *p = '\0'; 330 | (void)ungetc(c, stdin); 331 | 332 | p = token; 333 | c = *p; 334 | founddigit = FALSE; 335 | /* 336 | * str_nums always returns numbers as strings 337 | * plainnums returns 'numbers' with [-+eE] in them as strings 338 | * lastprtnum makes sure a number ends in one of [0-9eE.] 339 | */ 340 | if (!strnums && (isdigit(c) || c == '.' || c == '-' || c == '+')) { 341 | int lastprtnum = FALSE; 342 | 343 | while (isdigit(c) || c == '.' || (!plainnums && (c == '-' || 344 | c == '+' || c == 'e' || c == 'E'))) { 345 | if (isdigit(c)) 346 | lastprtnum = founddigit = TRUE; 347 | else 348 | if (!(c == '.' || c == 'e' || c == 'E')) 349 | lastprtnum = FALSE; 350 | c = *p++; 351 | } 352 | if (c == '\0' && founddigit && lastprtnum) 353 | return (NUM); 354 | else 355 | return (ALPHA); 356 | } 357 | 358 | return (ALPHA); 359 | } 360 | 361 | /* turns [A-Z][A-Z] into a number */ 362 | int 363 | getcol(char *p) 364 | { 365 | int col; 366 | 367 | col = 0; 368 | if (!p) 369 | return (0); 370 | while (*p && !isalpha((int)*p)) 371 | p++; 372 | if (!*p) 373 | return (0); 374 | col = (toupper((int)*p) - 'A'); 375 | if (isalpha((int)*++p)) 376 | col = (col + 1)*26 + (toupper((int)*p) - 'A'); 377 | return (col); 378 | } 379 | 380 | /* given a string turn it into a row number */ 381 | int 382 | getrow(char *p) 383 | { 384 | int row; 385 | 386 | row = 0; 387 | if (!p) 388 | return (0); 389 | while (*p && !isdigit((int)*p)) 390 | p++; 391 | if (!*p) 392 | return (0); 393 | while (*p && isdigit((int)*p)) { 394 | row = row * 10 + *p - '0'; 395 | p++; 396 | } 397 | return (row); 398 | } 399 | 400 | /* turns a column number into [A-Z][A-Z] */ 401 | char * 402 | coltoa(int col) 403 | { 404 | static char rname[3]; 405 | register char *p = rname; 406 | 407 | if (col < 0 || col > 27*26) { /* A-Z, AA-ZZ */ 408 | fprintf(stderr,"coltoa: invalid col: %d", col); 409 | exit_status = EXIT_FAILURE; 410 | } 411 | 412 | if (col > 25) { 413 | *p++ = col/26 + 'A' - 1; 414 | col %= 26; 415 | } 416 | 417 | *p++ = col+'A'; 418 | *p = '\0'; 419 | return (rname); 420 | } 421 | -------------------------------------------------------------------------------- /psc.doc: -------------------------------------------------------------------------------- 1 | .\" $Revision: 7.16 $ 2 | .TH PPNAME 1 "19 September 2002" "PPNAME #REVISION#" 3 | .SH NAME 4 | ppname \- prepare pname files 5 | .SH SYNOPSIS 6 | .B ppname 7 | .RB [ -fLkrSPv ] 8 | .RB [ -s 9 | .IB cell ] 10 | .RB [ -R 11 | .IB n ] 12 | .RB [ -C 13 | .IB n ] 14 | .RB [ -n 15 | .IB n ] 16 | .RB [ -d 17 | .IB c ] 18 | .\" ========== 19 | .SH DESCRIPTION 20 | .I Ppname 21 | is used to prepare data for input to the spreadsheet calculator 22 | .I pname(1). 23 | It accepts normal ascii data on standard input. Standard output 24 | is a 25 | .I pname 26 | file. 27 | With no options, 28 | .I ppname 29 | starts the spreadsheet in cell A0. Strings are right justified. 30 | All data on a line is entered on the same row; new input lines 31 | cause the output row number to increment by one. The default delimiters 32 | are tab and space. The column formats are set to one larger 33 | than the number of columns required to hold the largest value 34 | in the column. 35 | .\" ---------- 36 | .SH OPTIONS 37 | .\" ---------- 38 | .TP 39 | .B \-f 40 | Omit column width calculations. This option is for preparing 41 | data to be merged with an existing spreadsheet. If the option is not 42 | specified, the column widths calculated for the data read by 43 | .I ppname 44 | will override those already set in the existing spreadsheet. 45 | .\" ---------- 46 | .TP 47 | .B \-L 48 | Left justify strings. 49 | .\" ---------- 50 | .TP 51 | .B \-k 52 | Keep all delimiters. This option causes the output cell to change on 53 | each new delimiter encountered in the input stream. The default 54 | action is to condense multiple delimiters to one, so that the cell only 55 | changes once per input data item. 56 | .\" ---------- 57 | .TP 58 | .B \-r 59 | Output the data by row first then column. For input consisting of a single 60 | column, this 61 | option will result in output of one row with multiple columns 62 | instead of a single 63 | column spreadsheet. 64 | .\" ---------- 65 | .TP 66 | .BI \-s " cell" 67 | Start the top left corner of the spreadsheet in 68 | .I cell. 69 | For example, 70 | .I "-s B33" 71 | will arrange the output data so that the 72 | spreadsheet starts in column B, row 33. 73 | .\" ---------- 74 | .TP 75 | .BI \-R " n" 76 | Increment by 77 | .I n 78 | on each new output row. 79 | .\" ---------- 80 | .TP 81 | .BI \-C " n" 82 | Increment by 83 | .I n 84 | on each new output column. 85 | .\" ---------- 86 | .TP 87 | .BI \-n " n" 88 | Output 89 | .I n 90 | rows before advancing to the next column. This option is used when 91 | the input is arranged in a single column and the spreadsheet is to 92 | have multiple columns, each of which is to be length 93 | .I n. 94 | .\" ---------- 95 | .TP 96 | .BI \-d " c" 97 | Use the single character 98 | .I c 99 | as the delimiter between input fields. 100 | .\" ---------- 101 | .TP 102 | .B \-P 103 | Plain numbers only. 104 | A field is a number only when there is no imbedded [-+eE]. 105 | .\" ---------- 106 | .TP 107 | .B \-S 108 | All numbers are strings. 109 | .\" ---------- 110 | .TP 111 | .B \-v 112 | Print the version of 113 | ppname 114 | .\" ---------- 115 | .SH SEE ALSO 116 | pname(1) 117 | 118 | .SH AUTHOR 119 | 120 | Robert Bond 121 | -------------------------------------------------------------------------------- /range.c: -------------------------------------------------------------------------------- 1 | 2 | /* SC A Spreadsheet Calculator 3 | * Range Manipulations 4 | * 5 | * Robert Bond, 4/87 6 | * 7 | * $Revision: 7.16 $ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "compat.h" 17 | #include "sc.h" 18 | 19 | static struct range *rng_base; 20 | void sync_enode(struct enode *e); 21 | void fix_enode(struct enode *e, int row1, int col1, int row2, int col2, 22 | int delta1, int delta2); 23 | 24 | void 25 | add_range(char *name, struct ent_ptr left, struct ent_ptr right, int is_range) 26 | { 27 | struct range *r; 28 | register char *p; 29 | int minr, minc, maxr, maxc; 30 | int minrf, mincf, maxrf, maxcf; 31 | register struct ent *rcp; 32 | struct range *prev = 0; 33 | 34 | if (left.vp->row < right.vp->row) { 35 | minr = left.vp->row; minrf = left.vf & FIX_ROW; 36 | maxr = right.vp->row; maxrf = right.vf & FIX_ROW; 37 | } else { 38 | minr = right.vp->row; minrf = right.vf & FIX_ROW; 39 | maxr = left.vp->row; maxrf = right.vf & FIX_ROW; 40 | } 41 | 42 | if (left.vp->col < right.vp->col) { 43 | minc = left.vp->col; mincf = left.vf & FIX_COL; 44 | maxc = right.vp->col; maxcf = right.vf & FIX_COL; 45 | } else { 46 | minc = right.vp->col; mincf = right.vf & FIX_COL; 47 | maxc = left.vp->col; maxcf = left.vf & FIX_COL; 48 | } 49 | 50 | left.vp = lookat(minr, minc); 51 | left.vf = minrf | mincf; 52 | right.vp = lookat(maxr, maxc); 53 | right.vf = maxrf | maxcf; 54 | 55 | if (!find_range(name, strlen(name), (struct ent *)0, (struct ent *)0, 56 | &prev)) { 57 | error("Error: range name \"%s\" already defined", name); 58 | scxfree(name); 59 | return; 60 | } 61 | 62 | for (p = name; *p; p++) 63 | if (!(isalpha((int)*p) || isdigit((int)*p) || *p == '_')) { 64 | error("Invalid range name \"%s\" - illegal combination", name); 65 | scxfree(name); 66 | return; 67 | } 68 | 69 | p = name; 70 | if (isdigit((int)*p) || (isalpha((int)*p++) && (isdigit((int)*p) || 71 | (isalpha((int)*p++) && isdigit((int)*p))))) { 72 | if (*name == '0' && (name[1] == 'x' || name[1] == 'X')) { 73 | ++p; 74 | while (isxdigit((int)*++p)) /* */; 75 | if (*p == 'p' || *p == 'P') 76 | while (isxdigit((int)*++p)) /* */; 77 | } else { 78 | while (isdigit((int)*++p)) /* */; 79 | if (isdigit((int)*name) && (*p == 'e' || *p == 'E')) 80 | while (isdigit((int)*++p)) /* */; 81 | } 82 | if (!(*p)) { 83 | error("Invalid range name \"%s\" - ambiguous", name); 84 | scxfree(name); 85 | return; 86 | } 87 | } 88 | 89 | if (autolabel && minc>0 && !is_range) { 90 | rcp = lookat(minr, minc-1); 91 | if (rcp->label==0 && rcp->expr==0 && rcp->v==0) 92 | label(rcp, name, 0); 93 | } 94 | 95 | r = scxmalloc(sizeof(struct range)); 96 | r->r_name = name; 97 | r->r_left = left; 98 | r->r_right = right; 99 | r->r_is_range = is_range; 100 | if (prev) { 101 | r->r_next = prev->r_next; 102 | r->r_prev = prev; 103 | prev->r_next = r; 104 | if (r->r_next) 105 | r->r_next->r_prev = r; 106 | } else { 107 | r->r_next = rng_base; 108 | r->r_prev = (struct range *)0; 109 | if (rng_base) 110 | rng_base->r_prev = r; 111 | rng_base = r; 112 | } 113 | modflg++; 114 | } 115 | 116 | void 117 | del_range(struct ent *left, struct ent *right) 118 | { 119 | struct range *r; 120 | int minr, minc, maxr, maxc; 121 | 122 | minr = left->row < right->row ? left->row : right->row; 123 | minc = left->col < right->col ? left->col : right->col; 124 | maxr = left->row > right->row ? left->row : right->row; 125 | maxc = left->col > right->col ? left->col : right->col; 126 | 127 | left = lookat(minr, minc); 128 | right = lookat(maxr, maxc); 129 | 130 | if (find_range((char *)0, 0, left, right, &r)) 131 | return; 132 | 133 | if (r->r_next) 134 | r->r_next->r_prev = r->r_prev; 135 | if (r->r_prev) 136 | r->r_prev->r_next = r->r_next; 137 | else 138 | rng_base = r->r_next; 139 | scxfree((char *)(r->r_name)); 140 | scxfree((char *)r); 141 | modflg++; 142 | } 143 | 144 | void 145 | clean_range(void) { 146 | register struct range *r; 147 | register struct range *nextr; 148 | 149 | r = rng_base; 150 | rng_base = (struct range *)0; 151 | 152 | while (r) { 153 | nextr = r->r_next; 154 | scxfree((char *)(r->r_name)); 155 | scxfree((char *)r); 156 | r = nextr; 157 | } 158 | } 159 | 160 | /* Match on name or lmatch, rmatch */ 161 | 162 | int 163 | find_range(char *name, int len, struct ent *lmatch, struct ent *rmatch, 164 | struct range **rng) 165 | { 166 | struct range *r; 167 | int cmp; 168 | int exact = TRUE; 169 | 170 | if (len < 0) { 171 | exact = FALSE; 172 | len = -len; 173 | } 174 | 175 | if (name) { 176 | for (r = rng_base; r; r = r->r_next) { 177 | if ((cmp = strncmp(name, r->r_name, len)) > 0) 178 | return (cmp); 179 | *rng = r; 180 | if (cmp == 0) 181 | if (!exact || strlen(r->r_name) == (size_t)len) 182 | return (cmp); 183 | } 184 | return (-1); 185 | } 186 | 187 | for (r = rng_base; r; r = r->r_next) { 188 | if ((lmatch == r->r_left.vp) && (rmatch == r->r_right.vp)) { 189 | *rng = r; 190 | return (0); 191 | } 192 | } 193 | return (-1); 194 | } 195 | 196 | void 197 | sync_ranges(void) 198 | { 199 | int i, j; 200 | struct range *r; 201 | struct ent *p; 202 | 203 | for (r = rng_base; r; r = r->r_next) { 204 | r->r_left.vp = lookat(r->r_left.vp->row, r->r_left.vp->col); 205 | r->r_right.vp = lookat(r->r_right.vp->row, r->r_right.vp->col); 206 | } 207 | for (i=0; i<=maxrow; i++) 208 | for (j=0; j<=maxcol; j++) 209 | if ((p = *ATBL(tbl,i,j)) && p->expr) 210 | sync_enode(p->expr); 211 | sync_franges(); 212 | sync_cranges(); 213 | } 214 | 215 | void 216 | sync_enode(struct enode *e) 217 | { 218 | if (e) { 219 | if ((e->op & REDUCE)) { 220 | e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col); 221 | e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col); 222 | } else if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST) { 223 | sync_enode(e->e.o.left); 224 | sync_enode(e->e.o.right); 225 | } 226 | } 227 | } 228 | 229 | void 230 | write_ranges(FILE *f) 231 | { 232 | register struct range *r; 233 | register struct range *nextr; 234 | 235 | for (r = nextr = rng_base; nextr; r = nextr, nextr = r->r_next) /* */ ; 236 | while (r) { 237 | (void) fprintf(f, "define \"%s\" %s%s%s%d", 238 | r->r_name, 239 | r->r_left.vf & FIX_COL ? "$":"", 240 | coltoa(r->r_left.vp->col), 241 | r->r_left.vf & FIX_ROW ? "$":"", 242 | r->r_left.vp->row); 243 | if (r->r_is_range) 244 | (void) fprintf(f, ":%s%s%s%d\n", 245 | r->r_right.vf & FIX_COL ? "$":"", 246 | coltoa(r->r_right.vp->col), 247 | r->r_right.vf & FIX_ROW ? "$":"", 248 | r->r_right.vp->row); 249 | else 250 | (void) fprintf(f, "\n"); 251 | r = r->r_prev; 252 | } 253 | } 254 | 255 | void 256 | list_ranges(FILE *f) 257 | { 258 | register struct range *r; 259 | register struct range *nextr; 260 | 261 | if (!are_ranges()) { 262 | fprintf(f, " No ranges defined"); 263 | return; 264 | } 265 | 266 | (void) fprintf(f, " %-30s %s\n","Name","Definition"); 267 | if (!brokenpipe) (void) fprintf(f, " %-30s %s\n","----","----------"); 268 | 269 | for (r = nextr = rng_base; nextr; r = nextr, nextr = r->r_next) /* */ ; 270 | while (r) { 271 | (void) fprintf(f, " %-30s %s%s%s%d", 272 | r->r_name, 273 | r->r_left.vf & FIX_COL ? "$":"", 274 | coltoa(r->r_left.vp->col), 275 | r->r_left.vf & FIX_ROW ? "$":"", 276 | r->r_left.vp->row); 277 | if (brokenpipe) return; 278 | if (r->r_is_range) 279 | (void) fprintf(f, ":%s%s%s%d\n", 280 | r->r_right.vf & FIX_COL ? "$":"", 281 | coltoa(r->r_right.vp->col), 282 | r->r_right.vf & FIX_ROW ? "$":"", 283 | r->r_right.vp->row); 284 | else 285 | (void) fprintf(f, "\n"); 286 | if (brokenpipe) return; 287 | r = r->r_prev; 288 | } 289 | } 290 | 291 | char * 292 | v_name(int row, int col) 293 | { 294 | struct ent *v; 295 | struct range *r; 296 | static char buf[20]; 297 | 298 | v = lookat(row, col); 299 | if (!find_range((char *)0, 0, v, v, &r)) { 300 | return (r->r_name); 301 | } else { 302 | snprintf(buf, sizeof buf, "%s%d", coltoa(col), row); 303 | return (buf); 304 | } 305 | } 306 | 307 | char * 308 | r_name(int r1, int c1, int r2, int c2) 309 | { 310 | struct ent *v1, *v2; 311 | struct range *r; 312 | static char buf[100]; 313 | 314 | v1 = lookat(r1, c1); 315 | v2 = lookat(r2, c2); 316 | if (!find_range((char *)0, 0, v1, v2, &r)) { 317 | return (r->r_name); 318 | } else { 319 | size_t l; 320 | snprintf(buf, sizeof buf, "%s", v_name(r1, c1)); 321 | l = strlen(buf); 322 | snprintf(buf + l, sizeof(buf) - l, ":%s", v_name(r2, c2)); 323 | return (buf); 324 | } 325 | } 326 | 327 | int 328 | are_ranges(void) { 329 | return (rng_base != 0); 330 | } 331 | 332 | void 333 | fix_ranges(int row1, int col1, int row2, int col2, int delta1, int delta2) 334 | { 335 | int r1, r2, c1, c2, i, j; 336 | struct range *r; 337 | struct frange *fr; 338 | struct ent *p; 339 | 340 | fr = find_frange(currow, curcol); 341 | 342 | /* First we fix all of the named ranges. */ 343 | if (rng_base) 344 | for (r = rng_base; r; r = r->r_next) { 345 | r1 = r->r_left.vp->row; 346 | c1 = r->r_left.vp->col; 347 | r2 = r->r_right.vp->row; 348 | c2 = r->r_right.vp->col; 349 | 350 | if (!(fr && (c1 < fr->or_left->col || c1 > fr->or_right->col))) { 351 | if (r1 >= row1 && r1 <= row2) r1 = row2 - delta1; 352 | if (c1 >= col1 && c1 <= col2) c1 = col2 - delta1; 353 | } 354 | 355 | if (!(fr && (c2 < fr->or_left->col || c2 > fr->or_right->col))) { 356 | if (r2 >= row1 && r2 <= row2) r2 = row1 + delta2; 357 | if (c2 >= col1 && c2 <= col2) c2 = col1 + delta2; 358 | } 359 | r->r_left.vp = lookat(r1, c1); 360 | r->r_right.vp = lookat(r2, c2); 361 | } 362 | 363 | /* Next, we go through all valid cells with expressions and fix any ranges 364 | * that need fixing. 365 | */ 366 | for (i=0; i<=maxrow; i++) 367 | for (j=0; j<=maxcol; j++) 368 | if ((p = *ATBL(tbl,i,j)) && p->expr) 369 | fix_enode(p->expr, row1, col2, row2, col2, delta1, delta2); 370 | fix_frames(row1, col1, row2, col2, delta1, delta2); 371 | fix_colors(row1, col1, row2, col2, delta1, delta2); 372 | } 373 | 374 | void 375 | fix_enode(struct enode *e, int row1, int col1, int row2, int col2, 376 | int delta1, int delta2) 377 | { 378 | if (e) { 379 | if ((e->op & REDUCE)) { 380 | int r, c; 381 | int r1, c1, r2, c2; 382 | struct frange *fr; 383 | 384 | fr = find_frange(currow, curcol); 385 | r1 = e->e.r.left.vp->row; 386 | c1 = e->e.r.left.vp->col; 387 | r2 = e->e.r.right.vp->row; 388 | c2 = e->e.r.right.vp->col; 389 | if (r1>r2) r = r2, r2 = r1, r1 = r; 390 | if (c1>c2) c = c2, c2 = c1, c1 = c; 391 | 392 | if (!(fr && (c1 < fr->or_left->col || c1 > fr->or_right->col))) { 393 | if (r1 != r2 && r1 >= row1 && r1 <= row2) r1 = row2 - delta1; 394 | if (c1 != c2 && c1 >= col1 && c1 <= col2) c1 = col2 - delta1; 395 | } 396 | 397 | if (!(fr && (c2 < fr->or_left->col || c2 > fr->or_right->col))) { 398 | if (r1 != r2 && r2 >= row1 && r2 <= row2) r2 = row1 + delta2; 399 | if (c1 != c2 && c2 >= col1 && c2 <= col2) c2 = col1 + delta2; 400 | } 401 | e->e.r.left.vp = lookat(r1, c1); 402 | e->e.r.right.vp = lookat(r2, c2); 403 | 404 | } else if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST) { 405 | fix_enode(e->e.o.left, row1, col1, row2, col2, delta1, delta2); 406 | fix_enode(e->e.o.right, row1, col1, row2, col2, delta1, delta2); 407 | } 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /sc-7.16.lsm: -------------------------------------------------------------------------------- 1 | Begin4 2 | Title: sc Spreadsheet Calculator 3 | Version: 7.16 4 | Entered-date: 2002-9-19 5 | Description: sc is a free curses-based spreadsheet program that uses 6 | key bindings similar to vi and less. 7 | Keywords: spreadsheet calculator console textmode curses ncurses 8 | Author: Too numerous to mention. 9 | Maintained-by: nrocinu@myrealbox.com (Chuck Martin) 10 | Primary-site: ibiblio.org /pub/Linux/apps/financial/spreadsheet 11 | Alternate-site: 12 | Original-site: 13 | Platforms: Pre-7.x versions presumably worked on any Unix or Unix 14 | clone, as well as VMS and DOS. Hopefully, this is still 15 | true, but it's only been tested on Linux. 16 | Copying-policy: Public domain 17 | End 18 | -------------------------------------------------------------------------------- /scqref.doc: -------------------------------------------------------------------------------- 1 | .\" Carsten Kunze, 2016 2 | .Dd April 11, 2016 3 | .Dt PNAMEQREF 1 4 | .Sh NAME 5 | .Nm pnameqref 6 | .Nd output quick reference card in roff's 7 | .Fl ms 8 | format 9 | .Sh SYNOPSIS 10 | .Nm 11 | .Li | Ar "roff postprocessing ..." 12 | .Sh DESCRIPTION 13 | .Nm 14 | outputs a quick reference card for 15 | .Nm sc 16 | in roff's 17 | .Fl ms 18 | format. 19 | This output needs to be postprocessed by a roff tool 20 | to format it suited to be viewed or printed. 21 | .Sh EXAMPLES 22 | Generate PDF document with traditional troff: 23 | .Bd -filled -offset indent 24 | .Nm 25 | .Li | troff -ms | dpost | ps2pdf - Ar filename Ns Li .pdf 26 | .Ed 27 | .Pp 28 | .No The same using Nm groff : 29 | .Bd -filled -offset indent 30 | .Nm 31 | .Li | troff -Tpdf -ms | gropdf > Ar filename Ns Li .pdf 32 | .Ed 33 | .Pp 34 | View in a text terminal: 35 | .Bd -filled -offset indent 36 | .Nm 37 | .Li | nroff -ms | less 38 | .Ed 39 | .\" vim:set syntax=groff: 40 | -------------------------------------------------------------------------------- /sort.c: -------------------------------------------------------------------------------- 1 | /* SC A Spreadsheet Calculator 2 | * Sorting routines 3 | * 4 | * Chuck Martin 5 | * Originally created: April, 2001 6 | * 7 | * $Revision: 7.16 $ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "compat.h" 18 | #include "sc.h" 19 | 20 | int compare(const void *row1, const void *row2); 21 | 22 | static struct sortcrit { 23 | int direction, type, column; 24 | } *sort; 25 | 26 | static int howmany; 27 | 28 | void 29 | sortrange(struct ent *left, struct ent *right, char *criteria) 30 | { 31 | int minr, minc, maxr, maxc, r, c; 32 | int *rows, col = 0; 33 | int cp = 0; 34 | struct ent *p; 35 | 36 | minr = left->row < right->row ? left->row : right->row; 37 | minc = left->col < right->col ? left->col : right->col; 38 | maxr = left->row > right->row ? left->row : right->row; 39 | maxc = left->col > right->col ? left->col : right->col; 40 | 41 | sort = scxmalloc((2 * sizeof(struct sortcrit))); 42 | rows = scxmalloc((maxr - minr + 1) * sizeof(int)); 43 | for (r = minr, c = 0; r <= maxr; r++, c++) 44 | rows[c] = r; 45 | 46 | if (!criteria) { 47 | sort[0].direction = 1; 48 | sort[0].type = 1; 49 | sort[0].column = minc; 50 | sort[1].direction = 1; 51 | sort[1].type = 0; 52 | sort[1].column = minc; 53 | howmany = 2; 54 | } else 55 | for (howmany = 0; criteria[cp]; howmany++) { 56 | if (howmany > 1) 57 | sort = scxrealloc(sort, 58 | (howmany + 1) * (sizeof(struct sortcrit))); 59 | switch (criteria[cp++]) { 60 | case '+': 61 | sort[howmany].direction = 1; 62 | break; 63 | case '-': 64 | sort[howmany].direction = -1; 65 | break; 66 | default: 67 | error("Invalid sort criteria"); 68 | return; 69 | } 70 | switch (criteria[cp++]) { 71 | case '#': 72 | sort[howmany].type = 0; 73 | break; 74 | case '$': 75 | sort[howmany].type = 1; 76 | break; 77 | default: 78 | error("Invalid sort criteria"); 79 | return; 80 | } 81 | if (criteria[cp]) 82 | col = toupper((int)criteria[cp++]) - 'A'; 83 | else { 84 | error("Invalid sort criteria"); 85 | return; 86 | } 87 | if (criteria[cp] && criteria[cp] != '+' && criteria[cp] != '-') 88 | col = (col + 1) * 26 + toupper((int)criteria[cp++]) - 'A'; 89 | sort[howmany].column = col; 90 | if (col < minc || col > maxc) { 91 | error("Invalid sort criteria"); 92 | return; 93 | } 94 | } 95 | 96 | qsort(rows, maxr - minr + 1, sizeof(int), compare); 97 | erase_area(minr, minc, maxr, maxc, 1); 98 | sync_ranges(); 99 | for (c = 0, p = delbuf[dbidx]; p; p = p->next) { 100 | if (rows[c] != p->row) { 101 | for (c = 0; c <= maxr - minr && rows[c] != p->row; c++) ; 102 | if (c > maxr - minr) { 103 | error("sort error"); 104 | return; 105 | } 106 | } 107 | p->row = minr + c; 108 | } 109 | scxfree((char *)sort); 110 | scxfree((char *)rows); 111 | if (criteria) scxfree(criteria); 112 | 113 | r = currow; 114 | c = curcol; 115 | currow = minr; 116 | curcol = minc; 117 | 118 | pullcells('m'); 119 | flush_saved(); 120 | 121 | currow = r; 122 | curcol = c; 123 | } 124 | 125 | int 126 | compare(const void *row1, const void *row2) 127 | { 128 | struct ent *p1; 129 | struct ent *p2; 130 | double diff; 131 | int result = 0; 132 | int i; 133 | 134 | for (i = 0; !result && i < howmany; i++) { 135 | p1 = *ATBL(tbl, *((const int *) row1), sort[i].column); 136 | p2 = *ATBL(tbl, *((const int *) row2), sort[i].column); 137 | 138 | if (sort[i].type) { 139 | if (p1 && p1->label) 140 | if (p2 && p2->label) 141 | result = strcmp(p1->label, p2->label); 142 | else 143 | result = -1; 144 | else if (p2 && p2->label) 145 | result = 1; 146 | } else 147 | if (p1 && p2 && p1->flags & IS_VALID && p2->flags & IS_VALID) { 148 | diff = (p1->v - p2->v); 149 | result = (diff > 0 ? 1 : diff < 0 ? -1 : 0); 150 | } 151 | else if (p1 && p1->flags & IS_VALID) 152 | result = -1; 153 | else if (p2 && p2->flags & IS_VALID) 154 | result = 1; 155 | 156 | result *= sort[i].direction; 157 | } 158 | 159 | if (!result) 160 | result = (*((const int *) row1) - *((const int *) row2)); 161 | 162 | return (result); 163 | } 164 | -------------------------------------------------------------------------------- /sres.sed: -------------------------------------------------------------------------------- 1 | /%token.*S_/!d 2 | /%token.*S_\(.*\)/s// { "\1", S_\1 },/ 3 | -------------------------------------------------------------------------------- /torev: -------------------------------------------------------------------------------- 1 | REVISION=`sed -e '/Revision/!D' -e 's/.*$Revision: \(.*\) $.*/\1/' ${SRCDIR}/version.c` 2 | sed -e s/pname/$name/g -e s/PNAME/$NAME/g \ 3 | -e "s%#LIBDIR#%$LIBDIR%g" \ 4 | -e "s/#REVISION#/$REVISION/" \ 5 | -e 's/\\T[^]*//g;s/\\T//g;s/\\A[^]*//g' $1 6 | -------------------------------------------------------------------------------- /tutorial.sc: -------------------------------------------------------------------------------- 1 | # This data file was generated by the Spreadsheet Calculator. 2 | # You almost certainly shouldn't edit it. 3 | 4 | define "page5" A81:H100 5 | define "page4" A61:H80 6 | define "page3" A41:H60 7 | define "page2" A21:H40 8 | define "page1" A0:H20 9 | leftstring A1 = "This is a brief sc tutorial, best run in a 24-line window." 10 | leftstring A2 = "Type 'q' to exit, ^Z to suspend (w/ Job Control)." 11 | leftstring A3 = "^G interrupts a command." 12 | leftstring A5 = "Cells are named by their column and row number. For example," 13 | leftstring A6 = "Cell A6" 14 | leftstring B6 = "Cell B6" 15 | leftstring C6 = "Cell C6" 16 | leftstring A7 = "Cell A7" 17 | leftstring A8 = "Cell A8" 18 | leftstring C8 = "Cell C8" 19 | leftstring A9 = "Cells range from A0 to ZZ(some number depending on free memory)." 20 | leftstring A10 = "Cells can also be named by the user. See 'range names' in the manual." 21 | leftstring A11 = "You can move the cursor a couple of different ways:" 22 | leftstring B12 = "^n, j and the arrow key go down" 23 | leftstring B13 = "^p, k and the arrow key go up" 24 | leftstring B14 = "^h, h and the arrow key go left" 25 | leftstring B15 = ", l and the arrow key go right" 26 | leftstring B16 = "You can go directly to a cell by typing 'g' and the cell name. " 27 | leftstring B17 = "'g c6' will take you to cell c6." 28 | leftstring A18 = "Cells can contain numbers, formulas, or text." 29 | leftstring A19 = "Most of the cells on this page contain text." 30 | leftstring C20 = "" 31 | leftstring A22 = "Cell d22 contains text" 32 | leftstring D22 = "Text " 33 | leftstring A23 = "Cell d23 contains a number" 34 | let D23 = 123.34 35 | leftstring A24 = "Cell d24 contains a formula" 36 | let D24 = D23+88 37 | leftstring A26 = "To see what the cell contains, just move the cursor" 38 | leftstring A27 = "onto the cell. The contents will show up on line 1 in the brackets." 39 | leftstring A29 = "You can enter data into cells like this:" 40 | leftstring B30 = "' 15 | #endif /* PSC */ 16 | 17 | #include 18 | #include 19 | #include "compat.h" 20 | #include "sc.h" 21 | 22 | /* 23 | * check to see if *rowp && *colp are currently allocated, if not expand the 24 | * current size if we can. 25 | */ 26 | #ifndef PSC 27 | void 28 | checkbounds(int *rowp, int *colp) 29 | { 30 | if (*rowp < 0) 31 | *rowp = 0; 32 | else if (*rowp >= maxrows) { 33 | if (*colp >= maxcols) { 34 | if (!growtbl(GROWBOTH, *rowp, *colp)) { 35 | *rowp = maxrows - 1; 36 | *colp = maxcols - 1; 37 | } 38 | return; 39 | } else { 40 | if (!growtbl(GROWROW, *rowp, 0)) 41 | *rowp = maxrows - 1; 42 | return; 43 | } 44 | } 45 | if (*colp < 0) 46 | *colp = 0; 47 | else if (*colp >= maxcols) { 48 | if (!growtbl(GROWCOL, 0, *colp)) 49 | *colp = maxcols - 1; 50 | } 51 | } 52 | #endif /* !PSC */ 53 | 54 | /* scxrealloc will just scxmalloc if oldptr is == NULL */ 55 | #define GROWALLOC(newptr, oldptr, nelem, type, msg) \ 56 | newptr = scxrealloc(oldptr, \ 57 | nelem * sizeof(type)); \ 58 | if (newptr == (type *)NULL) { \ 59 | error(msg); \ 60 | return (FALSE); \ 61 | } \ 62 | oldptr = newptr /* wait incase we can't alloc */ 63 | 64 | #ifndef PSC 65 | static const char nolonger[] = "The table can't be any longer"; 66 | #endif /* !PSC */ 67 | 68 | static const char nowider[] = "The table can't be any wider"; 69 | 70 | /* 71 | * grow the main && auxiliary tables (reset maxrows/maxcols as needed) 72 | * toprow &&/|| topcol tell us a better guess of how big to become. 73 | * we return TRUE if we could grow, FALSE if not.... 74 | */ 75 | int 76 | growtbl(int rowcol, int toprow, int topcol) 77 | { 78 | int *fwidth2; 79 | int *precision2; 80 | int *realfmt2; 81 | int newcols; 82 | #ifndef PSC 83 | struct ent ***tbl2; 84 | struct ent ** nullit; 85 | int cnt; 86 | char *col_hidden2; 87 | char *row_hidden2; 88 | int newrows; 89 | int i; 90 | 91 | newrows = maxrows; 92 | #endif /* !PSC */ 93 | (void)toprow; /* unused */ 94 | newcols = maxcols; 95 | if (rowcol == GROWNEW) { 96 | #ifndef PSC 97 | maxrows = toprow = 0; 98 | /* when we first start up, fill the screen w/ cells */ 99 | { int startval; 100 | startval = LINES - RESROW; 101 | newrows = startval > MINROWS ? startval : MINROWS; 102 | startval = ((COLS) - rescol) / DEFWIDTH; 103 | newcols = startval > MINCOLS ? startval : MINCOLS; 104 | } 105 | #else 106 | newcols = MINCOLS; 107 | #endif /* !PSC */ 108 | maxcols = topcol = 0; 109 | } 110 | #ifndef PSC 111 | /* set how much to grow */ 112 | if ((rowcol == GROWROW) || (rowcol == GROWBOTH)) { 113 | if (toprow > maxrows) 114 | newrows = GROWAMT + toprow; 115 | else 116 | newrows += GROWAMT; 117 | } 118 | #endif /* !PSC */ 119 | if ((rowcol == GROWCOL) || (rowcol == GROWBOTH)) { 120 | if ((rowcol == GROWCOL) && ((maxcols == ABSMAXCOLS) || 121 | (topcol >= ABSMAXCOLS))) { 122 | error(nowider); 123 | return (FALSE); 124 | } 125 | 126 | if (topcol > maxcols) 127 | newcols = GROWAMT + topcol; 128 | else 129 | newcols += GROWAMT; 130 | 131 | if (newcols > ABSMAXCOLS) 132 | newcols = ABSMAXCOLS; 133 | } 134 | 135 | #ifndef PSC 136 | if ((rowcol == GROWROW) || (rowcol == GROWBOTH) || (rowcol == GROWNEW)) { 137 | struct ent *** lnullit; 138 | int lcnt; 139 | 140 | GROWALLOC(row_hidden2, row_hidden, newrows, char, nolonger); 141 | memset(row_hidden+maxrows, 0, (newrows-maxrows)*sizeof(char)); 142 | 143 | /* 144 | * alloc tbl row pointers, per net.lang.c, calloc does not 145 | * necessarily fill in NULL pointers 146 | */ 147 | GROWALLOC(tbl2, tbl, newrows, struct ent **, nolonger); 148 | for (lnullit = tbl+maxrows, lcnt = 0; lcnt < newrows-maxrows; 149 | lcnt++, lnullit++) 150 | *lnullit = (struct ent **)NULL; 151 | /* memset(tbl+maxrows, (char *)NULL, (newrows-maxrows)*(sizeof(struct ent **)));*/ 152 | } 153 | #endif /* !PSC */ 154 | 155 | if ((rowcol == GROWCOL) || (rowcol == GROWBOTH) || (rowcol == GROWNEW)) { 156 | GROWALLOC(fwidth2, fwidth, newcols, int, nowider); 157 | GROWALLOC(precision2, precision, newcols, int, nowider); 158 | GROWALLOC(realfmt2, realfmt, newcols, int, nowider); 159 | #ifdef PSC 160 | memset(fwidth+maxcols, 0, (newcols-maxcols)*sizeof(int)); 161 | memset(precision+maxcols, 0, (newcols-maxcols)*sizeof(int)); 162 | memset(realfmt+maxcols, 0, (newcols-maxcols)*sizeof(int)); 163 | } 164 | #else 165 | GROWALLOC(col_hidden2, col_hidden, newcols, char, nowider); 166 | memset(col_hidden+maxcols, 0, (newcols-maxcols)*sizeof(char)); 167 | for (i = maxcols; i < newcols; i++) { 168 | fwidth[i] = DEFWIDTH; 169 | precision[i] = DEFPREC; 170 | realfmt[i] = DEFREFMT; 171 | } 172 | 173 | /* [re]alloc the space for each row */ 174 | for (i = 0; i < maxrows; i++) { 175 | if ((tbl[i] = scxrealloc(tbl[i], 176 | newcols * sizeof(struct ent **))) == (struct ent **)0) { 177 | error(nowider); 178 | return(FALSE); 179 | } 180 | for (nullit = ATBL(tbl, i, maxcols), cnt = 0; 181 | cnt < newcols-maxcols; cnt++, nullit++) 182 | *nullit = (struct ent *)NULL; 183 | /* memset((char *)ATBL(tbl,i, maxcols), 0, 184 | (newcols-maxcols)*sizeof(struct ent **)); 185 | */ 186 | } 187 | } 188 | else 189 | i = maxrows; 190 | 191 | /* fill in the bottom of the table */ 192 | for (; i < newrows; i++) { 193 | if ((tbl[i] = scxmalloc((newcols * 194 | sizeof(struct ent **)))) == NULL) { 195 | error(nowider); 196 | return(FALSE); 197 | } 198 | for (nullit = tbl[i], cnt = 0; cnt < newcols; cnt++, nullit++) 199 | *nullit = (struct ent *)NULL; 200 | /* memset((char *)tbl[i], 0, newcols*sizeof(struct ent **));*/ 201 | } 202 | 203 | FullUpdate++; 204 | maxrows = newrows; 205 | 206 | if (maxrows > 1000) rescol = 5; 207 | if (maxrows > 10000) rescol = 6; 208 | #endif /* PSC */ 209 | 210 | maxcols = newcols; 211 | return (TRUE); 212 | } 213 | -------------------------------------------------------------------------------- /xmalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A safer saner malloc, for careless programmers 3 | * $Revision: 7.16 $ 4 | */ 5 | 6 | #include 7 | #include 8 | #include "compat.h" 9 | #include "sc.h" 10 | 11 | static void fatal(char *); 12 | 13 | #define MAGIC (double)1234567890.12344 14 | 15 | void * 16 | scxmalloc(size_t n) 17 | { 18 | void *ptr; 19 | 20 | if ((ptr = malloc(n + sizeof(double))) == NULL) 21 | fatal("scxmalloc: no memory"); 22 | *((double *) ptr) = MAGIC; /* magic number */ 23 | return(ptr + sizeof(double)); 24 | } 25 | 26 | /* we make sure realloc will do a malloc if needed */ 27 | void * 28 | scxrealloc(void *ptr, size_t n) 29 | { 30 | if (ptr == NULL) 31 | return(scxmalloc(n)); 32 | 33 | ptr -= sizeof(double); 34 | if (*((double *) ptr) != MAGIC) 35 | fatal("scxrealloc: storage not scxmalloc'ed"); 36 | 37 | if ((ptr = realloc(ptr, n + sizeof(double))) == NULL) 38 | fatal("scxmalloc: no memory"); 39 | *((double *) ptr) = MAGIC; /* magic number */ 40 | return(ptr + sizeof(double)); 41 | } 42 | 43 | void 44 | scxfree(void *p) 45 | { 46 | if (p == NULL) 47 | fatal("scxfree: NULL"); 48 | p -= sizeof(double); 49 | if (*((double *) p) != MAGIC) 50 | fatal("scxfree: storage not malloc'ed"); 51 | free(p); 52 | } 53 | 54 | static void 55 | fatal(char *str) 56 | { 57 | #ifndef PSC 58 | deraw(1); 59 | #endif /* PSC */ 60 | fprintf(stderr, "%s\n", str); 61 | #ifndef PSC 62 | diesave(); 63 | #endif /* PSC */ 64 | exit(1); 65 | } 66 | -------------------------------------------------------------------------------- /xsc.doc: -------------------------------------------------------------------------------- 1 | .\" Carsten Kunze, 2016 2 | .Dd August 5, 2016 3 | .Dt XPNAME 1 4 | .Sh NAME 5 | .Nm xpname 6 | .Nd open pname with mouse support in a separate xterm 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Ar "pname options" 10 | .Sh DESCRIPTION 11 | There are use cases for 12 | .Nm pname 13 | where it is desirable to start it in a separate X window. 14 | .Nm 15 | just starts 16 | .Do Nm xterm Fl e Dc 17 | with 18 | .Nm pname 19 | and the 20 | .Ar "pname options" 21 | as argument and enables mouse support. 22 | File names with spaces need to be enclosed in single or double quotes 23 | .Po Sq Li \(aq 24 | or 25 | .Sq Li \(dq 26 | .Pc 27 | .Em and 28 | the spaces needs to be protected with a backslash 29 | .Pq Sq \(rs . 30 | -------------------------------------------------------------------------------- /xsc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | while [ $# -gt 0 ]; do 3 | case "$1" in 4 | -fg | -bg | -fn) 5 | XFl="$XFl $1 $2" 6 | shift ;; 7 | -*) 8 | Fl="$Fl $1" ;; 9 | *) 10 | break ;; 11 | esac 12 | shift 13 | done 14 | xterm $XFl -T "pname $*" -e "pname -M $Fl $*" & 15 | --------------------------------------------------------------------------------