diff -Nru sc-im-0.8.2+ds/CHANGES sc-im-0.8.3+ds/CHANGES --- sc-im-0.8.2+ds/CHANGES 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/CHANGES 2023-01-16 15:38:03.000000000 +0000 @@ -1,3 +1,113 @@ +CHANGES FILE + +*********** +v0.8.3 + +New stuff +--------- +**Added Multi Sheet support +added :newsheet, :nextsheet, :prevsheet :delsheet COMMAND_MODE commands +`gt` and `gT` commands in NORMAL_MODE are now used for moving between sheets +added new colors types SHEET, CURRENT_SHEET and FILENM +.sc file saving with multiple sheets +loading xlsx with multiple sheet +saving xlsx with multiple sheets +add :renamesheet COMMAND_MODE command +created movetosheet command in gram.y, to be used internally or in scripts when saving +and loading files. +reeval in multiple sheets: graph now should keep track of the different sheets + reference cells from different sheets in formulas: ={"Sheet2"}!A2 +Save triggers in files +** Added automated tests +C command in EDIT MODE + ++ Added ignore_hidden configuration variable to address + #674 #653 + With this hidden rows can be ignored when exporting spreasheets. + Useful when exporting the result of a filter. + This will also be honored when copy/pasting a range that have hidden rows in it. + +PR 725: added 'default_open_file_under_cursor_cmd' configuration value that can be set at runtime + +Changes +------- ++ added more detailed error in gram.y:yyerror ++ Adapt string and number search for multisheet ++ marks now considers sheet. We could have mark A in Sheet 1, and mark B on Sheet 2.. + modified tick() and fix_marks() +Renamed auto_justify to auto_fit +`gt` command of NORMAL_MODE renamed to `go` +Removed --sheet and --filename_with_mode configuration variables +UNDO now saves reference to the sheet where the action took place. ++ copy_to_undostruct() now keep in added/removed list struct ent_ptr * + (that knows of sheets), rather than struct ent *. +Copy alignment of strings when doing `Pf`. + undo: save maxrow, maxcol, modflg values before and after changes, so they can be restored after undo/redo actions +Modified yanklist to be struct ent_ptr list, rather thant struct ent list. +Ents_that_depends_on_list now takes ent_ptr rather than struct ent * as parameter +Backslash double quotes in cpaste. Issue 574. +Do not free ents of sheets when deleting a sheet manually (only at exit). just mark them as deleted. +Inform old value and new value when changing configuration variable +UI optimizations +Store offscr_sc values when saving sc files. Restore them when loading sc files +Simplify clipboard code +xlsx.c: Convert to uppercase before replacing functions +Added D command on EDIT mode. +ESC in EDIT_MODE also confirm changes. +Reeval when pasting from clipboard and autocalc is set +Adjust Makefile to have logic for clipboard commands on MacOS + +Fixes +----- +** fixed building warnings +** fix in calc_mobile_cols() +** fix not updating graph correctly after yanking cells with references -> Pc -> undo. + It could also segfault on ocassions as well. Added test5 and test6 for this. + +Issue #568: handle '>' and '<' on mappings. +Issue #569: fix invalid read/write/segfault when deleting column. + Added test8 and test9 for this. + +fix horizontal scroll when editing cells with long strings (wider than screen) +Avoid reading passed maxcols maxrows when shifting left or up over last sheet column/row. +fix in Pv when pasting over same place where data was yanked. +fix in paste_yanked_ents: calloc didnt count that yanked cells could share dependencies. +fix a bug when refreshing grid when autowrap operates. Issue 578. +Avoid segfault in autobackup when no current file is set. +fix in cw dw c$ d$ commands of EDIT_MODE +fix leak in del_selected_cells +fix when using C-r in INSERT_MODE +fix arguments reversed on sc.colrow2a +fix in delete_filters that caused SEGFAULT. Issue 637. +fix in unformat. call to copy_to_undostruct with wrong parameters. +fix swapped arguments on lsetform +added string functions to dep graph +Issue #697: do not allow to override nocurses config variable +fix #694: csv import and export / LaTex export +fix #700: '{' '}' normal mode commands reset cmd_multiplier + + + +Ideas for v0.8.4 +---------------- ++ Add is_deleted flag on sheets that are deleted. So ents have a chance to update its references to that sheet. +Then rebuild graph. ++ arv should have priority over scimrc. ++ rethink overlap. it shows incorrectly if text does not fit in the current LINE ++ user customizable UI header (bar) ++ modify search procedure. highlight matches ++ yank.c functions should receive yanklist pointer as parameter, rather than use yanklist global variable. +this could allow future use of registers to copy to and paste from. ++ registers for yanking ++ use yanklist for added/removed in undo? ++ restore transpose + +Please open a discussion on GitHub to comment on these and other feature requests. + + + + +*********** v0.8.2 Changes @@ -68,7 +178,6 @@ calc_offscr_rows/cols rewriten and renamed to calc_mobile_rows/cols - Fixes ----- Fix old sc bug - issue #371 @@ -87,15 +196,6 @@ Ignore SIGWINCH outside ncurses. triggers: Avoid segfault when not being able to load module. Issue #325 --- -Thanks to all that helped and created PR. -Thanks to all who support and use this program. - -Andrés Martinelli -andmarti1424 - - - *********** v0.8.1 @@ -149,7 +249,6 @@ v0.8.0 Released March 17th 2021 - New features ------------ +New motions in edit mode: df cf F dF cF d0 d$ c0 c$ t T dt dT ct cT ^ g_ d^ dg_ c^ cg_ diff -Nru sc-im-0.8.2+ds/debian/changelog sc-im-0.8.3+ds/debian/changelog --- sc-im-0.8.2+ds/debian/changelog 2022-01-07 21:17:02.000000000 +0000 +++ sc-im-0.8.3+ds/debian/changelog 2023-03-28 16:35:11.000000000 +0000 @@ -1,3 +1,20 @@ +sc-im (0.8.3+ds-1ubuntu1) lunar; urgency=medium + + * Ensure ncurses is linked + * Copyright: Fix upstream license, add missing clause + * Add libncursesw-dev as acceptable build dep + + -- Joshua Peisach Tue, 28 Mar 2023 12:35:11 -0400 + +sc-im (0.8.3+ds-1) unstable; urgency=medium + + * New upstream version 0.8.3+ds + + * Update Makefile patch + * Bump Standards-Version to 4.6.2 (no changes required) + + -- Joshua Peisach Mon, 16 Jan 2023 11:06:57 -0500 + sc-im (0.8.2+ds-1) unstable; urgency=medium * Initial release (Closes: #1002715) diff -Nru sc-im-0.8.2+ds/debian/control sc-im-0.8.3+ds/debian/control --- sc-im-0.8.2+ds/debian/control 2022-01-07 21:17:02.000000000 +0000 +++ sc-im-0.8.3+ds/debian/control 2023-03-28 16:35:11.000000000 +0000 @@ -1,18 +1,19 @@ Source: sc-im Section: math Priority: optional -Maintainer: Debian Math Team +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian Math Team Uploaders: Joshua Peisach Build-Depends: debhelper-compat (= 13), bison, gnuplot, liblua5.4-dev, - libncurses-dev, + libncurses-dev | libncursesw-dev, libtinfo-dev, libxml2-dev, libzip-dev -Standards-Version: 4.6.0 +Standards-Version: 4.6.2 Homepage: https://github.com/andmarti1424/sc-im Vcs-Browser: https://salsa.debian.org/math-team/sc-im Vcs-Git: https://salsa.debian.org/math-team/sc-im.git diff -Nru sc-im-0.8.2+ds/debian/copyright sc-im-0.8.3+ds/debian/copyright --- sc-im-0.8.2+ds/debian/copyright 2022-01-07 21:17:02.000000000 +0000 +++ sc-im-0.8.3+ds/debian/copyright 2023-03-28 16:35:11.000000000 +0000 @@ -10,28 +10,30 @@ All rights reserved. . Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by Andrés Martinelli + . + 4. Neither the name of the Andrés Martinelli nor the + names of other contributors may be used to endorse or promote products + derived from this software without specific prior written permission. . - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Files: debian/* Copyright: 2021 Joshua Peisach diff -Nru sc-im-0.8.2+ds/debian/patches/adjust-makefile-for-packaging.patch sc-im-0.8.3+ds/debian/patches/adjust-makefile-for-packaging.patch --- sc-im-0.8.2+ds/debian/patches/adjust-makefile-for-packaging.patch 2022-01-07 21:17:02.000000000 +0000 +++ sc-im-0.8.3+ds/debian/patches/adjust-makefile-for-packaging.patch 2023-01-16 16:06:57.000000000 +0000 @@ -1,17 +1,9 @@ Adjust Makefile for Debian Packaging -Changes two things: -* Changes our prefix to /usr from /usr/local and replaces 'which' with 'command -v' -* (Important): For some reason, on some systems/installations pkg-config can't properly -find the ncurses linker flags. This uncomments the part of BSD installations with -pkg-config, gets rid of the -I/usr/pkg (because we don't have /usr/pkg) and strictly -ensures -lncursesw is a flag. +Was GH Issue #650: https://github.com/andmarti1424/sc-im/issues/650 for having +pkg-config properly pick up gnuplot and some dependencies, but now those seem to be fixed. -* Update of later discovery: It seems there may be an issue with how make detects -pkg-config. For now, lua support is strictly 5.4. - -Consider: uncommenting the bison/yacc flag -GH issue: https://github.com/andmarti1424/sc-im/issues/650 +Now, just set the prefix to /usr. Index: sc-im/src/Makefile =================================================================== --- sc-im.orig/src/Makefile @@ -25,107 +17,3 @@ EXDIR = $(prefix)/bin HELPDIR = $(prefix)/share/$(name) -@@ -58,16 +58,16 @@ CFLAGS += -DMOUSE - # Choose one of the following commands for copying to different clipboards: - # You can later change it at runtime. - #to copy to tmux clipboard: --CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""tmux load-buffer"\" -+#CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""tmux load-buffer"\" - #to copy to X clipboard: --#CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""xclip -i -selection clipboard <"\" -+CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""xclip -i -selection clipboard <"\" - #to copy to OSX clipboard: - #CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""pbcopy <"\" - # - # Choose one of the proposed commands for pasting from different clipboards: - # You can later change it at runtime. --CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""tmux show-buffer"\" --#CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""xclip -o -selection clipboard"\" -+#CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""tmux show-buffer"\" -+CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""xclip -o -selection clipboard"\" - #CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""pbpaste"\" - - # Command to open file or link under cursor -@@ -83,7 +83,7 @@ ifneq ($(shell uname -s),Darwin) - endif - - # Check for gnuplot existance --ifneq (, $(shell which gnuplot)) -+ifneq (, $(shell command -v gnuplot)) - CFLAGS += -DGNUPLOT - endif - -@@ -97,7 +97,7 @@ ifneq ($(shell uname -s | grep -o BSD),B - LDLIBS += -ldl - endif - --ifneq (, $(shell which pkg-config)) -+ifneq (, $(shell command -v pkg-config)) - # Any system with pkg-config - - # NOTE: ncursesw (required) -@@ -121,52 +121,31 @@ ifneq (, $(shell which pkg-config)) - LDLIBS += $(shell pkg-config --libs libxls) - endif - -- # NOTE: libxml and libzip are required for xlsx file import support -- ifneq ($(shell pkg-config --exists libzip libxml-2.0 || echo 'no'),no) -- CFLAGS += -DODS -DXLSX $(shell pkg-config --cflags libxml-2.0 libzip) -- LDLIBS += $(shell pkg-config --libs libxml-2.0 libzip) -- endif -- - # NOTE: libxlsxwriter is required for xlsx file export support - ifneq ($(shell pkg-config --exists xlsxwriter || echo 'no'),no) - CFLAGS += -DXLSX_EXPORT $(shell pkg-config --cflags xlsxwriter) - LDLIBS += $(shell pkg-config --libs xlsxwriter) - endif - -- # NOTE: lua support -- ifneq ($(shell pkg-config --exists lua || echo 'no'),no) # Check for user's default lua -- CFLAGS += -DXLUA $(shell pkg-config --cflags lua) -- ifneq ($(shell uname -s),Darwin) -- LDLIBS += $(shell pkg-config --libs lua) -Wl,--export-dynamic -- else -- LDLIBS += $(shell pkg-config --libs lua) -rdynamic -- endif -- else ifneq ($(shell pkg-config --exists luajit || echo 'no'),no) # If not found, check for luajit -- CFLAGS += -DXLUA $(shell pkg-config --cflags luajit) -- ifneq ($(shell uname -s),Darwin) -- LDLIBS += $(shell pkg-config --libs luajit) -Wl,--export-dynamic -- else -- LDLIBS += $(shell pkg-config --libs luajit) -rdynamic -- endif -- endif - else ifeq ($(shell uname -s),Darwin) - # macOS without pkg-config - - # macOS' ncurses is built with wide-char support - LDFLAGS += -lncurses --else ifeq ($(shell uname -s),NetBSD) -- # NetBSD without pkg-config -- -- CFLAGS += -I/usr/pkg/include -- CFLAGS += -I/usr/pkg/include/ncursesw -+endif - -- LDFLAGS += -L/usr/pkg/lib -- LDFLAGS += -Wl,-R/usr/pkg/lib -+# NOTE: lua support -+CFLAGS += -DXLUA -I/usr/include/lua5.4 -+LDLIBS += -llua5.4 -rdynamic -+LDFLAGS += -llua5.4 -rdynamic -+ -+#NOTE: libxml and libzip are required for xlsx file import support -+CFLAGS += -DODS -DXLSX -I/usr/include/libxml2 -+LDLIBS += -lxml2 -lzip -+LDFLAGS += -lxml2 -lzip - -- LDLIBS += -lncursesw --else -- LDFLAGS += -lncursesw --endif -+LDLIBS += -lncursesw -+LDFLAGS += -lncursesw - - OBJS = $(patsubst %.c, %.o, $(wildcard *.c) $(wildcard utils/*.c)) gram.o - diff -Nru sc-im-0.8.2+ds/debian/patches/ensure-ncurses-linked.patch sc-im-0.8.3+ds/debian/patches/ensure-ncurses-linked.patch --- sc-im-0.8.2+ds/debian/patches/ensure-ncurses-linked.patch 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/debian/patches/ensure-ncurses-linked.patch 2023-03-28 16:35:11.000000000 +0000 @@ -0,0 +1,17 @@ +Description: Ensure ncurses is linked + It looks like once the Makefile checks for ncurses, and the platform + isn't any of the defaults, LDFLAGS isn't enough - LDLIBS needs to have + ncurses included for the linker to link properly. +Author: Joshua Peisach +Last-Update: 2023-03-28 + +--- sc-im-0.8.3+ds.orig/src/Makefile ++++ sc-im-0.8.3+ds/src/Makefile +@@ -165,6 +165,7 @@ else ifeq ($(shell uname -s),NetBSD) + + LDLIBS += -lncursesw + else ++ LDLIBS += -lncursesw + LDFLAGS += -lncursesw + endif + diff -Nru sc-im-0.8.2+ds/debian/patches/series sc-im-0.8.3+ds/debian/patches/series --- sc-im-0.8.2+ds/debian/patches/series 2022-01-07 21:17:02.000000000 +0000 +++ sc-im-0.8.3+ds/debian/patches/series 2023-03-28 16:35:11.000000000 +0000 @@ -1 +1,2 @@ adjust-makefile-for-packaging.patch +ensure-ncurses-linked.patch diff -Nru sc-im-0.8.2+ds/examples/sc/sheets/a.sc sc-im-0.8.3+ds/examples/sc/sheets/a.sc --- sc-im-0.8.2+ds/examples/sc/sheets/a.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/examples/sc/sheets/a.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,11 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (SC-IM) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "UNO" +let A0 = 1 +newsheet "DOS" +let B1 = 2 +newsheet "TRES" +let C2 = 4 +goto C2 diff -Nru sc-im-0.8.2+ds/examples/sc/sheets/b.sc sc-im-0.8.3+ds/examples/sc/sheets/b.sc --- sc-im-0.8.2+ds/examples/sc/sheets/b.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/examples/sc/sheets/b.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,7 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (SC-IM) +# You almost certainly shouldn't edit it. + +set external_functions +let C2 = 4 +let D2 = 15 +goto C2 diff -Nru sc-im-0.8.2+ds/examples/sc/sheets/c.sc sc-im-0.8.3+ds/examples/sc/sheets/c.sc --- sc-im-0.8.2+ds/examples/sc/sheets/c.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/examples/sc/sheets/c.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,8 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (SC-IM) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "Sheet 1" +let C2 = 4 +let D2 = 15 +goto C2 Binary files /tmp/tmpo767m6sf/DhFTpiqgkK/sc-im-0.8.2+ds/examples/xlsx/multisheet.xlsx and /tmp/tmpo767m6sf/wC4syVuZXZ/sc-im-0.8.3+ds/examples/xlsx/multisheet.xlsx differ Binary files /tmp/tmpo767m6sf/DhFTpiqgkK/sc-im-0.8.2+ds/examples/xlsx/t3.xlsx and /tmp/tmpo767m6sf/wC4syVuZXZ/sc-im-0.8.3+ds/examples/xlsx/t3.xlsx differ diff -Nru sc-im-0.8.2+ds/.gitignore sc-im-0.8.3+ds/.gitignore --- sc-im-0.8.2+ds/.gitignore 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/.gitignore 2023-01-16 15:38:03.000000000 +0000 @@ -4,6 +4,10 @@ src/gram.c src/sc-im src/tags +src/log +tests/tags +tests/log +tests/*_vallog src/scim src/statres.h doc/grammar_yacc_tools/commands.txt @@ -11,3 +15,7 @@ doc/grammar_yacc_tools/term_list.txt doc/grammar_yacc_tools/yacc-format-stage1 src/html +src/debug.sh +src/debuga.sh +src/a.sc +src/lua Binary files /tmp/tmpo767m6sf/DhFTpiqgkK/sc-im-0.8.2+ds/logo.png and /tmp/tmpo767m6sf/wC4syVuZXZ/sc-im-0.8.3+ds/logo.png differ diff -Nru sc-im-0.8.2+ds/Readme.md sc-im-0.8.3+ds/Readme.md --- sc-im-0.8.2+ds/Readme.md 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/Readme.md 2023-01-16 15:38:03.000000000 +0000 @@ -1,3 +1,7 @@ +

+ sc-im +

+ # sc-im Spreadsheet Calculator Improvised, aka sc-im, is an ncurses based, vim-like spreadsheet calculator. @@ -41,7 +45,7 @@ | k | Move up | | h | Move left | | l | Move right | -| gtab12 | go to cell AB12 | +| goab12 | go to cell AB12 | | u | undo last change | | C-r | redo last change undone | | yy | Copy current cell | @@ -113,7 +117,6 @@ ### Homebrew for OSX users ``` -brew tap nickolasburr/pfa brew install sc-im ``` @@ -121,6 +124,10 @@ See [this wiki page](https://github.com/andmarti1424/sc-im/wiki/Ubuntu-with-XLSX-import-&-export). +### Other distros / OS + +Please check [wiki pages](https://github.com/andmarti1424/sc-im/wiki/) + ### Configuration The `scimrc` file can be used to configure `sc-im`. The file should be placed in the `~/.config/sc-im` directory. @@ -135,6 +142,10 @@ Other configuration variables are listed in the [help file](https://raw.githubusercontent.com/andmarti1424/sc-im/freeze/src/doc). +### Tutorial + +[sc-im tutorial](https://github.com/jonnieey/Sc-im-Tutorial) + ### Helping us Want to help? You can help us with one or more of the following: @@ -147,7 +158,7 @@ ### Donations If you like sc-im please support its development by making a DONATION with PayPal. -It would really help a lot. 2 kids, 2 cats, 1 wife and only one salary.. +It would really help a lot. @@ -156,4 +167,4 @@ If you wish to make a donation, please click the above button or just send money to scim.spreadsheet@gmail.com via PayPal, choosing "Goods and Services". Paypal is preferred over Patreon. -Thanks! +Thank you! diff -Nru sc-im-0.8.2+ds/src/actions/filter.c sc-im-0.8.3+ds/src/actions/filter.c --- sc-im-0.8.2+ds/src/actions/filter.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/filter.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,270 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file filter.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include +#include // for isalpha toupper +#include +// #include + +#include "../macros.h" +#include "../tui.h" +#include "../conf.h" +#include "../xmalloc.h" +#include "filter.h" +#include "../utils/string.h" +#include "../sc.h" +#include "../cmds/cmds.h" + +static int howmany = 0; /**< how many filters were defined */ +static int active = 0; /**< indicates if those filters are applied or not */ +static int * results = NULL; /**< this keeps the results of the applied filters */ +static struct filter_item * filters = NULL; +extern struct session * session; + + +/** + * \brief Add a filter to filters structure + * \param[in] criteria + * \return none + */ +void add_filter(char * criteria) { + int cp = 0; + char c; + + while (criteria[cp]) { + int pos = exists_freed_filter(); // we check if there exists a freed filter + if (pos == -1) { // if not we alloc a new one + filters = (struct filter_item *) scxrealloc((char *) filters, (++howmany) * (sizeof(struct filter_item))); + pos = howmany-1; + } + + filters[pos].eval = (char *) scxmalloc(sizeof(char) * strlen(criteria) + 1); + filters[pos].eval[0] = '\0'; + + while (criteria[cp] && criteria[cp] != ';' && criteria[cp] != '\n') { + c = criteria[cp]; + if (c == '"') { cp++; continue; } + if (criteria[cp++] == '\'') c ='"'; + sprintf(filters[pos].eval + strlen(filters[pos].eval), "%c", c); + } + + if (criteria[cp] == ';') cp++; + } + return; +} + + +/** + * \brief Apply filters to a range + * \param[in] left + * \param[in] right + * \return none + */ +void enable_filters(struct ent * left, struct ent * right) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int minr = left->row < right->row ? left->row : right->row; + int maxr = left->row > right->row ? left->row : right->row; + int i, r, c = 0; + wchar_t cadena [BUFFERSIZE] = L""; + wchar_t aux [BUFFERSIZE] = L""; + results = (int *) scxrealloc((char *) results, (maxr - minr + 3) * sizeof(int)); + results[0] = minr; // keep in first position the first row of the range! + results[1] = maxr; // keep in second position the last row of the range! + if (filters == NULL) { + sc_error("There are no filters defined"); + return; + } + active = 1; + + for (r = minr; r <= maxr; r++) { + results[r-minr+2] = 0; // show row by default (0 = NOT HIDDEN) + for (i = 0; i < howmany; i++, c=0) { + cadena[0]=L'\0'; + if (filters[i].eval == NULL) continue; + while (filters[i].eval[c] != '\0') { + + if (filters[i].eval[c] == '#' || filters[i].eval[c] == '$') { + if (isalpha(toupper(filters[i].eval[++c]))) + swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%c", filters[i].eval[c]); + if (isalpha(toupper(filters[i].eval[++c]))) + swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%c", filters[i].eval[c]); + swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%d", r); + continue; + } else + swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%c", filters[i].eval[c]); + c++; + } + + swprintf(aux, BUFFERSIZE, L"eval %ls", cadena); + send_to_interp(aux); + if ( (! seval_result && str_in_str(filters[i].eval, "seval") != -1) || ! eval_result) { + results[r-minr+2] = 1; // this row does not eval to expression. we hide it. (1 = HIDDEN)! + i = howmany; + } + if (seval_result != NULL) free(seval_result); + } + } + + // Hide rows that don't match with filters + for (r = results[0]; r <= results[1]; r++) { + sh->row_hidden[r] = results[r-results[0]+2]; + } + sc_info("Filters enabled"); + return; +} + + +/** + * \brief Disable any applied filters + * \return none + */ +void disable_filters() { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + if (results == NULL) { + sc_error("There are no filters active"); + return; + } + // Hide rows that don't match with filters + int r; + for (r = results[0]; r <= results[1]; r++) { + sh->row_hidden[r] = 0; + } + active = 0; + sc_info("Filters disabled"); + return; +} + + +/** + * \brief Show details of each filter + * \return none + */ +void show_filters() { + if (filters == NULL) { + sc_error("There are no filters defined"); + return; + } + + int i, size = 0; + char init_msg[BUFFERSIZE]; + sprintf(init_msg, "Filters status: %s\nFilters:\n", active == 1 ? "ON" : "OFF"); + + size += sizeof(init_msg); + for (i=0; i < howmany; i++) + size += sizeof(filters[i].eval) + 4 + floor(log10(howmany)); + + char valores[ size + howmany ]; + valores[0]='\0'; + + strcpy(valores, init_msg); + for (i=0; i < howmany; i++) + if (filters[i].eval != NULL) sprintf(valores + strlen(valores), "%d + %s\n", i, filters[i].eval); + + ui_show_text(valores); + return; +} + + +/** + * \brief Free memory of entire filters structure + * \return int: -1 not removed - 0 removed + */ +/* + * FIXME: howmany in the forloop should be the max id, cause: + * you could for instance create 12 filters and remove the filters, 2 to 11. + * howmany would be two there, but filter12 would be allocated. + */ +int free_filters() { + if (filters == NULL) return -1; + int i; + disable_filters(); + for (i=0; i < howmany; i++) { + if (filters[i].eval != NULL) { + scxfree((char *) filters[i].eval); + filters[i].eval = NULL; + } + } + howmany = 0; + scxfree((char *) filters); + filters = NULL; + return 0; +} + + +/** + * \brief Remove a filter, freeing its memory + * \param[in] id + * \return int: -1 not removed - 0 removed + */ +int del_filter(int id) { + if (filters == NULL || id < 0) { + sc_error("Cannot delete the filter"); + return -1; + } + if (filters[id].eval != NULL) { + scxfree((char *) filters[id].eval); + filters[id].eval = NULL; + } + howmany--; + return 0; +} + + +/** + * \brief Check if a filter was deleted + * \details This function checks if a filter was deleted, so there would + * be room in filters structure for a new filter and preventing + * an unnecessary realloc. + * \return how many filters exist; -1 otherwise + */ +int exists_freed_filter() { + if (filters == NULL) return -1; + int i; + for (i=0; i < howmany; i++) + if (filters[i].eval == NULL) return i; + return -1; +} diff -Nru sc-im-0.8.2+ds/src/actions/filter.h sc-im-0.8.3+ds/src/actions/filter.h --- sc-im-0.8.2+ds/src/actions/filter.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/filter.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file filter.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for filter.c + */ + +struct filter_item { + char * eval; +}; + +void show_filters(); +void add_filter(char * criteria); +void enable_filters(struct ent * left, struct ent * right); +void disable_filters(); +int free_filters(); +int del_filter(int id); +int exists_freed_filter(); diff -Nru sc-im-0.8.2+ds/src/actions/freeze.c sc-im-0.8.3+ds/src/actions/freeze.c --- sc-im-0.8.2+ds/src/actions/freeze.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/freeze.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file freeze.c + * \author Andrés Martinelli + * \date 28/05/2021 + * \brief source code for handling the freeze of rows and columns. + */ + +#include + +#include "freeze.h" +#include "../macros.h" +#include "../tui.h" +#include "../undo.h" + +extern struct session * session; + +/** + * \brief handle_freeze. freeze/unfreeze a row/column + * \param[in] tl_ent: top ent that defines area + * \param[in] br_ent: bottom ent that defines area + * \param[in] value: 0 (unfreeze) or 1 (freeze) + * \param[in] type: 'r' or 'c' + * \return none + */ +void handle_freeze(struct sheet * sh, struct ent * tl_ent, struct ent * br_ent, char value, char type) { + int i; + +#ifdef UNDO + create_undo_action(); +#endif + if (type == 'r') + for (i=tl_ent->row; i<=br_ent->row; i++) { + sh->row_frozen[i]=value; +#ifdef UNDO + undo_freeze_unfreeze(i, -1, value == 1 ? 'f' : 'u', 1); +#endif + } + else if (type == 'c') + for (i=tl_ent->col; i<=br_ent->col; i++) { + sh->col_frozen[i]=value; +#ifdef UNDO + undo_freeze_unfreeze(-1, i, value == 1 ? 'f' : 'u', 1); +#endif + } +#ifdef UNDO + end_undo_action(); +#endif + return; +} diff -Nru sc-im-0.8.2+ds/src/actions/freeze.h sc-im-0.8.3+ds/src/actions/freeze.h --- sc-im-0.8.2+ds/src/actions/freeze.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/freeze.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file freeze.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for freeze.c + */ + +#include "../sc.h" + +void handle_freeze(struct sheet * sh, struct ent * tl_ent, struct ent * br_ent, char value, char type); diff -Nru sc-im-0.8.2+ds/src/actions/hide_show.c sc-im-0.8.3+ds/src/actions/hide_show.c --- sc-im-0.8.2+ds/src/actions/hide_show.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/hide_show.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file hide_show.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include + +#include "../sc.h" +#include "../macros.h" +#include "../tui.h" +#include "hide_show.h" +#include "../conf.h" +#include "../vmtbl.h" // for growtbl + +#ifdef UNDO +#include "../undo.h" +extern struct undo undo_item; +#endif + +extern struct session * session; + + +/** + * \brief Mark a row as hidden + * + * \param[in] from_row + * \param[in] arg + * + * \return none + */ +void hide_row(int from_row, int arg) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + register int r2; + + r2 = from_row + arg - 1; + if (from_row < 0 || from_row > r2) { + sc_error("Cannot hide row: Invalid range."); + return; + } + if (r2 >= sh->maxrows - 1) { + // error: tried to hide a row higher than maxrow. + lookat(sh, from_row + arg + 1, sh->curcol); //FIXME this HACK + if (! growtbl(sh, GROWROW, arg + 1, 0)) { + sc_error("You can't hide the last row"); + return; + } + } + + if (! roman->loading) { + roman->modflg++; + #ifdef UNDO + create_undo_action(); + undo_hide_show(from_row, -1, 'h', arg); + end_undo_action(); + #endif + } + while ( from_row <= r2) + sh->row_hidden[ from_row++ ] = TRUE; + return; +} + + +/** + * \brief Mark a column as hidden + * + * \param[in] from_col + * \param[in] arg + * + * \return none + */ +void hide_col(int from_col, int arg) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int c2 = from_col + arg - 1; + if (from_col < 0 || from_col > c2) { + sc_error ("Cannot hide col: Invalid range."); + return; + } + if (c2 >= sh->maxcols - 1) { + // sc_error: tried to hide a column higher than maxcol. + lookat(sh, sh->currow, from_col + arg + 1); //FIXME this HACK + if ((arg >= ABSMAXCOLS - 1) || ! growtbl(sh, GROWCOL, 0, arg + 1)) { + sc_error("You can't hide the last col"); + return; + } + } + + if (! roman->loading) { + roman->modflg++; + #ifdef UNDO + create_undo_action(); + create_undo_action(); + create_undo_action(); + undo_hide_show(-1, from_col, 'h', arg); + end_undo_action(); + #endif + } + while (from_col <= c2) + sh->col_hidden[ from_col++ ] = TRUE; + return; +} + + +/** + * \brief Mark a row as not-hidden + * + * \param[in] from_row + * \param[in] arg + * + * \return none + */ +void show_row(int from_row, int arg) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r2 = from_row + arg - 1; + if (from_row < 0 || from_row > r2) { + sc_error ("Cannot show row: Invalid range."); + return; + } + if (r2 > sh->maxrows - 1) { + r2 = sh->maxrows - 1; + } + + roman->modflg++; + #ifdef UNDO + create_undo_action(); + #endif + while (from_row <= r2) { + #ifdef UNDO + if (sh->row_hidden[from_row] ) undo_hide_show(from_row, -1, 's', 1); + #endif + sh->row_hidden[ from_row++ ] = FALSE; + } + #ifdef UNDO + end_undo_action(); + #endif + return; +} + + +/** + * \brief Mark a column as not-hidden + * + * \param[in] from_col + * \param[in] arg + * + * \return none + */ +void show_col(int from_col, int arg) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int c2 = from_col + arg - 1; + if (from_col < 0 || from_col > c2) { + sc_error ("Cannot show col: Invalid range."); + return; + } + if (c2 > sh->maxcols - 1) { + c2 = sh->maxcols - 1; + } + + roman->modflg++; + #ifdef UNDO + create_undo_action(); + #endif + while (from_col <= c2) { + #ifdef UNDO + if (sh->col_hidden[from_col] ) undo_hide_show(-1, from_col, 's', 1); + #endif + sh->col_hidden[ from_col++ ] = FALSE; + } + #ifdef UNDO + end_undo_action(); + #endif + return; +} + + +/** + * \brief TODO Document show_hiddenrows + * + * \return none + */ +void show_hiddenrows() { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r, c = 0; + for (r = 0; r < sh->maxrow; r++) { + if (sh->row_hidden[r]) c++; + } + char valores[12 * c + 20]; + valores[0]='\0'; + strcpy(valores, "Hidden rows:\n"); // 20 + for (r = 0; r < sh->maxrow; r++) { + if (sh->row_hidden[r]) sprintf(valores + strlen(valores), "- %d\n", r); // 12 + } + ui_show_text(valores); + + return; +} + + +/** + * \brief TODO Document show_hiddencols + * + * \return none + */ +void show_hiddencols() { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int c, count = 0; + for (c = 0; c < sh->maxcol; c++) { + if (sh->col_hidden[c]) count++; + } + char valores[8 * c + 20]; + valores[0]='\0'; + strcpy(valores, "Hidden cols:\n"); // 20 + for (c = 0; c < sh->maxcol; c++) { + if (sh->col_hidden[c]) sprintf(valores + strlen(valores), "- %s\n", coltoa(c)); // 8 + } + ui_show_text(valores); + + return; +} diff -Nru sc-im-0.8.2+ds/src/actions/hide_show.h sc-im-0.8.3+ds/src/actions/hide_show.h --- sc-im-0.8.2+ds/src/actions/hide_show.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/hide_show.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file hide_show.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file hide_show.c + */ + +void hide_row(int from_row, int arg); +void hide_col(int from_col, int arg); +void show_row(int from_row, int arg); +void show_col(int from_col, int arg); +void show_hiddenrows(); +void show_hiddencols(); diff -Nru sc-im-0.8.2+ds/src/actions/plot.c sc-im-0.8.3+ds/src/actions/plot.c --- sc-im-0.8.2+ds/src/actions/plot.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/plot.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file plot.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include +#include +#include +#include + +#include "plot.h" +#include "../file.h" +#include "../tui.h" + + +/** + * \brief plotedit() + * \details edit a plot instruction + * \param[in] s + * \return none + */ +int plotedit(wchar_t * s) { +#ifdef GNUPLOT + // edit ~/.scim/plotxxxx (or /usr/local/share/scim/plotxxxx) + char command[BUFFERSIZE]; + + if (! wcscmp(s, L"line") || ! wcscmp(s, L"scatter") || + ! wcscmp(s, L"pie") || ! wcscmp(s, L"bar")) { + char buffer[PATHLEN + 5]; + char path_out[PATHLEN]; + char type[BUFFERSIZE]; + wcstombs(type, s, BUFFERSIZE); + sprintf(buffer, "plot_%s", type); + if (! plugin_exists(buffer, strlen(buffer), path_out)) { + sc_error("could not load plot template file"); + return -1; + } + ui_pause(); + + char * editor; + if (! (editor = getenv("EDITOR"))) + editor = DFLT_EDITOR; + sprintf(command, "%.*s %.*s", 100, editor, 100, path_out); + + if (system(command) == -1) sc_error("Failed editting plot file - errno:%d", errno); + ui_resume(); + } else { + sc_error("error: invalid plot file: %ls", s); + return -1; + } + return 0; +#else + sc_error("Gnuplot was not installed when building Sc-im. Please rebuild Sc-im."); + return -1; +#endif +} + + +/** + * \brief plot() + * \param[in] s + * \param[in] r + * \param[in] c + * \param[in] rf + * \param[in] cf + * \return none + */ +int plot(char * s, int r, int c, int rf, int cf) { +#ifdef GNUPLOT + // create tmp file + char datafile[] = "/tmp/sc-im-plotdataXXXXXX"; + int fd = mkstemp(datafile); + if (fd == -1) { + sc_error("Error while creating temp file for plot"); + return -1; + } + + // export range to temp file in csv format + export_delim(datafile, ',', r, c, rf, cf, 0); + + // call gnuplot with ~/.scim/plotline (or /usr/local/share/scim/plotline) and temp data file + char command[BUFFERSIZE+PATHLEN]; + char buffer[PATHLEN]; + char plug_buffer[PATHLEN]; + sprintf(command, "gnuplot -e \"filename='%s'\"", datafile); + if (! strcmp(s, "line") || ! strcmp(s, "scatter") || + ! strcmp(s, "pie") || ! strcmp(s, "bar")) { + sprintf(buffer, "plot_%s", s); + if (! plugin_exists(buffer, strlen(buffer), plug_buffer)) { + sc_error("could not load default plotline file"); + return -1; + } + sprintf(command + strlen(command), " %s", plug_buffer); + + } else { + sc_error("plot option not valid"); + return -1; + } + + ui_pause(); + + if (system(command) == -1) + sc_error("Failed during plot - errno:%d", errno); + getchar(); + ui_resume(); + + // close file descriptor + close(fd); + + // remove temp file + unlink(datafile); + + return 0; +#else + sc_error("Gnuplot was not installed when building Sc-im. Please rebuild Sc-im."); + return -1; +#endif +} diff -Nru sc-im-0.8.2+ds/src/actions/plot.h sc-im-0.8.3+ds/src/actions/plot.h --- sc-im-0.8.2+ds/src/actions/plot.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/plot.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file plot.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for plot.c + */ + +int plot(char * s, int r, int c, int rf, int cf); +int plotedit(wchar_t * s); diff -Nru sc-im-0.8.2+ds/src/actions/shift.c sc-im-0.8.3+ds/src/actions/shift.c --- sc-im-0.8.2+ds/src/actions/shift.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/shift.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file shift.c + * \author Andrés Martinelli + * \date 25/05/2021 + */ + +#include +#include +#include "shift.h" +#include "../sc.h" +#include "../vmtbl.h" // for growtbl +#include "../cmds/cmds.h" +#include "../graph.h" +#include "../undo.h" +#include "../marks.h" +#include "../yank.h" +#include "../conf.h" +#include "../tui.h" + +extern graphADT graph; +extern int cmd_multiplier; +extern struct session * session; + +/** + * @brief Shift function - handles undo + * + * Shift functin - handles unto. Should also be called form gram.y. + * + * \param[in] r + * \param[in] c + * \param[in] rf + * \param[in] cf + * \param[in] type + * + * \return none + */ + +void shift(struct sheet * sh, int r, int c, int rf, int cf, wchar_t type) { + struct roman * roman = session->cur_doc; + if (cf - 1 + cmd_multiplier >= sh->maxcols && type == L'h') { + sc_error("current column + multiplier exceeds max column. Nothing changed"); + return; + } else if (rf - 1 + cmd_multiplier >= sh->maxrows && type == L'k') { + sc_error("current row + multiplier exceeds max row. Nothing changed"); + return; + } else if (any_locked_cells(sh, r, c, rf, cf) && (type == L'h' || type == L'k') ) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } +#ifdef UNDO + create_undo_action(); +#endif + int ic = cmd_multiplier + 1; + + switch (type) { + + case L'j': + fix_marks(sh, (rf - r + 1) * cmd_multiplier, 0, r, sh->maxrow, c, cf); +#ifdef UNDO + save_undo_range_shift(cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf); +#endif + while (ic--) shift_range(sh, ic, 0, r, c, rf, cf); + break; + + case L'k': + fix_marks(sh, -(rf - r + 1) * cmd_multiplier, 0, r, sh->maxrow, c, cf); + yank_area(sh, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, 'a', cmd_multiplier); // keep ents in yanklist for sk +#ifdef UNDO + ents_that_depends_on_range(sh, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf); + copy_to_undostruct(sh, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, UNDO_DEL, HANDLE_DEPS, NULL); + save_undo_range_shift(-cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf); +#endif + while (ic--) shift_range(sh, -ic, 0, r, c, rf, cf); + if (get_conf_int("autocalc") && ! roman->loading) EvalAll(); +#ifdef UNDO + copy_to_undostruct(sh, 0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); +#endif + break; + + case L'h': + fix_marks(sh, 0, -(cf - c + 1) * cmd_multiplier, r, rf, c, sh->maxcol); + yank_area(sh, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), 'a', cmd_multiplier); // keep ents in yanklist for sk +#ifdef UNDO + // here we save in undostruct, all the ents that depends on the deleted one (before change) + ents_that_depends_on_range(sh, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1)); + copy_to_undostruct(sh, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), UNDO_DEL, HANDLE_DEPS, NULL); + save_undo_range_shift(0, -cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1)); +#endif + while (ic--) shift_range(sh, 0, -ic, r, c, rf, cf); + + if (get_conf_int("autocalc") && ! roman->loading) EvalAll(); + //update(TRUE); // this is used just to make debugging easier +#ifdef UNDO + copy_to_undostruct(sh, 0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); +#endif + break; + + case L'l': + fix_marks(sh, 0, (cf - c + 1) * cmd_multiplier, r, rf, c, sh->maxcol); +#ifdef UNDO + save_undo_range_shift(0, cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1)); +#endif + while (ic--) shift_range(sh, 0, ic, r, c, rf, cf); + break; + } +#ifdef UNDO + end_undo_action(); + extern struct ent_ptr * deps; + if (deps != NULL) free(deps); + deps = NULL; +#endif + roman->modflg++; + /* just for testing + sync_refs(); + rebuild_graph(); + sync_refs(); + rebuild_graph(); */ + cmd_multiplier = 0; + return; +} + +/** + * \brief shift_range() + * \details Shift a range of cells + * \param[in] struct sheet * sh + * \param[in] delta_rows + * \param[in] delta_cols + * \param[in] tlrow + * \param[in] tlcol + * \param[in] brrow + * \param[in] brcol + * + * \return none + */ + +void shift_range(struct sheet * sh, int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol) { + sh->currow = tlrow; + sh->curcol = tlcol; + + if (delta_rows > 0) shift_cells_down (sh, brrow - tlrow + 1, brcol - tlcol + 1); + else if (delta_rows < 0) shift_cells_up (sh, brrow - tlrow + 1, brcol - tlcol + 1); + + if (delta_cols > 0) shift_cells_right(sh, brrow - tlrow + 1, brcol - tlcol + 1); + else if (delta_cols < 0) shift_cells_left (sh, brrow - tlrow + 1, brcol - tlcol + 1); + + return; +} + +/** + * \brief Shift cells down + * + * \param[in] deltarows + * \param[in] deltacols + * + * \return none + */ + +void shift_cells_down(struct sheet * sh, int deltarows, int deltacols) { + int r, c; + struct ent ** pp; + //if (sh->currow + deltarows > sh->maxrow) sh->maxrow = sh->currow + deltarows; + //commented for #569 + //if (sh->currow > sh->maxrow) sh->maxrow = sh->currow; + sh->maxrow += deltarows; + if ((sh->maxrow >= sh->maxrows) && !growtbl(sh, GROWROW, sh->maxrow, 0)) { + sh->maxrow = sh->maxrows - 1; + return; + } + + for (r = sh->maxrow; r > sh->currow + deltarows - 1; r--) { + for (c = sh->curcol; c < sh->curcol + deltacols; c++) { + pp = ATBL(sh, sh->tbl, r, c); + pp[0] = *ATBL(sh, sh->tbl, r-deltarows, c); + if ( pp[0] ) pp[0]->row += deltarows; + } + } + // blank new ents + for (c = sh->curcol; c < sh->curcol + deltacols; c++) + for (r = sh->currow; r < sh->currow + deltarows; r++) { + pp = ATBL(sh, sh->tbl, r, c); + *pp = (struct ent *) 0; + } + return; +} + +/** + * \brief Shift cells right + * + * \param[in] deltaros + * \param[in] deltacols + * + * \return none + */ + +void shift_cells_right(struct sheet * sh, int deltarows, int deltacols) { + int r, c; + struct ent ** pp; + + //commented for #569 + //if (sh->curcol + deltacols > sh->maxcol) sh->maxcol = sh->curcol + deltacols; + sh->maxcol += deltacols; + + if ((sh->maxcol >= sh->maxcols) && !growtbl(sh, GROWCOL, 0, sh->maxcol)) { + sh->maxcol = sh->maxcols - 1; + return; + } + + int lim = sh->maxcol - sh->curcol - deltacols; + for (r=sh->currow; r < sh->currow + deltarows; r++) { + pp = ATBL(sh, sh->tbl, r, sh->maxcol); + for (c = lim; c-- >= 0; pp--) + if ((pp[0] = pp[-deltacols])) pp[0]->col += deltacols; + + pp = ATBL(sh, sh->tbl, r, sh->curcol); + for (c = sh->curcol; c < sh->curcol + deltacols; c++, pp++) + *pp = (struct ent *) 0; + } + return; +} + +/** + * \brief Shift cells up + * + * \param[in] deltarows + * \param[in] deltacols + * + * \return none + */ + +void shift_cells_up(struct sheet * sh, int deltarows, int deltacols) { + int r, c; + struct ent ** pp; + + for (r = sh->currow; r <= sh->maxrow; r++) { + for (c = sh->curcol; c < sh->curcol + deltacols; c++) { + + if (r < sh->currow + deltarows) { + pp = ATBL(sh, sh->tbl, r, c); + + /* delete vertex in graph + unless vertex is referenced by other. Shall comment this? See NOTE1 above */ + vertexT * v = getVertex(graph, sh, *pp, 0); + if (v != NULL && v->back_edges == NULL ) destroy_vertex(sh, *pp); + + if (*pp) { + mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted + //clearent(*pp); + //free(*pp); + *pp = NULL; + } + } + if (r <= sh->maxrow - deltarows) { + pp = ATBL(sh, sh->tbl, r, c); + pp[0] = *ATBL(sh, sh->tbl, r + deltarows, c); + if ( pp[0] ) pp[0]->row -= deltarows; + } + //blank bottom ents + if (r > sh->maxrow - deltarows) { + pp = ATBL(sh, sh->tbl, r, c); + *pp = (struct ent *) 0; + } + } + } + return; +} + +/** + * \brief Shift cells left + * + * \param[in] deltarows + * \param[in] deltacols + * + * \return none + */ + +void shift_cells_left(struct sheet * sh, int deltarows, int deltacols) { + int r, c; + struct ent ** pp; + + for (c = sh->curcol; c <= sh->maxcol; c++) { + for (r = sh->currow; r < sh->currow + deltarows; r++) { + + if (c < sh->curcol + deltacols) { + pp = ATBL(sh, sh->tbl, r, c); + + /* delete vertex in graph + unless vertex is referenced by other */ + vertexT * v = getVertex(graph, sh, *pp, 0); + if (v != NULL && v->back_edges == NULL ) destroy_vertex(sh, *pp); + + if (*pp) { + mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted + //clearent(*pp); + //free(*pp); + *pp = NULL; + } + } + if (c <= sh->maxcol - deltacols) { + pp = ATBL(sh, sh->tbl, r, c); + pp[0] = *ATBL(sh, sh->tbl, r, c + deltacols); + if ( pp[0] ) pp[0]->col -= deltacols; + } + //blank bottom ents + if (c > sh->maxcol - deltacols) { + pp = ATBL(sh, sh->tbl, r, c); + *pp = (struct ent *) 0; + } + } + } + return; +} diff -Nru sc-im-0.8.2+ds/src/actions/shift.h sc-im-0.8.3+ds/src/actions/shift.h --- sc-im-0.8.2+ds/src/actions/shift.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/shift.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file shift.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for shift.c + */ + +#include "../sc.h" +void shift_cells(struct sheet * sh, int type, int arg, int delta); +void shift_cells_up(struct sheet * sh, int deltarows, int deltacols); +void shift_cells_down(struct sheet * sh, int deltarows, int deltacols); +void shift_cells_left(struct sheet * sh, int deltarows, int deltacols); +void shift_cells_right(struct sheet * sh, int deltarows, int deltacols); +void shift_range(struct sheet * sh, int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol); +void shift(struct sheet * sh, int r, int c, int rf, int cf, wchar_t type); diff -Nru sc-im-0.8.2+ds/src/actions/sort.c sc-im-0.8.3+ds/src/actions/sort.c --- sc-im-0.8.2+ds/src/actions/sort.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/sort.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file sort.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a brief file description. + */ + +/* Adaptation of Chuck Martin's code - */ + +#include +#include +#include +#include +#include +#include + +#include "../macros.h" +#include "../yank.h" +#include "../cmds/cmds.h" +#include "../conf.h" +#include "../color.h" +#include "../xmalloc.h" // for scxfree + +int compare(const void * row1, const void * row2); + +struct sortcrit { + int direction, type, column; +} * sort; + +int howmany; +extern struct session * session; + +/** + * \brief TODO Write a brief function description> + * + * \param[in] left + * \param[in] right + * \param[in] criteria + * + * \return none + */ + +void sortrange(struct sheet * sh, struct ent * left, struct ent * right, char * criteria) { + struct roman * roman = session->cur_doc; + int minr, minc, maxr, maxc, r, c; + int * rows, col = 0; + int cp = 0; + + minr = left->row < right->row ? left->row : right->row; + minc = left->col < right->col ? left->col : right->col; + maxr = left->row > right->row ? left->row : right->row; + maxc = left->col > right->col ? left->col : right->col; + + sort = (struct sortcrit *) scxmalloc((2 * sizeof(struct sortcrit))); + + // Save 'ent' elements in the range to the 'rows' structure + rows = (int *) scxmalloc((maxr - minr + 1) * sizeof(int)); + for (r = minr, c = 0; r <= maxr; r++, c++) + rows[c] = r; + + if (! criteria) { + sort[0].direction = 1; + sort[0].type = 1; + sort[0].column = minc; + sort[1].direction = 1; + sort[1].type = 0; + sort[1].column = minc; + howmany = 2; + } else { + howmany = 0; + while (criteria[cp]) { + if (howmany > 1) + sort = (struct sortcrit *) scxrealloc((char *) sort, (howmany + 1) * (sizeof(struct sortcrit))); + + switch (criteria[cp++]) { + case '+': + sort[howmany].direction = 1; + break; + case '-': + sort[howmany].direction = -1; + break; + default: + sc_error("Invalid sort criteria"); + return; + } + switch (criteria[cp++]) { + case '#': + sort[howmany].type = 0; + break; + case '$': + sort[howmany].type = 1; + break; + default: + sc_error("Invalid sort criteria"); + return; + } + if (criteria[cp]) { + col = toupper(criteria[cp++]) - 'A'; + } else { + sc_error("Invalid sort criteria"); + return; + } + if (criteria[cp] && criteria[cp] != '+' && criteria[cp] != '-' && criteria[cp] != ';') + col = (col + 1) * 26 + toupper(criteria[cp++]) - 'A'; + sort[howmany].column = col; + if (col < minc || col > maxc) { + sc_error("Invalid sort criteria"); + return; + } + cp++; + howmany++; + if (cp > strlen(criteria)) + break; + } + } + + // Sort 'rows' structure + qsort(rows, maxr - minr + 1, sizeof(int), compare); + + //currow = minr; + //curcol = minc; + + yank_area(sh, minr, minc, maxr, maxc, 's', 1); // save yanklist in the original range + + + // Fix the 'ent' elements in the sorted range + struct ent_ptr * p_aux, * yl = get_yanklist(); + + for (c = 0, p_aux = yl; p_aux; p_aux = p_aux->next) { + if (rows[c] != p_aux->vp->row) { + for (c = 0; c <= maxr - minr && rows[c] != p_aux->vp->row; c++) ; + if (c > maxr - minr) { + sc_error("sort error"); + return; + } + } + p_aux->vp->row = minr + c; + } + + sh->currow = minr; + sh->curcol = minc; + + paste_yanked_ents(sh, 0, 's'); // paste ents over currow and curcol + roman->modflg++; + + scxfree((char *) sort); + scxfree((char *) rows); + + if (criteria) scxfree(criteria); +} + +/** + * \brief TODO Write a brief function description> + * + * \param[in] row1 + * \param[in] row2 + * + * \return result + */ + +int compare(const void * row1, const void * row2) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + struct ent * p1; + struct ent * p2; + double diff; + int result = 0; + int i; + + for (i = 0; !result && i < howmany; i++) { + p1 = *ATBL(sh, sh->tbl, *((int *) row1), sort[i].column); + p2 = *ATBL(sh, sh->tbl, *((int *) row2), sort[i].column); + + if (sort[i].type) { + if (p1 && p1->label) { + if (p2 && p2->label) { + result = strcmp(p1->label, p2->label); + } else { + result = -1; + } + } else if (p2 && p2->label) { + result = 1; + } + } else if (p1 && p2 && p1->flags & is_valid && p2->flags & is_valid) { + diff = (p1->v - p2->v); + result = (diff > 0 ? 1 : diff < 0 ? -1 : 0); + } else if (p1 && p1->flags & is_valid) { + result = -1; + } else if (p2 && p2->flags & is_valid) { + result = 1; + } + result *= sort[i].direction; + } + + if (! result) result = (*((int *) row1) - *((int *) row2)); + + return (result); +} diff -Nru sc-im-0.8.2+ds/src/actions/sort.h sc-im-0.8.3+ds/src/actions/sort.h --- sc-im-0.8.2+ds/src/actions/sort.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/sort.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file sort.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for sort.c + */ + +void sortrange(struct sheet * sh, struct ent * left, struct ent * right, char * criteria); diff -Nru sc-im-0.8.2+ds/src/actions/subtotal.c sc-im-0.8.3+ds/src/actions/subtotal.c --- sc-im-0.8.2+ds/src/actions/subtotal.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/subtotal.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file subtotal.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include "../sc.h" +#include "../macros.h" +#include "../cmds/cmds.h" +#include "shift.h" +#include "../tui.h" + +/* +#include +#include +#include +#include +#include +#include + +#include "yank.h" +#include "conf.h" +#include "color.h" +#include "xmalloc.h" // for scxfree +*/ + +extern struct session * session; + +/** + * \brief TODO Document subtotal() + * + * \details Example command: subtotal A @sum C. If you want to replace a presxistant + * subtotals, you should use: rsubtotal A @sum C. + * + * \param[in] r used in defining the range of the data to be rearranged with subtotals + * \param[in] c used in defining the range of the data to be rearranged with subtotals + * \param[in] rf used in defining the range of the data to be rearranged with subtotals + * \param[in] cf used in defining the range of the data to be rearranged with subtotals + * \param[in] group_col + * \param[in] operation the operation to be done over the group can be one of the + * following: @sum, @prod, @avg, @count, @stddev, @max, @min + * \param[in] ope_col the operation column + * \param[in] replace_subtotal + * + * \return none + */ + +int subtotal(int r, int c, int rf, int cf, int group_col, char * operation, int ope_col, int replace_subtotals) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + // check ope_col and group_col are valid + if (ope_col < c || ope_col > cf || group_col < c || group_col > cf) return -1; + + // check if they are headers in first row + struct ent * p, * q; + int headers_in_first_row = 0; + if ((p = *ATBL(sh, sh->tbl, r, ope_col)) && p->label && + (q = *ATBL(sh, sh->tbl, r+1, ope_col)) && ! q->label) headers_in_first_row=1; + + // group operation shall be done over text content ! + wchar_t cline [BUFFERSIZE]; + p = *ATBL(sh, sh->tbl, r + headers_in_first_row, group_col); + swprintf(cline, BUFFERSIZE, L"+$%s", coltoa(group_col)); + + // sort the range + extern wchar_t interp_line[BUFFERSIZE]; + swprintf(interp_line, BUFFERSIZE, L"sort %s%d:", coltoa(c), r + headers_in_first_row); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d \"%ls\"", coltoa(cf), rf, cline); + send_to_interp(interp_line); + + // traverse the range and replace subtotals + // + // TODO replace subtotals only if replace_subtotals is set + int i, j, is_subtotal_row; + extern int cmd_multiplier; + //if (replace_subtotals) { + for (i=r+headers_in_first_row; i <= rf; i++) { + is_subtotal_row=0; + for (j=c; jtbl, i, j); + if (p && p->label && p->label[0] == '+' && p->label[1] == '@') { is_subtotal_row=1; break; } + } + if (is_subtotal_row) { + cmd_multiplier = 1; + shift(sh, i, c, i, cf, L'k'); + i--; + rf--; + } + } + //} + + // traverse the range and add subtotals + int new_rows = 0; + wchar_t cmd[BUFFERSIZE]; + int row_start_range = r + headers_in_first_row; + for (i=r+headers_in_first_row+1; i <= rf + new_rows + 1; i++) { + p = *ATBL(sh, sh->tbl, i-1, group_col); + q = *ATBL(sh, sh->tbl, i, group_col); + + // TODO ignore preexistance subtotals by default + + if ( (p && q && p->label && q->label && strcmp(q->label, p->label) != 0) + || i == rf + new_rows + 1) { + cmd_multiplier = 1; + shift(sh, i, c, i, cf, L'j'); + + swprintf(cmd, BUFFERSIZE, L"rightstring %s%d = \"+%s(%s)\"", coltoa(group_col), i, operation, p->label); + send_to_interp(cmd); + + swprintf(cmd, BUFFERSIZE, L"let %s%d = %s(%s%d:%s%d)", coltoa(ope_col), i, operation, + coltoa(ope_col), row_start_range, coltoa(ope_col), i-1); + send_to_interp(cmd); + valueize_area(sh, i, ope_col, i, ope_col); + + new_rows++; + i++; + row_start_range = i; + } + } + + return 0; +} diff -Nru sc-im-0.8.2+ds/src/actions/subtotal.h sc-im-0.8.3+ds/src/actions/subtotal.h --- sc-im-0.8.2+ds/src/actions/subtotal.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/subtotal.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file subtotal.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for subtotal.c + */ + +int subtotal(int r, int c, int rf, int cf, int group_col, char * operation, int ope_col, int replace_subtotals); diff -Nru sc-im-0.8.2+ds/src/actions/tags sc-im-0.8.3+ds/src/actions/tags --- sc-im-0.8.2+ds/src/actions/tags 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/actions/tags 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,48 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ +!_TAG_OUTPUT_FILESEP slash /slash or backslash/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/ +!_TAG_PROC_CWD /home/mongo/scim/src/actions/ // +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 5.9.0 /2b88b80ac/ +active filter.c /^static int active = 0; \/**< indicates if those filters are applied or not *\/$/;" v typeref:typename:int file: +add_filter filter.c /^void add_filter(char * criteria) {$/;" f typeref:typename:void +column sort.c /^ int direction, type, column;$/;" m struct:sortcrit typeref:typename:int file: +compare sort.c /^int compare(const void * row1, const void * row2) {$/;" f typeref:typename:int +del_filter filter.c /^int del_filter(int id) {$/;" f typeref:typename:int +direction sort.c /^ int direction, type, column;$/;" m struct:sortcrit typeref:typename:int file: +disable_filters filter.c /^void disable_filters() {$/;" f typeref:typename:void +enable_filters filter.c /^void enable_filters(struct ent * left, struct ent * right) {$/;" f typeref:typename:void +eval filter.h /^ char * eval;$/;" m struct:filter_item typeref:typename:char * +exists_freed_filter filter.c /^int exists_freed_filter() {$/;" f typeref:typename:int +filters filter.c /^static struct filter_item * filters = NULL;$/;" v typeref:struct:filter_item * file: +filter_item filter.h /^struct filter_item {$/;" s +free_filters filter.c /^int free_filters() {$/;" f typeref:typename:int +handle_freeze freeze.c /^void handle_freeze(struct sheet * sh, struct ent * tl_ent, struct ent * br_ent, char value, char/;" f typeref:typename:void +hide_col hide_show.c /^void hide_col(int from_col, int arg) {$/;" f typeref:typename:void +hide_row hide_show.c /^void hide_row(int from_row, int arg) {$/;" f typeref:typename:void +howmany filter.c /^static int howmany = 0; \/**< how many filters were defined *\/$/;" v typeref:typename:int file: +howmany sort.c /^int howmany;$/;" v typeref:typename:int +plot plot.c /^int plot(char * s, int r, int c, int rf, int cf) {$/;" f typeref:typename:int +plotedit plot.c /^int plotedit(wchar_t * s) {$/;" f typeref:typename:int +results filter.c /^static int * results = NULL; \/**< this keeps the results of the applied filters *\/$/;" v typeref:typename:int * file: +shift shift.c /^void shift(struct sheet * sh, int r, int c, int rf, int cf, wchar_t type) {$/;" f typeref:typename:void +shift_cells_down shift.c /^void shift_cells_down(struct sheet * sh, int deltarows, int deltacols) {$/;" f typeref:typename:void +shift_cells_left shift.c /^void shift_cells_left(struct sheet * sh, int deltarows, int deltacols) {$/;" f typeref:typename:void +shift_cells_right shift.c /^void shift_cells_right(struct sheet * sh, int deltarows, int deltacols) {$/;" f typeref:typename:void +shift_cells_up shift.c /^void shift_cells_up(struct sheet * sh, int deltarows, int deltacols) {$/;" f typeref:typename:void +shift_range shift.c /^void shift_range(struct sheet * sh, int delta_rows, int delta_cols, int tlrow, int tlcol, int br/;" f typeref:typename:void +show_col hide_show.c /^void show_col(int from_col, int arg) {$/;" f typeref:typename:void +show_filters filter.c /^void show_filters() {$/;" f typeref:typename:void +show_hiddencols hide_show.c /^void show_hiddencols() {$/;" f typeref:typename:void +show_hiddenrows hide_show.c /^void show_hiddenrows() {$/;" f typeref:typename:void +show_row hide_show.c /^void show_row(int from_row, int arg) {$/;" f typeref:typename:void +sort sort.c /^} * sort;$/;" v typeref:struct:sortcrit * +sortcrit sort.c /^struct sortcrit {$/;" s file: +sortrange sort.c /^void sortrange(struct sheet * sh, struct ent * left, struct ent * right, char * criteria) {$/;" f typeref:typename:void +subtotal subtotal.c /^int subtotal(int r, int c, int rf, int cf, int group_col, char * operation, int ope_col, int rep/;" f typeref:typename:int +type sort.c /^ int direction, type, column;$/;" m struct:sortcrit typeref:typename:int file: diff -Nru sc-im-0.8.2+ds/src/block.c sc-im-0.8.3+ds/src/block.c --- sc-im-0.8.2+ds/src/block.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/block.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -34,7 +34,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *******************************************************************************/ - /** * \file block.c * \author Andrés Martinelli @@ -46,6 +45,7 @@ #include #include "utils/string.h" + /** * \brief Function that tells if 'b' buffer is inside 'o' buffer * \details Find out if the int elements in the 'b' list are inside the @@ -99,8 +99,9 @@ return -1; } + /** - * \brief TODO Document replace_block_in_block() + * \brief replace_block_in_block() * * Replace the content of the block list "olist". Replace the nodes of the 'in' * list with the nodes of the 'out' list. @@ -112,7 +113,6 @@ * \return 0 on success * \return -1 on error */ - int replace_block_in_block (struct block * olist, struct block * in, struct block * out) { struct block * ori = olist; diff -Nru sc-im-0.8.2+ds/src/block.h sc-im-0.8.3+ds/src/block.h --- sc-im-0.8.2+ds/src/block.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/block.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -47,4 +47,3 @@ int block_in_block (struct block * o, struct block * b); int replace_block_in_block (struct block * olist, struct block * in, struct block * out); -void block_to_str(struct block * b, char * out); diff -Nru sc-im-0.8.2+ds/src/buffer.c sc-im-0.8.3+ds/src/buffer.c --- sc-im-0.8.2+ds/src/buffer.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/buffer.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -39,7 +39,7 @@ * \file buffer.c * \author Andrés Martinelli * \date 2017-07-18 - * \brief TODO Write a brief file description. + * \brief buffer functions used by stdin andm mappings */ #include @@ -49,12 +49,11 @@ #include "macros.h" #include "utils/string.h" + /** * \brief Create buffer as list of blocks -* * \return b */ - struct block * create_buf() { struct block * b = (struct block *) malloc(sizeof(struct block)); b->value = '\0'; @@ -62,15 +61,13 @@ return b; } + /** * \brief Add a wint_t to a buffer -* * \param[in] buf * \param[in] d -* * \return none */ - void addto_buf(struct block * buf, wint_t d) { struct block * aux = buf; @@ -88,15 +85,13 @@ return; } + /** * \brief Replace the elements of "origen" buffer to "destino" buffer -* * \param[in] origen * \param[in] destino -* * \return none */ - void copybuffer(struct block * origen, struct block * destino) { flush_buf(destino); int len = get_bufsize(origen); @@ -109,13 +104,10 @@ /** * \brief Replace the element of a buffer at 'pos' with a '\0' -* * \param[in] buf * \param[in] pos -* * \return none */ - // FIXME void del_buf (struct block * buf, int pos) { int i; @@ -138,12 +130,9 @@ /** * \brief TODO Document flush_buf() -* * \param[in] buf -* * \return none */ - void flush_buf (struct block * buf) { if (buf == NULL) return; @@ -154,34 +143,28 @@ } buf->value = '\0'; buf->pnext = NULL; - return; } + /** * \brief Delete all blocks of a buffer including the initial node -* * \details Delete all blocks of a buffer including the initial node -* * \param buf -* * \return none */ - void erase_buf (struct block * buf) { flush_buf(buf); free(buf); return; } + /** * \brief Get size of buffer (included special chars) -* * \param[in] buf -* * \return c size of buffer */ - int get_bufsize(struct block * buf) { struct block * b_aux = buf; if (b_aux == NULL || b_aux->value == '\0') return 0; @@ -193,17 +176,14 @@ return c; } + /** * \brief Get printable buffer length (excluded special chars) -* * \details Get printable bufferlength, which excludes special characters * as they should never be printed to a screen. -* * \param[in] buf -* * \return c printable buffer length */ - int get_pbuflen(struct block * buf) { struct block * b_aux = buf; if (b_aux == NULL || b_aux->value == '\0') return 0; @@ -215,15 +195,13 @@ return c; } + /** * \brief Return the int value of n block -* * \param[in] buf * \param[in] d -* * \return none */ - int get_bufval(struct block * buf, int d) { int i; struct block * b_aux = buf; @@ -233,14 +211,12 @@ return b_aux->value; } + /** * \brief Return an int value if found in a buffer -* * \details Search a buffer for a given integer value. -* * \return 0 if not found, 1 if found */ - int find_val(struct block * buf, int value) { struct block * b_aux = buf; while ( b_aux != NULL && b_aux->value != '\0' ) { @@ -250,14 +226,12 @@ return 0; } + /** * \brief Delete the first element in a buffer -* * \param[in] buf -* * \return none */ - struct block * dequeue (struct block * buf) { if (buf == NULL) return buf; struct block * sig; diff -Nru sc-im-0.8.2+ds/src/buffer.h sc-im-0.8.3+ds/src/buffer.h --- sc-im-0.8.2+ds/src/buffer.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/buffer.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/clipboard.c sc-im-0.8.3+ds/src/clipboard.c --- sc-im-0.8.2+ds/src/clipboard.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/clipboard.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -34,7 +34,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *******************************************************************************/ - /** * \file clipboard.c * \author Andrés Martinelli @@ -53,49 +52,22 @@ #include "macros.h" #include "tui.h" #include "clipboard.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "file.h" #include "conf.h" #include "utils/string.h" -int convert_string_to_number( int r0, int c0, int rn, int cn) { - int row, col; - register struct ent ** pp; - wchar_t out[FBUFLEN] = L""; - for (row = r0; row <= rn; row++) { - // ignore hidden rows - //if (row_hidden[row]) continue; - - for (pp = ATBL(tbl, row, col = c0); col <= cn; col++, pp++) { - // ignore hidden cols - //if (col_hidden[col]) continue; - - if (*pp) { - - // If a string exists - if ((*pp)->label) { - char * num = str_replace((*pp)->label," ",""); - (*pp)->label[0] = '\0'; - swprintf(out, BUFFERSIZE, L"let %s%d=%s", coltoa(col), row, num); - send_to_interp(out); - free(num); - } - } - } - } +extern struct session * session; - return 0; - -} /** -* \brief Pastes from clipboard -* +* \brief Paste to sc-im content stored on clipboard * \return 0 on success; -1 on error */ - int paste_from_clipboard() { - if (! strlen(get_conf_value("default_paste_from_clipboard_cmd"))) return -1; + struct roman * roman = session->cur_doc; + char *clipboard_cmd = get_conf_value("default_paste_from_clipboard_cmd"); + if (!clipboard_cmd || !*clipboard_cmd) return -1; // create tmp file char template[] = "/tmp/sc-im-clipboardXXXXXX"; @@ -109,23 +81,28 @@ //FILE * fpori = fdopen(fd, "w"); // copy content from clipboard to temp file - char syscmd[PATHLEN + strlen(get_conf_value("default_paste_from_clipboard_cmd")) + 1]; - sprintf(syscmd, "%s", get_conf_value("default_paste_from_clipboard_cmd")); - sprintf(syscmd + strlen(syscmd), " >> %s", template); + char syscmd[PATHLEN]; + int ret = snprintf(syscmd, PATHLEN, "%s >> %s", clipboard_cmd, template); + if (ret < 0 || ret >= PATHLEN) { + sc_error("Error while pasting from clipboard"); + ret = -1; + goto out; + } + ret = 0; system(syscmd); // traverse the temp file FILE * fp = fdopen(fd, "r"); char line_in[BUFFERSIZE]; wchar_t line_interp[FBUFLEN] = L""; - int c, r = currow; + int c, r = roman->cur_sh->currow; char * token; char delim[2] = { '\t', '\0' } ; while ( ! feof(fp) && (fgets(line_in, sizeof(line_in), fp) != NULL) ) { // Split string using the delimiter token = xstrtok(line_in, delim); - c = curcol; + c = roman->cur_sh->curcol; while( token != NULL ) { if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; clean_carrier(token); @@ -133,36 +110,46 @@ char * st = token; if (strlen(num) && isnumeric(num)) swprintf(line_interp, BUFFERSIZE, L"let %s%d=%s", coltoa(c), r, num); - else - swprintf(line_interp, BUFFERSIZE, L"label %s%d=\"%s\"", coltoa(c), r, st); + else { + if (strlen(st) > MAX_IB_LEN) { + sc_debug("Content from clipboard exceeds maximum width for a label. Cutting it to %d chars", MAX_IB_LEN); + st[MAX_IB_LEN-1]='\0'; + } + char * std = str_replace(st, "\"", "\\\""); // backspace double quotes + swprintf(line_interp, BUFFERSIZE, L"label %s%d=\"%s\"", coltoa(c), r, std); + free(std); + } if (strlen(st)) send_to_interp(line_interp); c++; token = xstrtok(NULL, delim); + free(num); //free(st); - if (c > maxcol) maxcol = c; + if (c > roman->cur_sh->maxcol) roman->cur_sh->maxcol = c; } r++; - if (r > maxrow) maxrow = r; + if (r > roman->cur_sh->maxrow) roman->cur_sh->maxrow = r; if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; } + if (get_conf_int("autocalc")) EvalAll(); sc_info("Content pasted from clipboard"); +out: // close file descriptor close(fd); // remove temp file unlink(template); - return 0; + return ret; } -/** -* @brief Copies to clipboard -* -* \return 0 on success; -1 on error -*/ +/** + * @brief Copies a range of cells to clipboard + * \return 0 on success; -1 on error + */ int copy_to_clipboard(int r0, int c0, int rn, int cn) { - if (! strlen(get_conf_value("default_copy_to_clipboard_cmd"))) return -1; + char *clipboard_cmd = get_conf_value("default_copy_to_clipboard_cmd"); + if (!clipboard_cmd || !*clipboard_cmd) return -1; // create tmp file char template[] = "/tmp/sc-im-clipboardXXXXXX"; @@ -180,12 +167,16 @@ fclose(fp); // copy to clipboard - char syscmd[PATHLEN + strlen(get_conf_value("default_copy_to_clipboard_cmd")) + 1]; - sprintf(syscmd, "%s", get_conf_value("default_copy_to_clipboard_cmd")); - sprintf(syscmd + strlen(syscmd), " %s", template); - system(syscmd); - - sc_info("Content copied to clipboard"); + char syscmd[PATHLEN]; + int ret = snprintf(syscmd, PATHLEN, "%s %s", clipboard_cmd, template); + if (ret < 0 || ret >= PATHLEN) { + sc_error("Error while copying to clipboard"); + ret = -1; + } else { + system(syscmd); + sc_info("Content copied to clipboard"); + ret = 0; + } // close file descriptor close(fd); @@ -193,26 +184,26 @@ // remove temp file unlink(template); - return 0; + return ret; } + /** -* @brief TODO Write a brief function description -* -* \details Note: The file must already be open. -* +* @brief save_plain() +* \details copy a range of cell to an open file stream +* Note: The file must already be open. * \param[in] fout output file * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn -* * \return 0 on success +* \return -1 on error */ - -// TODO Does this check if the file is already open? -// TODO What are the returns? Does 0 mean success? int save_plain(FILE * fout, int r0, int c0, int rn, int cn) { + if (fout == NULL) return -1; + struct roman * roman = session->cur_doc; + int conf_clipboard_delimited_tab = get_conf_int("copy_to_clipboard_delimited_tab"); int row, col; register struct ent ** pp; wchar_t out[FBUFLEN] = L""; @@ -227,7 +218,7 @@ // ignore hidden rows //if (row_hidden[row]) continue; - for (pp = ATBL(tbl, row, col = c0); col <= cn; col++, pp++) { + for (pp = ATBL(roman->cur_sh, roman->cur_sh->tbl, row, col = c0); col <= cn; col++, pp++) { // ignore hidden cols //if (col_hidden[col]) continue; emptyfield=-1; @@ -248,7 +239,7 @@ if (res == 0 || res == 1) { strcpy(num, formated_s); } else if (res == -1) { - sprintf(num, "%.*f", precision[col], (*pp)->v); + sprintf(num, "%.*f", roman->cur_sh->precision[col], (*pp)->v); } } else { @@ -273,16 +264,16 @@ if(emptyfield){ fwprintf(fout, L"\t"); } - if (! get_conf_int("copy_to_clipboard_delimited_tab")) { - pad_and_align(text, num, fwidth[col], align, 0, out, row_format[row]); + if (! conf_clipboard_delimited_tab) { + pad_and_align(text, num, roman->cur_sh->fwidth[col], align, 0, out, roman->cur_sh->row_format[row]); fwprintf(fout, L"%ls", out); } else if ( (*pp)->flags & is_valid) { fwprintf(fout, L"%s\t", num); } else if ( (*pp)->label) { fwprintf(fout, L"%s\t", text); } - } else if (! get_conf_int("copy_to_clipboard_delimited_tab")) { - fwprintf(fout, L"%*s", fwidth[col], " "); + } else if (! conf_clipboard_delimited_tab) { + fwprintf(fout, L"%*s", roman->cur_sh->fwidth[col], " "); } else { fwprintf(fout, L"\t"); } diff -Nru sc-im-0.8.2+ds/src/clipboard.h sc-im-0.8.3+ds/src/clipboard.h --- sc-im-0.8.2+ds/src/clipboard.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/clipboard.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -46,4 +46,3 @@ int copy_to_clipboard(int r0, int c0, int rn, int cn); int save_plain(FILE * fout, int r0, int c0, int rn, int cn); int paste_from_clipboard(); -int convert_string_to_number( int r0, int c0, int rn, int cn); diff -Nru sc-im-0.8.2+ds/src/cmds/cmds.c sc-im-0.8.3+ds/src/cmds/cmds.c --- sc-im-0.8.2+ds/src/cmds/cmds.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,3109 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds.c + * \author Andrés Martinelli + * \date 05/04/2021 + * \brief TODO Write brief file description + */ + +#include +#include // for isdigit +#include +#include +#include +#include "cmds.h" +#include "../main.h" +#include "../maps.h" +#include "../yank.h" +#include "../marks.h" +#include "../buffer.h" +#include "../tui.h" +#include "../conf.h" // for conf parameters +#include "../xmalloc.h" // for scxfree +#include "../vmtbl.h" // for growtbl +#include "../utils/string.h" // for add_char +#include "../y.tab.h" // for yyparse +#include "../graph.h" +#ifdef UNDO +#include "../undo.h" +#endif + +extern struct session * session; +extern int shall_quit; +extern graphADT graph; +extern int yyparse(void); + +char insert_edit_submode; +wchar_t interp_line[BUFFERSIZE]; +struct ent * freeents = NULL; // keep deleted ents around before sync_refs + + +/** + * \brief Maintain ent strucs until they are release for deletion by sync_refs. + * + * \details This structure is used to keep ent structs around before + * they are actually deleted (memory freed) to allow the sync_refs + * routine a chance to fix the variable references. If delete flag + * is set, is_deleted flag of an ent is set. + * + * \param[in] p + * \param[in] delete + * + * \return none + */ +void mark_ent_as_deleted(struct ent * p, int delete) { + if (p == NULL) return; + if (delete) p->flags |= is_deleted; + + p->next = freeents; /* put this ent on the front of freeents */ + freeents = p; + + return; +} + + +/** + * \brief TODO Write brief description + * + * \details Iterates throw freeents (ents marked as deleted). Calls + * clearent for freeing ents contents memory and free ent pointer. This + * function should always be called at exit. This is mandatory, just in + * case we want to UNDO any changes. + * TODO: any malloc of ents should check here before asking for memory + * + * \return none + */ +void flush_saved() { + struct ent * p; + struct ent * q; + + p = freeents; + while (p != NULL) { + (void) clearent(p); + q = p->next; + free(p); + p = q; + } + freeents = NULL; + return; +} + + +/** + * \brief sync_refs() + * \details Used to remove references to deleted struct ents. + * \details Note that the deleted structure must still be hanging + * around before the call, but not referenced by an entry in tbl. + * \return none + */ +// TODO Improve this function such that it does not traverse the whole table. Use the graph. +void sync_refs(struct sheet * sh) { + int i, j; + struct ent * p; + for (i=0; i <= sh->maxrow; i++) + for (j=0; j <= sh->maxcol; j++) + if ( (p = *ATBL(sh, sh->tbl, i, j)) && p->expr ) { + syncref(sh, p->expr); + } + return; +} + + +/** + * \brief TODO Write brief description + * + * Used to remove a reference to deleted a single struct ent. + * + * Note that the deleted structure must still be hanging around before the + * call, but not referenced by an entry in tbl. + * + * Example usage: + * @code + * syncref(); + * @endcode + * returns: none + */ +void syncref(struct sheet * sh, struct enode * e) { + if ( e == NULL ) { + return; + } else if ( e->op == ERR_ ) { + e->e.o.left = NULL; + e->e.o.right = NULL; + return; + } else if ( e->op == REF_ ) { + e->op = REF_; + e->e.o.left = NULL; + e->e.o.right = NULL; + return; + } else if (e->op & REDUCE) { + //e->e.r.right.vp = lookat(e->e.r.right.sheet, e->e.r.right.vp->row, e->e.r.right.vp->col); + e->e.r.right.vp = lookat(sh, e->e.r.right.vp->row, e->e.r.right.vp->col); + // e->e.r.left.vp = lookat(e->e.r.left.sheet, e->e.r.left.vp->row, e->e.r.left.vp->col); + e->e.r.left.vp = lookat(sh, e->e.r.left.vp->row, e->e.r.left.vp->col); + } else { + switch (e->op) { + case 'v': + if (e->e.v.vp->flags & is_deleted) { + //e->op = ERR_; + //e->e.o.left = NULL; + //e->e.o.right = NULL; + break; + } else if (e->e.v.vp->flags & may_sync) + e->e.v.vp = lookat(e->e.v.sheet == NULL ? sh : e->e.v.sheet, e->e.v.vp->row, e->e.v.vp->col); + break; + case 'k': + break; + case '$': + break; + default: + syncref(sh, e->e.o.right); + syncref(sh, e->e.o.left); + break; + } + } + return; +} + + +/** + * \brief deletecol() + * + * \param[in] struct sheet * sh + * \param[in] col + * \param[in] mult + * + * \return none + */ +void deletecol(struct sheet * sh, int col, int mult) { + + struct roman * roman = session->cur_doc; + + //if (col - 1 + mult >= sh->maxcols) { + if (col - 1 + mult > sh->maxcol) { + sc_error("current column + multiplier exceeds max column. Nothing changed"); + return; + } else if (any_locked_cells(sh, 0, col, sh->maxrow, col - 1 + mult)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } +#ifdef UNDO + create_undo_action(); + // here we save in undostruct, all the ents that depends on the deleted one (before change) + ents_that_depends_on_range(sh, 0, col, sh->maxrow, col - 1 + mult); + copy_to_undostruct(sh, 0, col, sh->maxrow, col - 1 + mult, UNDO_DEL, HANDLE_DEPS, NULL); + save_undo_range_shift(0, -mult, 0, col, sh->maxrow, col - 1 + mult); + + int i; + for (i=col; i < col + mult; i++) { + add_undo_col_format(i, 'R', sh->fwidth[i], sh->precision[i], sh->realfmt[i]); + if (sh->col_hidden[i]) undo_hide_show(-1, i, 's', 1); + else undo_hide_show(-1, i, 'h', 1); + // TODO undo col_frozen + } +#endif + + fix_marks(sh, 0, -mult, 0, sh->maxrow, col + mult -1, sh->maxcol); + if (! roman->loading) yank_area(sh, 0, col, sh->maxrow, col + mult - 1, 'c', mult); + + // do the job + int_deletecol(sh, col, mult); + + // if (get_conf_int("autocalc")) EvalAll(); + + if (! roman->loading) roman->modflg++; + +#ifdef UNDO + // here we save in undostruct, just the ents that depends on the deleted one (after change) + copy_to_undostruct(sh, 0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); + + extern struct ent_ptr * deps; + if (deps != NULL) free(deps); + deps = NULL; + + end_undo_action(); +#endif + return; +} + + +/** + * \brief int_deletecol() + * + * \details Delete a column. Parameters col = column to delete + * multi = cmds multiplier. (commonly 1) + * + * \param[in] struct sheet * sh + * \param[in] col + * \param[in] mult + * + * \return none + */ +void int_deletecol(struct sheet * sh, int col, int mult) { + struct ent ** pp; + int r, c, i; + + while (mult--) { + /* mark ent of column to erase with is_deleted flag + for (r = 0; r <= sh->maxrow; r++) { + pp = ATBL(sh, sh->tbl, r, col); + if ( *pp != NULL ) { + mark_ent_as_deleted(*pp, TRUE); + //clearent(*pp); + //free(*pp); + *pp = NULL; + } + }*/ + erase_area(sh, 0, col, sh->maxrow, col, 0, 1); //important: this mark the ents as deleted + + rebuild_graph(); // Rebuild of graph is needed. + //But shouldnt! TODO + + // Copy references from right column cells to left column (which gets removed) + for (r = 0; r <= sh->maxrow; r++) { + for (c = col; c < sh->maxcol; c++) { + pp = ATBL(sh, sh->tbl, r, c); + + // nota: pp[1] = ATBL(sh, sh->tbl, r, c+1); + pp[0] = pp[1]; + if ( pp[0] != NULL ) pp[0]->col--; + } + + // Free last column memory (Could also initialize 'ent' to zero with `cleanent`). + pp = ATBL(sh, sh->tbl, r, sh->maxcol); + *pp = (struct ent *) 0; + } + + // Fix columns precision and width + for (i = col; i < sh->maxcols - 1; i++) { + sh->fwidth[i] = sh->fwidth[i+1]; + sh->precision[i] = sh->precision[i+1]; + sh->realfmt[i] = sh->realfmt[i+1]; + sh->col_hidden[i] = sh->col_hidden[i+1]; + sh->col_frozen[i] = sh->col_frozen[i+1]; + } + + for (; i < sh->maxcols - 1; i++) { + sh->fwidth[i] = DEFWIDTH; + sh->precision[i] = DEFPREC; + sh->realfmt[i] = DEFREFMT; + sh->col_hidden[i] = FALSE; + sh->col_frozen[i] = FALSE; + } + + if (sh->maxcol) sh->maxcol--; + sync_refs(sh); + EvalAll(); + //flush_saved(); // we have to flush_saved only at exit. + //this is because we have to keep ents in case we want to UNDO + } + + return; +} + + +/** + * \brief TODO Write a brief description + * + * \details Copy cell (struct ent). "special" indicates special treatment + * when merging two cells for the "pm" command, merging formate only for + * the "pf" command, or for adjusting cell references when transposing + * with the "pt" command. r1, c1, r2, and c2 define the range in which the + * dr and dc values should be used. Special =='u' means special copy from + * spreadsheet to undo struct. Since its mandatory to make isolated copies + * of p->expr->e.o.right.e.v.vp and p->expr->e.o.right.e.v.vp + * + * \param[in] n + * \param[in] p + * \param[in] dr + * \param[in] dc + * \param[in] r1 + * \param[in] c1 + * \param[in] r2 + * \param[in] c2 + * \param[in] special + * \return none + * + * struct ent * n should be already alloc'ed + */ +void copyent(struct ent * n, struct sheet * sh_p, struct ent * p, int dr, int dc, int r1, int c1, int r2, int c2, int special) { + if (!p) { + sc_error("copyent: internal error"); + return; + } + n->flags = may_sync; + if (p->flags & is_deleted) + n->flags |= is_deleted; + + if (special != 'f') { + if (p->flags & is_valid) { + n->v = p->v; + n->flags |= p->flags & is_valid; + } + if (special != 'v' && p->expr && special != 'u') { + n->expr = copye(p->expr, sh_p, dr, dc, r1, c1, r2, c2, special == 't'); +#ifdef UNDO + } else if (special == 'u' && p->expr) { // from spreadsheet to undo + n->expr = copye(p->expr, sh_p, dr, dc, r1, c1, r2, c2, 2); +#endif + } + if (p->expr && p->flags & is_strexpr) + n->flags |= is_strexpr; + else if (p->expr) + n->flags &= ~is_strexpr; + + if (p->label) { + if (n->label) scxfree(n->label); + n->label = scxmalloc((unsigned) (strlen(p->label) + 1)); + (void) strcpy(n->label, p->label); + n->flags &= ~is_leftflush; + n->flags |= ((p->flags & is_label) | (p->flags & is_leftflush)); + } + n->flags |= p->flags & is_locked; + } + if (p->label && special == 'f' && n->label) { + n->flags &= ~is_leftflush; + n->flags |= ((p->flags & is_label) | (p->flags & is_leftflush)); + } + + if (p->format && special != 'v') { + if (n->format) scxfree(n->format); + n->format = scxmalloc((unsigned) (strlen(p->format) + 1)); + (void) strcpy(n->format, p->format); + } else if (special != 'v' && special != 'f') + n->format = NULL; + + if (special != 'v') { + n->pad = p->pad; + if (n->ucolor) { // remove current cellcolor format in n ent + free(n->ucolor); + n->ucolor = NULL; + } + if (p->ucolor) { // copy new cellcolor format from p to n ent + n->ucolor = (struct ucolor *) malloc (sizeof(struct ucolor)); + n->ucolor->fg = p->ucolor->fg; + n->ucolor->bg = p->ucolor->bg; + n->ucolor->bold = p->ucolor->bold; + n->ucolor->italic = p->ucolor->italic; + n->ucolor->dim = p->ucolor->dim; + n->ucolor->reverse = p->ucolor->reverse; + n->ucolor->standout = p->ucolor->standout; + n->ucolor->underline = p->ucolor->underline; + n->ucolor->blink = p->ucolor->blink; + } + } + + // used for undoing / redoing cells that has errors + n->cellerror = p->cellerror; + + if (special == 'c' && n->expr) { + // sc_debug("reeval in copyent"); + EvalJustOneVertex(sh_p, n, 0); + } + + n->flags |= is_changed; + n->row = p->row; + n->col = p->col; + return; +} + + +/** + * \brief etype(): return type of an enode + * \return NUM; STR; etc. + */ +int etype(struct enode *e) { + if (e == (struct enode *)0) + return NUM; + switch (e->op) { + case UPPER: case LOWER: case CAPITAL: + case O_SCONST: case '#': case DATE: case FMT: case STINDEX: + case EXT: case LUA: case SVAL: case SUBSTR: + return (STR); + + case '?': + case IF: + return (etype(e->e.o.right->e.o.left)); + + case 'f': + return (etype(e->e.o.right)); + + case O_VAR: { + struct ent *p; + p = e->e.v.vp; + if (p->expr) + return (p->flags & is_strexpr ? STR : NUM); + else if (p->label) + return (STR); + else + return (NUM); + } + + default: + return (NUM); + } + return -1; +} + + +/** + * \brief TODO Write a brief function description + * \details ignorelock is used when sorting so that locked cells + * can still be sorted + * \param[in] struct sheet * sh + * \param[in] sr + * \param[in] sc + * \param[in] er + * \param[in] ec + * \param[in] ignorelock + * \param[in] mark_as_deleted + * \return none + */ +void erase_area(struct sheet * sh, int sr, int sc, int er, int ec, int ignorelock, int mark_as_deleted) { + int r, c; + struct ent **pp; + + if (sr > er) { + r = sr; sr = er; er = r; + } + + if (sc > ec) { + c = sc; sc = ec; ec = c; + } + + if (sr < 0) + sr = 0; + if (sc < 0) + sc = 0; + checkbounds(sh, &er, &ec); + + /* mark the ent as deleted + * Do a lookat() for the upper left and lower right cells of the range + * being erased to make sure they are included in the delete buffer so + * that pulling cells always works correctly even if the cells at one + * or more edges of the range are all empty. + */ + (void) lookat(sh, sr, sc); + (void) lookat(sh, er, ec); + for (r = sr; r <= er; r++) { + for (c = sc; c <= ec; c++) { + pp = ATBL(sh, sh->tbl, r, c); + if (*pp && (!((*pp)->flags & is_locked) || ignorelock)) { + + /* delete vertex in graph + only if this vertex is not referenced by other */ + vertexT * v = getVertex(graph, sh, *pp, 0); + if (v != NULL && v->back_edges == NULL ) + destroy_vertex(sh, *pp); + + if (mark_as_deleted) { + mark_ent_as_deleted(*pp, TRUE); + } else { + clearent(*pp); // free memory + cleanent(*pp); // fill ent with empty values + mark_ent_as_deleted(*pp, FALSE); + } + *pp = NULL; + } + } + } + return; +} + + +/** + * \brief copye() + * \details Function used to get a copy of an expression. + * \param[in] e: expression to be copied + * \param[in] Rdelta + * \param[in] Cdelta + * \param[in] r1 + * \param[in] c1 + * \param[in] r2 + * \param[in] c2 + * \param[in] special + * special = 1 means transpose + * special = 2 means copy from spreadsheet to undo struct + * \return struct enode * + */ +struct enode * copye(struct enode *e, struct sheet * sh, int Rdelta, int Cdelta, int r1, int c1, int r2, int c2, int special) { + struct enode * ret; + static struct enode * range = NULL; + + if (e == NULL) { + ret = (struct enode *) 0; + + } else if (e->op & REDUCE) { + int newrow, newcol; + ret = (struct enode *) scxmalloc((unsigned) sizeof (struct enode)); + ret->op = e->op; + //ret->e.s = NULL; + //ret->e.o.s = NULL; + ret->e.r.left.expr = e->e.r.left.expr ? copye(e->e.r.left.expr, e->e.r.left.sheet, Rdelta, Cdelta, r1, c1, r2, c2, special) : NULL; // important to initialize + ret->e.r.right.expr = e->e.r.right.expr ? copye(e->e.r.right.expr, e->e.r.right.sheet, Rdelta, Cdelta, r1, c1, r2, c2, special) : NULL; // important to initialize + newrow = e->e.r.left.vf & FIX_ROW || e->e.r.left.vp->row < r1 || e->e.r.left.vp->row > r2 || e->e.r.left.vp->col < c1 || e->e.r.left.vp->col > c2 ? e->e.r.left.vp->row : special == 1 ? r1 + Rdelta + e->e.r.left.vp->col - c1 : e->e.r.left.vp->row + Rdelta; + newcol = e->e.r.left.vf & FIX_COL || e->e.r.left.vp->row < r1 || e->e.r.left.vp->row > r2 || e->e.r.left.vp->col < c1 || e->e.r.left.vp->col > c2 ? e->e.r.left.vp->col : special == 1 ? c1 + Cdelta + e->e.r.left.vp->row - r1 : e->e.r.left.vp->col + Cdelta; + ret->e.r.left.vp = lookat(sh, newrow, newcol); + ret->e.r.left.vf = e->e.r.left.vf; + ret->e.r.left.sheet = e->e.r.left.sheet; + newrow = e->e.r.right.vf & FIX_ROW || e->e.r.right.vp->row < r1 || e->e.r.right.vp->row > r2 || e->e.r.right.vp->col < c1 || e->e.r.right.vp->col > c2 ? e->e.r.right.vp->row : special == 1 ? r1 + Rdelta + e->e.r.right.vp->col - c1 : e->e.r.right.vp->row + Rdelta; + newcol = e->e.r.right.vf & FIX_COL || e->e.r.right.vp->row < r1 || e->e.r.right.vp->row > r2 || e->e.r.right.vp->col < c1 || e->e.r.right.vp->col > c2 ? e->e.r.right.vp->col : special == 1 ? c1 + Cdelta + e->e.r.right.vp->row - r1 : e->e.r.right.vp->col + Cdelta; + ret->e.r.right.vp = lookat(sh, newrow, newcol); + ret->e.r.right.vf = e->e.r.right.vf; + ret->e.r.right.sheet = e->e.r.right.sheet; + } else { + struct enode *temprange=0; + ret = (struct enode *) scxmalloc((unsigned) sizeof (struct enode)); + ret->op = e->op; + ret->e.s = NULL; + ret->e.o.s = NULL; + //ret->e.r.left.expr = copye(e->e.r.left.expr, e->e.r.left.sheet, Rdelta, Cdelta, r1, c1, r2, c2, special); + //ret->e.r.right.expr = copye(e->e.r.right.expr, e->e.r.right.sheet, Rdelta, Cdelta, r1, c1, r2, c2, special); + //ret->e.r.left.expr = NULL; + //ret->e.r.right.expr = NULL; + ret->e.r.left.vp = e->e.r.left.vp; + ret->e.r.right.vp = e->e.r.right.vp; + ret->e.r.left.sheet = e->e.r.left.sheet; + ret->e.r.right.sheet = e->e.r.right.sheet; + switch (ret->op) { + case SUM: + case PROD: + case AVG: + case COUNT: + case STDDEV: + case MAX: + case MIN: + temprange = range; + range = e->e.o.left; + r1 = 0; + c1 = 0; + r2 = sh->maxrow; + c2 = sh->maxcol; + } + switch (ret->op) { + case 'v': + { + int newrow, newcol; + if (range && e->e.v.vp->row >= range->e.r.left.vp->row && e->e.v.vp->row <= range->e.r.right.vp->row && e->e.v.vp->col >= range->e.r.left.vp->col && e->e.v.vp->col <= range->e.r.right.vp->col) { + newrow = range->e.r.left.vf & FIX_ROW ? e->e.v.vp->row : e->e.v.vp->row + Rdelta; + newcol = range->e.r.left.vf & FIX_COL ? e->e.v.vp->col : e->e.v.vp->col + Cdelta; + } else { + newrow = e->e.v.vf & FIX_ROW || e->e.v.vp->row < r1 || e->e.v.vp->row > r2 || e->e.v.vp->col < c1 || e->e.v.vp->col > c2 ? e->e.v.vp->row : special == 1 ? r1 + Rdelta + e->e.v.vp->col - c1 : e->e.v.vp->row + Rdelta; + newcol = e->e.v.vf & FIX_COL || e->e.v.vp->row < r1 || e->e.v.vp->row > r2 || e->e.v.vp->col < c1 || e->e.v.vp->col > c2 ? e->e.v.vp->col : special == 1 ? c1 + Cdelta + e->e.v.vp->row - r1 : e->e.v.vp->col + Cdelta; + } + ret->e.v.vp = lookat(e->e.v.sheet != NULL ? e->e.v.sheet : sh, newrow, newcol); + ret->e.v.vf = e->e.v.vf; + ret->e.v.sheet = e->e.v.sheet; + break; + } + case 'k': + ret->e.k = e->e.k; + break; + case 'f': + case 'F': + if ((range && ret->op == 'F') || (!range && ret->op == 'f')) + Rdelta = Cdelta = 0; + ret->e.o.left = copye(e->e.o.left, sh, Rdelta, Cdelta, r1, c1, r2, c2, special); + ret->e.o.right = (struct enode *)0; + break; + case '$': + case EXT: + ret->e.s = scxmalloc((unsigned) strlen(e->e.s)+1); + (void) strcpy(ret->e.s, e->e.s); + if (e->op == '$') /* Drop through if ret->op is EXT */ + break; + default: + if (e->op == ERR_) { + //ret->e.o.left = NULL; + //ret->e.o.right = NULL; + //ret->e.o.right = (struct enode *)0; + break; /* fix #108 */ + } + ret->e.o.left = copye(e->e.o.left, e->e.v.sheet != NULL ? e->e.v.sheet : sh, Rdelta, Cdelta, r1, c1, r2, c2, special); + ret->e.o.right = copye(e->e.o.right, e->e.v.sheet != NULL ? e->e.v.sheet : sh, Rdelta, Cdelta, r1, c1, r2, c2, special); + break; + } + switch (ret->op) { + case SUM: + case PROD: + case AVG: + case COUNT: + case STDDEV: + case MAX: + case MIN: + range = temprange; + } + } + return ret; +} + + +/** + * \brief dorowformat() + * \details: apply a row format in lines(size) to a row (r) + * \param[in] r + * \param[in] size + * \return none + */ +void dorowformat(struct sheet * sh, int r, unsigned char size) { + struct roman * roman = session->cur_doc; + if (size < 1 || size > UCHAR_MAX || (! get_conf_int("nocurses") && size > SC_DISPLAY_ROWS)) { sc_error("Invalid row format"); return; } + + if (r >= sh->maxrows && !growtbl(sh, GROWROW, 0, r)) r = sh->maxrows-1 ; + checkbounds(sh, &r, &(sh->curcol)); + sh->row_format[r] = size; + if (! roman->loading) roman->modflg++; + return; +} + + +/** + * \brief doformat() + * \details Note: Modified 9/17/90 THA to handle more formats. + * \param[in] struct sheet * sh + * \param[in] c1 + * \param[in] c2 + * \param[in] w + * \param[in] p + * \param[in] r + * \return none + */ +void doformat(struct sheet * sh, int c1, int c2, int w, int p, int r) { + struct roman * roman = session->cur_doc; + int i; + int crows = 0; + int ccols = c2; + + if (c1 >= sh->maxcols && !growtbl(sh, GROWCOL, 0, c1)) c1 = sh->maxcols-1 ; + if (c2 >= sh->maxcols && !growtbl(sh, GROWCOL, 0, c2)) c2 = sh->maxcols-1 ; + + if (w == 0) { + sc_info("Width too small - setting to 1"); + w = 1; + } + + if (! get_conf_int("nocurses") && w > SC_DISPLAY_COLS - 2) { + sc_info("Width too large - Maximum = %d", SC_DISPLAY_COLS - 2); + w = SC_DISPLAY_COLS - 2; + } + + if (p > w) { + sc_info("Precision too large"); + p = w; + } + + checkbounds(sh, &crows, &ccols); + if (ccols < c2) { + sc_error("Format statement failed to create implied column %d", c2); + return; + } + + for (i = c1; i <= c2; i++) + sh->fwidth[i] = w, sh->precision[i] = p, sh->realfmt[i] = r; + + roman->modflg++; + return; + +} + + +/** + * \brief formatcol() + * \param[in] struct sheet * sh + * \param[in] c + * \return none + */ +void formatcol(struct sheet * sh, int c) { + struct roman * roman = session->cur_doc; + int arg = 1; + int i; + + switch (c) { + case '<': + case 'h': + case OKEY_LEFT: + for (i = sh->curcol; i < sh->curcol + arg; i++) { + if (sh->fwidth[i] <= 2) { + sc_error("Cannot resize column any longer"); + return; + } + sh->fwidth[i]--; + if (sh->fwidth[i] <= 1) + sh->fwidth[i] = 1; + } + roman->modflg++; + break; + case '>': + case 'l': + case OKEY_RIGHT: + for (i = sh->curcol; i < sh->curcol + arg; i++) { + sh->fwidth[i]++; + if (sh->fwidth[i] > SC_DISPLAY_COLS - 2) + sh->fwidth[i] = SC_DISPLAY_COLS - 2; + } + roman->modflg++; + break; + case '-': + for (i = sh->curcol; i < sh->curcol + arg; i++) { + sh->precision[i]--; + if (sh->precision[i] < 0) + sh->precision[i] = 0; + } + roman->modflg++; + break; + case '+': + for (i = sh->curcol; i < sh->curcol + arg; i++) + sh->precision[i]++; + roman->modflg++; + break; + } + sc_info("Current format is %d %d %d", sh->fwidth[sh->curcol], sh->precision[sh->curcol], sh->realfmt[sh->curcol]); + ui_update(TRUE); + return; +} + + +/** + * \brief insert_row() + * \details Insert a single row. It will be inserted before currow + * if after is 0. After if it is 1. + * \param[in] struct sheet * sh + * \param[in] after + * \returnsnone + */ +void insert_row(struct sheet * sh, int after) { + int r, c; + struct ent ** tmprow, ** pp, ** qq; + struct ent * p; + int lim = sh->maxrow - sh->currow + 1; + + if (sh->currow > sh->maxrow) sh->maxrow = sh->currow; + sh->maxrow++; + lim = sh->maxrow - lim + after; + if (sh->maxrow >= sh->maxrows && ! growtbl(sh, GROWROW, sh->maxrow, 0)) { + sc_error("cannot grow sheet larger"); + return; + } + + tmprow = sh->tbl[sh->maxrow]; + for (r = sh->maxrow; r > lim; r--) { + sh->row_hidden[r] = sh->row_hidden[r-1]; + sh->row_frozen[r] = sh->row_frozen[r-1]; + sh->row_format[r] = sh->row_format[r-1]; + sh->tbl[r] = sh->tbl[r-1]; + for (c = 0, pp = ATBL(sh, sh->tbl, r, 0); c < sh->maxcols; c++, pp++) + if (*pp) (*pp)->row = r; + } + sh->tbl[r] = tmprow; // the last row is never used + sh->row_format[r] = 1; + + // if padding exists in the old currow, we copy it to the new row! + for (c = 0; c < sh->maxcols; c++) { + if (r >= 0 && (qq = ATBL(sh, sh->tbl, r+1, c)) && (*qq) && (*qq)->pad) { + p = lookat(sh, r, c); + p->pad = (*qq)->pad; + } + } + + // TODO pass roman as parameter + session->cur_doc->modflg++; + return; +} + + +/** + * \brief insert_col() + * \details Insert a single column. The column will be inserted + * BEFORE CURCOL if after is 0; + * AFTER CURCOL if it is 1. + * \param[in] struct sheet * sh + * \param[in] after + * \return none + */ +void insert_col(struct sheet * sh, int after) { + struct roman * roman = session->cur_doc; + int r, c; + struct ent ** pp, ** qq; + struct ent * p; + int lim = sh->maxcol - sh->curcol - after + 1; + + if (sh->curcol + after > sh->maxcol) + sh->maxcol = sh->curcol + after; + sh->maxcol++; + + if ((sh->maxcol >= sh->maxcols) && !growtbl(sh, GROWCOL, 0, sh->maxcol)) { + sc_error("cannot grow sheet wider"); + return; + } + + for (c = sh->maxcol; c >= sh->curcol + after + 1; c--) { + sh->fwidth[c] = sh->fwidth[c-1]; + sh->precision[c] = sh->precision[c-1]; + sh->realfmt[c] = sh->realfmt[c-1]; + sh->col_hidden[c] = sh->col_hidden[c-1]; + sh->col_frozen[c] = sh->col_frozen[c-1]; + } + for (c = sh->curcol + after; c - sh->curcol - after < 1; c++) { + sh->fwidth[c] = DEFWIDTH; + sh->precision[c] = DEFPREC; + sh->realfmt[c] = DEFREFMT; + sh->col_hidden[c] = FALSE; + sh->col_frozen[c] = FALSE; + } + + for (r=0; r <= sh->maxrow; r++) { + pp = ATBL(sh, sh->tbl, r, sh->maxcol); + for (c = lim; --c >= 0; pp--) + if ((pp[0] = pp[-1])) pp[0]->col++; + + pp = ATBL(sh, sh->tbl, r, sh->curcol + after); + for (c = sh->curcol + after; c - sh->curcol - after < 1; c++, pp++) + *pp = (struct ent *) 0; + } + + // if padding exists in the old curcol, we copy it to the new col! + for (r = 0; r < sh->maxrows; r++) { + if (c >= 0 && (qq = ATBL(sh, sh->tbl, r, c+1)) && (*qq) && (*qq)->pad) { + p = lookat(sh, r, c); + p->pad = (*qq)->pad; + } + } + + sh->curcol += after; + roman->modflg++; + return; +} + + +/** + * \brief deleterow() + * \details Delete a row + * \param[in] struct sheet * sh + * \param[in] row + * \param[in] mult + * \return none + */ +void deleterow(struct sheet * sh, int row, int mult) { + struct roman * roman = session->cur_doc; + //if (row + mult - 1 >= sh->maxrows) { + if (row + mult - 1 > sh->maxrow) { + sc_error("current row + multiplier exceeds max row. Nothing changed"); + return; + } else if (any_locked_cells(sh, row, 0, row + mult - 1, sh->maxcol)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } +#ifdef UNDO + create_undo_action(); + // here we save in undostruct, all the ents that depends on the deleted one (before change) + ents_that_depends_on_range(sh, row, 0, row + mult - 1, sh->maxcol); + copy_to_undostruct(sh, row, 0, row + mult - 1, sh->maxcol, UNDO_DEL, HANDLE_DEPS, NULL); + save_undo_range_shift(-mult, 0, row, 0, row - 1 + mult, sh->maxcol); + int i; + for (i=row; i < row + mult; i++) { + add_undo_row_format(i, 'R', sh->row_format[sh->currow]); + if (sh->row_hidden[i]) undo_hide_show(i, -1, 's', 1); + //else undo_hide_show(i, -1, 'h', 1); + } +#endif + + fix_marks(sh, -mult, 0, row + mult - 1, sh->maxrow, 0, sh->maxcol); + if (! roman->loading) yank_area(sh, row, 0, row + mult - 1, sh->maxcol, 'r', mult); + + // do the job + int_deleterow(sh, row, mult); + + //flush_saved(); // we have to flush only at exit. this is in case we want to UNDO + + if (! roman->loading) roman->modflg++; + +#ifdef UNDO + // here we save in undostruct, just the ents that depends on the deleted one (after the change) + copy_to_undostruct(sh, 0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); + + extern struct ent_ptr * deps; + if (deps != NULL) free(deps); + deps = NULL; + + end_undo_action(); +#endif + return; +} + + +/** + * \brief Delete a row + * \details Delete a row - internal function + * \param[in] struct sheet * sh + * \param[in] int row - row to delete + * \param[in] int multi - command multiplier (usually 1) + * \return none + */ +void int_deleterow(struct sheet * sh, int row, int mult) { + struct ent ** pp; + struct ent * q; + int r, c; + + //if (sh->currow > sh->maxrow) return; + + while (mult--) { + // we need to decrease row of the row that we delete if + // other cells refers to this one. + for (c = 0; c < sh->maxcols; c++) { + if (row <= sh->maxrow) { + pp = ATBL(sh, sh->tbl, row, c); + if ((q = *ATBL(sh, sh->tbl, row, c)) != NULL && q->row > 0) q->row--; + } + } + sync_refs(sh); + + // and after that the erase_area of the deleted row + erase_area(sh, row, 0, row, sh->maxcol, 0, 1); //important: this mark the ents as deleted + + // and we decrease ->row of all rows after the deleted one + for (r = row; r < sh->maxrows - 1; r++) { + for (c = 0; c < sh->maxcols; c++) { + if (r <= sh->maxrow) { + pp = ATBL(sh, sh->tbl, r, c); + pp[0] = *ATBL(sh, sh->tbl, r+1, c); + if ( pp[0] ) pp[0]->row--; + } + } + //update row_hidden and row_format here + sh->row_hidden[r] = sh->row_hidden[r+1]; + sh->row_frozen[r] = sh->row_frozen[r+1]; + sh->row_format[r] = sh->row_format[r+1]; + } + + rebuild_graph(); //TODO CHECK HERE WHY REBUILD IS NEEDED. See NOTE1 in shift.c + sync_refs(sh); + EvalAll(); + if (sh->maxrow) sh->maxrow--; + } + return; +} + + +/** + * \brief ljustify() + * \param[in] struct sheet * sh + * \param[in] sr + * \param[in] sc + * \param[in] er + * \param[in] ec + * \return none + */ +void ljustify(struct sheet * sh, int sr, int sc, int er, int ec) { + struct roman * roman = session->cur_doc; + struct ent *p; + int i, j; + + if (sr > er) { + i = sr; + sr = er; + er = i; + } + if (sc > ec) { + i = sc; + sc = ec; + ec = i; + } + for (i = sr; i <= er; i++) { + for (j = sc; j <= ec; j++) { + p = *ATBL(sh, sh->tbl, i, j); + if (p && p->label) { + p->flags &= ~is_label; + p->flags |= is_leftflush | is_changed; + roman->modflg++; + } + } + } + return; +} + + +/** + * \brief rjustify() + * \param[in] struct sheet * sh + * \param[in] sr + * \param[in] sc + * \param[in] er + * \param[in] ec + * \return none + */ +void rjustify(struct sheet * sh, int sr, int sc, int er, int ec) { + struct roman * roman = session->cur_doc; + struct ent *p; + int i, j; + + if (sr > er) { + i = sr; + sr = er; + er = i; + } + if (sc > ec) { + i = sc; + sc = ec; + ec = i; + } + for (i = sr; i <= er; i++) { + for (j = sc; j <= ec; j++) { + p = *ATBL(sh, sh->tbl, i, j); + if (p && p->label) { + p->flags &= ~(is_label | is_leftflush); + p->flags |= is_changed; + roman->modflg++; + } + } + } + return; +} + + +/** + * \brief center() + * \param[in] struct sheet * sh + * \param[in] sr + * \param[in] sc + * \param[in] er + * \param[in] ec + * \return none + */ +void center(struct sheet * sh, int sr, int sc, int er, int ec) { + struct roman * roman = session->cur_doc; + struct ent *p; + int i, j; + + if (sr > er) { + i = sr; + sr = er; + er = i; + } + if (sc > ec) { + i = sc; + sc = ec; + ec = i; + } + for (i = sr; i <= er; i++) { + for (j = sc; j <= ec; j++) { + p = *ATBL(sh, sh->tbl, i, j); + if (p && p->label) { + p->flags &= ~is_leftflush; + p->flags |= is_label | is_changed; + roman->modflg++; + } + } + } + return; +} + + +/** + * @brief chg_mode() + * \param[in] strcmd + * \return none + */ +void chg_mode(char strcmd){ + lastmode = curmode; + switch (strcmd) { + case '=': + curmode = INSERT_MODE; + break; + case '<': + curmode = INSERT_MODE; + break; + case '>': + curmode = INSERT_MODE; + break; + case '\\': + curmode = INSERT_MODE; + break; + case 'E': + curmode = EDIT_MODE; + break; + case 'e': + curmode = EDIT_MODE; + break; + case ':': + curmode = COMMAND_MODE; + break; + case '.': + curmode = NORMAL_MODE; + break; + case 'v': + curmode = VISUAL_MODE; + break; + } + return; +} + + +/** + * \brief del_selected_cells() + * \details Delete selected cell or range of cells. + * \param[in] struct sheet * sh + * \return none + */ +void del_selected_cells(struct sheet * sh) { + struct roman * roman = session->cur_doc; + int tlrow = sh->currow; + int tlcol = sh->curcol; + int brrow = sh->currow; + int brcol = sh->curcol; + extern struct ent_ptr * deps; + + // is we delete a range + if (is_range_selected() != -1) { + srange * r = get_selected_range(); + tlrow = r->tlrow; + tlcol = r->tlcol; + brrow = r->brrow; + brcol = r->brcol; + } + + if (any_locked_cells(sh, tlrow, tlcol, brrow, brcol)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } + + if (is_range_selected() != -1) + yank_area(sh, tlrow, tlcol, brrow, brcol, 'a', 1); + else + yank_area(sh, tlrow, tlcol, brrow, brcol, 'e', 1); + +#ifdef UNDO + create_undo_action(); + // here we save in undostruct, all the ents that depends on the deleted one (before change) + ents_that_depends_on_range(sh, tlrow, tlcol, brrow, brcol); + copy_to_undostruct(sh, tlrow, tlcol, brrow, brcol, UNDO_DEL, HANDLE_DEPS, NULL); + if (deps != NULL) { free(deps); deps = NULL; } +#endif + + erase_area(sh, tlrow, tlcol, brrow, brcol, 0, 0); //important: this erases the ents, but does NOT mark them as deleted + roman->modflg++; + sync_refs(sh); + //flush_saved(); DO NOT UNCOMMENT! flush_saved shall not be called other than at exit. + + /* TODO + * EvalRange() cleans deps so it can eval. + * we should keep it so me can copy to undostruct later on + * Here, we might want to make that free of deps inside EvalRange optional as a parameter + */ + //EvalRange(sh, tlrow, tlcol, brrow, brcol); + EvalAll(); + +#ifdef UNDO + // here we save in undostruct, all the ents that depends on the deleted one (after the change) + ents_that_depends_on_range(sh, tlrow, tlcol, brrow, brcol); + copy_to_undostruct(sh, tlrow, tlcol, brrow, brcol, UNDO_ADD, HANDLE_DEPS, NULL); + if (deps != NULL) { free(deps); deps = NULL; } + end_undo_action(); +#endif + + return; +} + + +/** + * \brief enter_cell_content() + * \details Enter cell content on a cell. + * Covers commands LET, LABEL, LEFTSTRING, and RIGHTSTRING + * \param[in] struct sheet * sh + * \param[in] r + * \param[in] c + * \param[in] submode + * \param[in] content + * \return none + */ +void enter_cell_content(struct sheet * sh, int r, int c, char * submode, wchar_t * content) { + (void) swprintf(interp_line, BUFFERSIZE, L"%s %s = %ls", submode, v_name(r, c), content); + send_to_interp(interp_line); + if (get_conf_int("autocalc") && ! session->cur_doc->loading) EvalRange(sh, r, c, r, c); +} + + +/** + * @brief Send command to interpreter + * \details Send command to interpreter + * wide_char version + * \param[in] oper + * \return none + */ +void send_to_interp(wchar_t * oper) { + if (get_conf_int("nocurses")) { + int pos = -1; + if ((pos = wstr_in_wstr(oper, L"\n")) != -1) + oper[pos] = L'\0'; + sc_debug("Interp GOT: %ls", oper); + } + wcstombs(line, oper, BUFFERSIZE); + + linelim = 0; + yyparse(); + linelim = -1; + line[0]='\0'; + // commented on 28/04/2021. EvalAll should be used only on certain ocasions. + // Use EvalRange instead when possible, and certainly not here everytime sending to interp. + //if (get_conf_int("autocalc") && ! roman->loading) EvalAll(); + return; +} + + +/** + * \brief lookat() + * \details Return a pointer to a cell's [struct ent *], creating if needed + * \param[in] struct sheet * sh + * \param[in] row + * \param[in] col + * \return none + */ +struct ent * lookat(struct sheet * sh, int row, int col) { + struct ent **pp; + + checkbounds(sh, &row, &col); + pp = ATBL(sh, sh->tbl, row, col); + if ( *pp == NULL) { + *pp = (struct ent *) malloc( (unsigned) sizeof(struct ent) ); + (*pp)->label = (char *) 0; + (*pp)->flags = may_sync; + (*pp)->expr = (struct enode *) 0; + (*pp)->trigger = (struct trigger *) 0; + (*pp)->v = (double) 0.0; + (*pp)->format = (char *) 0; + (*pp)->cellerror = CELLOK; + (*pp)->next = NULL; + (*pp)->ucolor = NULL; + (*pp)->pad = 0; + } + (*pp)->row = row; + (*pp)->col = col; + if (row > sh->maxrow) sh->maxrow = row; + if (col > sh->maxcol) sh->maxcol = col; + return (*pp); +} + + +/** + * \brief cleanent() + * \details Blank an ent + * \param[in] p + * \return none + */ +void cleanent(struct ent * p) { + if (!p) return; + p->label = (char *) 0; + // do not uncomment. if so mod erase_area. + //p->row = 0; + //p->col = 0; + + p->flags = may_sync; + p->expr = (struct enode *) 0; + p->v = (double) 0.0; + p->format = (char *) 0; + p->cellerror = CELLOK; + p->next = NULL; + p->ucolor = NULL; + p->pad = 0; + return; +} + + +/** + * \brief clearent() + * \details Free memory of an ent and its contents + * \param[in] v + * \return none + */ +void clearent(struct ent * v) { + struct roman * roman = session->cur_doc; + if (!v) return; + + label(v, "", -1); + v->v = (double)0; + + if (v->expr) efree(v->expr); + v->expr = NULL; + + if (v->format) scxfree(v->format); + v->format = NULL; + + if (v->ucolor) free(v->ucolor); + v->ucolor = NULL; + + v->flags = is_changed; + + roman->modflg++; + return; +} + + +/** + * \brief back_col() + * \details Moves curcol back one displayed column + * \param[in] struct sheet * sh + * \param[in] arg + * \return lookat + */ +struct ent * back_col(struct sheet * sh, int arg) { + int c = sh->curcol; + + while (--arg >= 0) { + if (c) { + sh->curcol = --c; + } else { + sc_info ("At column A"); + break; + } + while (sh->col_hidden[c] && c) { + sh->curcol = --c; + } + } + if (sh->curcol < sh->offscr_sc_cols) + sh->offscr_sc_cols = sh->curcol; + + return lookat(sh, sh->currow, c); +} + + +/** + * \brief forw_col() + * \details Moves curcol forward one displayed column + * \param[in] struct sheet * sh + * \param[in] arg + * \return lookat + */ +struct ent * forw_col(struct sheet * sh, int arg) { + int c = sh->curcol; + + while (--arg >= 0) { + if (c < sh->maxcols - 1) { + c++; + } else { + if (! growtbl(sh, GROWCOL, 0, arg)) { /* get as much as needed */ + sc_error("cannot grow sheet wider"); + return lookat(sh, sh->currow, sh->curcol); + } else { + c++; + } + } + while (sh->col_hidden[c] && c < sh->maxcols - 1) { + c++; + } + + } + return lookat(sh, sh->currow, c); +} + + +/** + * \brief forw_row() + * \details Move currow forward one displayed row + * \param[in] struct sheet * sh + * \param[in] arg + * \return lookat + */ +struct ent * forw_row(struct sheet * sh, int arg) { + int r = sh->currow; + + while (arg--) { + if (r < sh->maxrows - 1) + r++; + else { + if (! growtbl(sh, GROWROW, arg, 0)) { + sc_error("cannot grow sheet larger"); + return lookat(sh, sh->currow, sh->curcol); + } else + r++; + } + while (sh->row_hidden[r] && r < sh->maxrows - 1) r++; + } + return lookat(sh, r, sh->curcol); +} + + +/** + * \brief back_row() + * \details Moves currow backward on displayed row + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * back_row(struct sheet * sh, int arg) { + int r = sh->currow; + + while (--arg >= 0) { + if (r) { + --r; + } else { + sc_info ("At row 0"); + break; + } + while (sh->row_hidden[r] && r) --r; + } + return lookat(sh, r, sh->curcol); +} + + +/** + * \brief scroll_down() + * \param[in] struct sheet * sh + * \param[in] n + * \return none + */ +void scroll_down(struct sheet * sh, int n) { + while (n--) { + int last, currow_orig = sh->currow; + /* find last mobile row */ + calc_mobile_rows(sh, &last); + /* move to next non-hidden non-frozen row */ + do { + lookat(sh, ++last, sh->curcol); + if (last >= sh->maxrows) + return; + } while (sh->row_hidden[last] || sh->row_frozen[last]); + /* this will adjust offscr_sc_rows */ + sh->currow = last; + calc_mobile_rows(sh, NULL); + /* restore currow */ + sh->currow = currow_orig; + if (sh->currow < sh->offscr_sc_rows) + sh->currow = sh->offscr_sc_rows; + unselect_ranges(); + } +} + + +/** + * \brief scroll_up() + * \param[in] struct sheet * sh + * \param[in] n + * \return none + */ +void scroll_up(struct sheet * sh, int n) { + while (n--) { + int first, last, currow_orig = sh->currow; + /* move to previous non-hidden non-frozen row */ + first = sh->offscr_sc_rows; + do { + if (--first < 0) + return; + } while (sh->row_hidden[first] || sh->row_frozen[first]); + sh->offscr_sc_rows = first; + /* find corresponding last mobile row */ + sh->currow = first; + calc_mobile_rows(sh, &last); + /* restore/adjust currow */ + sh->currow = currow_orig; + if (sh->currow > last) + sh->currow = last; + unselect_ranges(); + } +} + + +/** + * \brief go_home() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * go_home(struct sheet * sh) { + return lookat(sh, 0, 0); +} + + +/** + * \brief vert_top() - for command H in normal mode + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * vert_top(struct sheet * sh) { + int r = sh->offscr_sc_rows; + while (sh->row_hidden[r] || sh->row_frozen[r]) r++; + return lookat(sh, r, sh->curcol); +} + + +/** + * \brief vert_bottom() - for command L in normal mode + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * vert_bottom(struct sheet * sh) { + int last; + calc_mobile_rows(sh, &last); + return lookat(sh, last, sh->curcol); +} + +/** + * \brief vert_middle() - for command M in normal mode + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * vert_middle(struct sheet * sh) { + int i; + int midscreen_pos = (SC_DISPLAY_ROWS - 1)/2; + int curr_pos = 0; + int mobile_rows = calc_mobile_rows(sh, NULL); + + for (i = 0; i < sh->maxrows; i++) { + if (sh->row_hidden[i]) + continue; + if (! sh->row_frozen[i]) { + if (i < sh->offscr_sc_rows) + continue; + if (--mobile_rows < 0) + continue; + } + + /* compare middle of current row against middle of screen */ + if (curr_pos + (sh->row_format[i] - 1)/2 >= midscreen_pos) + return lookat(sh, i, sh->curcol); + + curr_pos += sh->row_format[i]; + } + return NULL; +} + + +/** + * \brief go_end(): go to last valid cell of grid + * \param[in] struct sheet * sh + * \return lookat; NULL otherwise + */ +struct ent * go_end(struct sheet * sh) { + int r = 0, c = 0; + int raux = r, caux = c; + struct ent *p; + do { + if (c < sh->maxcols - 1) + c++; + else { + if (r < sh->maxrows - 1) { + r++; + c = 0; + } else break; + } + if (VALID_CELL(sh, p, r, c) && ! sh->col_hidden[c] && ! sh->row_hidden[r]) { raux = r; caux = c; } + } while ( r < sh->maxrows || c < sh->maxcols ); + if ( ! VALID_CELL(sh, p, r, c) && ! sh->col_hidden[c] && ! sh->row_hidden[r] ) + return lookat(sh, raux, caux); + return NULL; +} + + +/** + * \brief tick(): return an ent_ptr to an ent (or range) previously marked with the 'm' command. + * \details + * if ticks a cell, malloc's and returns an ent_ptr with struct ent * in ->vp. + * if ticks a range, malloc's and returns struct ent * to top left cell in ->vp. + * \return ent_ptr (should be free later on). + */ +struct ent_ptr * tick(char ch) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r, c; + struct mark * m = get_mark(ch); + if (m->sheet != NULL) sh = m->sheet; + struct ent_ptr * ep_result = calloc(1, sizeof(struct ent_ptr)); + + //tick cell + r = m->row; + if (r != -1) { + checkbounds(sh, &r, &(sh->curcol)); + ep_result->sheet = sh; + ep_result->vp = lookat(sh, r, m->col); + return ep_result; + } + + // tick range + if (curmode != VISUAL_MODE) { + r = m->rng->tlrow; + c = m->rng->tlcol; + m->rng->selected = 1; + checkbounds(sh, &r, &c); + ep_result->sheet = sh; + ep_result->vp = lookat(sh, r, c); + return ep_result; + } + free(ep_result); + return NULL; +} + + +/** + * \brief scroll_right() + * \param[in] struct sheet * sh + * \param[in] n + * \return none + */ +void scroll_right(struct sheet * sh, int n) { + while (n--) { + int last, curcol_orig = sh->curcol; + /* find last mobile column */ + calc_mobile_cols(sh, &last); + /* move to next non-hidden non-frozen column */ + do { + lookat(sh, sh->currow, ++last); + if (last >= sh->maxcols) + return; + } while (sh->col_hidden[last] || sh->col_frozen[last]); + /* this will adjust offscr_sc_cols */ + sh->curcol = last; + calc_mobile_cols(sh, NULL); + /* restore curcol */ + sh->curcol = curcol_orig; + if (sh->curcol < sh->offscr_sc_cols) + sh->curcol = sh->offscr_sc_cols; + unselect_ranges(); + } +} + +/** + * \brief scroll_left() + * \param[in] struct sheet * sh + * \param[in] n + * \return none + */ +void scroll_left(struct sheet * sh, int n) { + while (n--) { + int first, last, curcol_orig = sh->curcol; + /* move to previous non-hidden non-frozen column */ + first = sh->offscr_sc_cols; + do { + if (--first < 0) + return; + } while (sh->col_hidden[first] || sh->col_frozen[first]); + sh->offscr_sc_cols = first; + /* find corresponding last mobile column */ + sh->curcol = first; + calc_mobile_cols(sh, &last); + /* restore/adjust curcol */ + sh->curcol = curcol_orig; + if (sh->curcol > last) + sh->curcol = last; + unselect_ranges(); + } +} + + +/** + * \brief left_limit() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * left_limit(struct sheet * sh) { + int c = 0; + while (sh->col_hidden[c] && c < sh->curcol ) c++; + return lookat(sh, sh->currow, c); +} + + +/** + * \brief right_limit() + * \details get the last valid cell to the right + * \param[in] struct sheet * sh + * \param[in] row where to check + * \return lookat + */ +struct ent * right_limit(struct sheet * sh, int row) { + struct ent *p; + int c = sh->maxcols - 1; + while ( (! VALID_CELL(sh, p, row, c) && c > 0) || sh->col_hidden[c]) c--; + return lookat(sh, row, c); +} + + +/** + * \brief goto_top() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * goto_top(struct sheet * sh) { + int r = 0; + while (sh->row_hidden[r] && r < sh->currow ) r++; + return lookat(sh, r, sh->curcol); +} + + +/** + * \brief goto_bottom() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * goto_bottom(struct sheet * sh) { + struct ent *p; + int r = sh->maxrows - 1; + while ( (! VALID_CELL(sh, p, r, sh->curcol) && r > 0) || sh->row_hidden[r]) r--; + return lookat(sh, r, sh->curcol); +} + + +/** + * \brief goto_last_col() + * \details traverse the table and see which is the max column that has content + * this is because maxcol changes when moving cursor. + * this function is used when exporting files + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * goto_last_col(struct sheet * sh) { + int r, mr = sh->maxrows; + int c, mc = 0; + struct ent *p; + int rf = 0; + + for (r = 0; r < mr; r++) { + for (c = 0; c < sh->maxcols; c++) { + if (c >= mc && VALID_CELL(sh, p, r, c)) { mc = c; rf = r; } + } + } + return lookat(sh, rf, mc); +} + + +/** + * \brief go_forward() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * go_forward(struct sheet * sh) { + int r = sh->currow, c = sh->curcol; + int r_ori = r, c_ori = c; + struct ent * p; + do { + if (c < sh->maxcols - 1) { + c++; + } else { + if (r < sh->maxrows - 1) { + r++; + c = 0; + } else break; + } + if (VALID_CELL(sh, p, r, c) && ! sh->col_hidden[c] && ! sh->row_hidden[r] ) + return lookat(sh, r, c); + } while (r < sh->maxrows || c < sh->maxcols); + + return lookat(sh, r_ori, c_ori); +} + + +/** + * \brief go_bol() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * go_bol(struct sheet * sh) { + return lookat(sh, sh->currow, sh->offscr_sc_cols); +} + + +/** + * \brief go_eol() + * \param[in] struct sheet * sh + * \return none + */ +struct ent * go_eol(struct sheet * sh) { + int last_col; + calc_mobile_cols(sh, &last_col); + return lookat(sh, sh->currow, last_col); +} + + +/** + * \brief horiz_middle() + * \param[in] struct sheet * sh + * \return lookat; NULL otherwise + */ +struct ent * horiz_middle(struct sheet * sh) { + int i; + int midscreen_pos = (SC_DISPLAY_COLS - 1)/2; + int curr_pos = 0; + int mobile_cols = calc_mobile_cols(sh, NULL); + + for (i = 0; i < sh->maxcols; i++) { + if (sh->col_hidden[i]) + continue; + if (! sh->col_frozen[i]) { + if (i < sh->offscr_sc_cols) + continue; + if (--mobile_cols < 0) + continue; + } + + /* compare middle of current col against middle of screen */ + if (curr_pos + (sh->fwidth[i] - 1)/2 >= midscreen_pos) + return lookat(sh, sh->currow, i); + + curr_pos += sh->fwidth[i]; + } + return NULL; +} + + +/** + * \brief go_backward() + * \param[in] struct sheet * sh + * \return lookat + */ +struct ent * go_backward(struct sheet * sh) { + int r = sh->currow, c = sh->curcol; + int r_ori = r, c_ori = c; + struct ent * p; + do { + if (c) + c--; + else { + if (r) { + r--; + c = sh->maxcols - 1; + } else break; + } + if ( VALID_CELL(sh, p, r, c) && ! sh->col_hidden[c] && ! sh->row_hidden[r] ) + return lookat(sh, r, c); + } while ( sh->currow || sh->curcol ); + + return lookat(sh, r_ori, c_ori); +} + + +/** + * \brief auto_fit() + * \param[in] struct sheet * sh + * \param[in] ci + * \param[in] cf + * \param[in] min + * \return none + */ +void auto_fit(struct sheet * sh, int ci, int cf, int min) { + // column width is not set below the min value + int r, c, sum = 0; + char field[1024] = ""; + struct ent * p; + wchar_t widestring[BUFFERSIZE] = { L'\0' }; + mbstate_t state; + size_t result; + const char * mbsptr; + +#ifdef UNDO + create_undo_action(); +#endif + + checkbounds(sh, &(sh->maxrow), &cf); + + for (c = ci; c <= cf; c++) { +#ifdef UNDO + add_undo_col_format(c, 'R', sh->fwidth[c], sh->precision[c], sh->realfmt[c]); +#endif + sh->fwidth[c] = min; + for (r = 0; r <= sh->maxrow; r++) { + if ((p = *ATBL(sh, sh->tbl, r, c)) != NULL) { + sum = 0; + if (p->pad) sum += p->pad; + if (p->label) { + memset( &state, '\0', sizeof state ); + mbsptr = p->label; + result = mbsrtowcs(widestring, &mbsptr, BUFFERSIZE, &state); + if ( result != (size_t)-1 ) + sum += wcswidth(widestring, wcslen(widestring)); + } + if (p->flags & is_valid) { + sprintf(field, "%.*f", sh->precision[c], p->v); + sum += strlen(field); + } + if (sum > sh->fwidth[c] && sum < SC_DISPLAY_COLS) + sh->fwidth[c] = sum; + } + } +#ifdef UNDO + add_undo_col_format(c, 'A', sh->fwidth[c], sh->precision[c], sh->realfmt[c]); +#endif + } +#ifdef UNDO + end_undo_action(); +#endif + + return; +} + + +/** + * \brief valueize_area() + * \details + * Delete a cell expression and turn into constant. + * Deletes the expression associated with a cell and + * turns it into a constant containing whatever was on the screen. + * + * \param[in] struct sheet * sh + * \param[in] sr + * \param[in] sc + * \param[in] er + * \param[in] ec + * + * \return none + */ +void valueize_area(struct sheet * sh, int sr, int sc, int er, int ec) { + int r, c; + struct ent *p; + + if (sr > er) { + r = sr; sr = er; er= r; + } + + if (sc > ec) { + c = sc; sc = ec; ec= c; + } + + if (sr < 0) + sr = 0; + if (sc < 0) + sc = 0; + checkbounds(sh, &er, &ec); + + #ifdef UNDO + create_undo_action(); + copy_to_undostruct(sh, sr, sc, er, ec, UNDO_DEL, IGNORE_DEPS, NULL); + #endif + for (r = sr; r <= er; r++) { + for (c = sc; c <= ec; c++) { + p = *ATBL(sh, sh->tbl, r, c); + if (p && p->flags & is_locked) { + sc_error(" Cell %s%d is locked", coltoa(c), r); + continue; + } + if (p && p->expr) { + efree(p->expr); + p->expr = (struct enode *)0; + p->flags &= ~is_strexpr; + + // TODO move this to depgraph ? + vertexT * v_cur = getVertex(graph, sh, p, 0); + if (v_cur != NULL) { // just in case + + // for each edge in edges, we look for the reference to the vertex we are deleting, and we erase it! + edgeT * e = v_cur->edges; + while (e != NULL) { // && v_cur->back_edges == NULL) { + delete_reference(v_cur, e->connectsTo, 1); + + // delete vertex only if it end up having no edges, no expression, no value, no label.... + if (e->connectsTo->edges == NULL && e->connectsTo->back_edges == NULL && !e->connectsTo->ent->expr && !(e->connectsTo->ent->flags & is_valid) && ! e->connectsTo->ent->label) + destroy_vertex(sh, e->connectsTo->ent); + // WARNING: an orphan vertex now represents an ent that has an enode thats + // need to be evaluated, but do not depend in another cell. + e = e->next; + } + + destroy_list_edges(v_cur->edges); + v_cur->edges = NULL; + + /* delete vertex in graph + only if this vertex is not referenced by other */ + if (v_cur->back_edges == NULL ) destroy_vertex(sh, p); + } + } + } + } + #ifdef UNDO + copy_to_undostruct(sh, sr, sc, er, ec, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); + #endif + sc_info("Removed formulas from range"); + return; +} + + +/** + * \brief select_inner_range() + * \param[in] struct sheet * sh + * \param[in] vir_tlrow + * \param[in] vir_tlcol + * \param[in] vir_brrow + * \param[in] vir_brcol + * \return none + */ +void select_inner_range(struct sheet * sh, int * vir_tlrow, int * vir_tlcol, int * vir_brrow, int * vir_brcol) { + struct ent * p; + int rr, cc, r, c, mf = 1; + + while (mf != 0) { + mf = 0; + for (rr = *vir_tlrow; rr <= *vir_brrow; rr++) { + for (cc = *vir_tlcol; cc <= *vir_brcol; cc++) + for (r=-1; r<=1; r++) + for (c=-1; c<=1; c++) { + if (r == 0 && c == 0) continue; + else if (rr + r < 0 || cc + c < 0 || rr + r > sh->maxrow || cc + c > sh->maxcol) continue; + p = *ATBL(sh, sh->tbl, rr + r, cc + c); + if ( p != NULL && (p->label || p->flags & is_valid) ) { + if (*vir_brcol < cc + c) { + *vir_brcol = cc + c; + mf=1; + } + if (*vir_brrow < rr + r) { + *vir_brrow = rr + r; + mf=1; + } + if (*vir_tlcol > cc + c) { + *vir_tlcol = cc + c; + mf=1; + } + if (*vir_tlrow > rr + r) { + *vir_tlrow = rr + r; + mf = 1; + } + } + } + if (mf) break; + } // rr + } + return; +} + + +/** + * \brief locked_cell() + * \details Check if cell is locked + * \param[in] struct sheet * sh + * \param[in] int r + * \param[in] int c + * \return 1 if cell if locked; 0 otherwise + */ +int locked_cell(struct sheet * sh, int r, int c) { + struct ent *p = *ATBL(sh, sh->tbl, r, c); + if (p && (p->flags & is_locked)) { + sc_error("Cell %s%d is locked", coltoa(c), r) ; + return 1; + } + return 0; +} + + +/** + * \brief any_locked_cells() + * \details Check if area contains locked cells + * \param[in] struct sheet * sh + * \param[in] r1 + * \param[in] c1 + * \param[in] r2 + * \param[in] c2 + * \return 1 if area contains a locked cell; 0 otherwise + */ +int any_locked_cells(struct sheet * sh, int r1, int c1, int r2, int c2) { + int r, c; + struct ent * p ; + + for (r = r1; r <= r2; r++) + for (c = c1; c <= c2; c++) { + p = *ATBL(sh, sh->tbl, r, c); + if (p && (p->flags & is_locked)) + return 1; + } + return 0; +} + + +/** + * \brief fsum() + * \details sum special command + * \param[in] struct sheet * sh + * \return none + */ +int fsum(struct sheet * sh) { + int r = sh->currow, c = sh->curcol; + struct ent * p; + + if (r > 0 && (*ATBL(sh, sh->tbl, r-1, c) != NULL) && (*ATBL(sh, sh->tbl, r-1, c))->flags & is_valid) { + for (r = sh->currow-1; r >= 0; r--) { + p = *ATBL(sh, sh->tbl, r, c); + if (p == NULL) break; + if (! (p->flags & is_valid)) break; + } + if (sh->currow != r) { + swprintf(interp_line, BUFFERSIZE, L"let %s%d = @SUM(", coltoa(sh->curcol), sh->currow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d:", coltoa(sh->curcol), r+1); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d)", coltoa(sh->curcol), sh->currow-1); + } + } else if (c > 0 && (*ATBL(sh, sh->tbl, r, c-1) != NULL) && (*ATBL(sh, sh->tbl, r, c-1))->flags & is_valid) { + for (c = sh->curcol-1; c >= 0; c--) { + p = *ATBL(sh, sh->tbl, r, c); + if (p == NULL) break; + if (! (p->flags & is_valid)) break; + } + if (sh->curcol != c) { + swprintf(interp_line, BUFFERSIZE, L"let %s%d = @SUM(", coltoa(sh->curcol), sh->currow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d:", coltoa(c+1), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d)", coltoa(sh->curcol-1), r); + } + } + + if ((sh->currow != r || sh->curcol != c) && wcslen(interp_line)) + send_to_interp(interp_line); + EvalRange(sh, sh->currow, sh->curcol, sh->currow, sh->curcol); + return 0; +} + + +/** + * \brief fcopy() + * \param[in] struct sheet * sh + * \param[in] action + * \return -1 on error; 0 otherwise + */ +int fcopy(struct sheet * sh, char * action) { + int r, ri, rf, c, ci, cf; + struct ent * pdest; + struct ent * pact; + int p = is_range_selected(); + struct srange * sr = NULL; + if (p != -1) sr = get_range_by_pos(p); + + if (p == -1) { // no range selected + // fail if the cursor is on the first column + if (sh->curcol == 0) { + sc_error("Can't fcopy with no arguments while on column 'A'"); + return -1; + } + + ri = sh->currow; + ci = sh->curcol; + cf = sh->curcol; + for (r=ri+1; rmaxrow && (*ATBL(sh, sh->tbl, r, cf-1)) != NULL && (*ATBL(sh, sh->tbl, r, cf-1))->flags & is_valid ; r++) {} + rf = --r; + } else { // range is selected + ri = sr->tlrow; + ci = sr->tlcol; + cf = sr->brcol; + rf = sr->brrow; + } + + // check if all cells that will be copied to somewhere have a formula in them + if (! strcmp(action, "") || ! strcmp(action, "cells")) { + if (! *ATBL(sh, sh->tbl, ri, ci) ) goto formula_not_found; + if (! (*ATBL(sh, sh->tbl, ri, ci))->expr) goto formula_not_found; + } else if (! strcmp(action, "c") || ! strcmp(action, "columns")) { + for (c=ci; c<=cf; c++) { + if (! *ATBL(sh, sh->tbl, ri, c) ) goto formula_not_found; + if (! (*ATBL(sh, sh->tbl, ri, c))->expr) goto formula_not_found; + } + } else if (! strcmp(action, "r") || ! strcmp(action, "rows")) { + for (r=ri; r<=rf; r++) { + if (! *ATBL(sh, sh->tbl, r, ci) ) goto formula_not_found; + if (! (*ATBL(sh, sh->tbl, r, ci))->expr) goto formula_not_found; + } + } else { + sc_error("Invalid parameter"); + } + + goto all_formulas_found; + + formula_not_found: + sc_error("At least 1 formula not found. Nothing changed"); + return -1; + + all_formulas_found: + + if (any_locked_cells(sh, ri, ci, rf, cf)) { + swprintf(interp_line, BUFFERSIZE, L""); + sc_error("Locked cells encountered. Nothing changed"); + return -1; + } +#ifdef UNDO + create_undo_action(); + copy_to_undostruct(sh, ri, ci, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); +#endif + + if (! strcmp(action, "")) { + // copy first column down (old behavior), for backwards compatibility + pact = *ATBL(sh, sh->tbl, ri, ci); + for (r=ri+1; r<=rf; r++) { + pdest = lookat(sh, r, ci); + copyent(pdest, sh, pact, r - ri, 0, 0, 0, sh->maxrows, sh->maxcols, 'c'); + } + } else if (! strcmp(action, "c") || ! strcmp(action, "columns")) { + // copy all selected columns down + for (c=ci; c<=cf; c++) { + pact = *ATBL(sh, sh->tbl, ri, c); + for (r=ri+1; r<=rf; r++) { + pdest = lookat(sh, r, c); + copyent(pdest, sh, pact, r - ri, 0, 0, 0, sh->maxrows, sh->maxcols, 'c'); + } + } + } else if (! strcmp(action, "r") || ! strcmp(action, "rows")) { + // copy all selected rows right + for (r=ri; r<=rf; r++) { + pact = *ATBL(sh, sh->tbl, r, ci); + for (c=ci+1; c<=cf; c++) { + pdest = lookat(sh, r, c); + copyent(pdest, sh, pact, 0, c - ci, 0, 0, sh->maxrows, sh->maxcols, 'c'); + } + } + } else if (! strcmp(action, "cells")) { + // copy selected cell down and right + pact = *ATBL(sh, sh->tbl, ri, ci); + for (r=ri; r<=rf; r++) { + for(c=(r==ri?ci+1:ci); c<=cf; c++) { + pdest = lookat(sh, r, c); + copyent(pdest, sh, pact, r - ri, c - ci, 0, 0, sh->maxrows, sh->maxcols, 'c'); + } + } + } + EvalRange(sh, ri, ci, rf, cf); + +#ifdef UNDO + copy_to_undostruct(sh, ri, ci, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); +#endif + + return 0; +} + + +/** + * \brief pad() + * \details Add padding to cells + * \param[in] struct sheet * sh + * \param[in] int n + * \param[in] int r1 + * \param[in] int c1 + * \param[in] int r2 + * \param[in] int c2 + * \details Add padding to cells. This set padding of a range. + * \return -1 if locked cell is encountered; 1 if padding exceeded + * column width; 0 otherwise + */ +int pad(struct sheet * sh, int n, int r1, int c1, int r2, int c2) { + int r, c; + struct ent * p ; + int pad_exceed_width = 0; + + if (any_locked_cells(sh, r1, c1, r2, c2)) { + sc_info("Locked cells encountered. Nothing changed"); + return -1; + } + +#ifdef UNDO + create_undo_action(); + copy_to_undostruct(sh, r1, c1, r2, c2, UNDO_DEL, IGNORE_DEPS, NULL); +#endif + + for (r = r1; r <= r2; r++) { + for (c = c1; c <= c2; c++) { + if (n > sh->fwidth[c]) { + pad_exceed_width = 1; + continue; + } + if ((p = *ATBL(sh, sh->tbl, r, c)) != NULL) p->pad = n; + session->cur_doc->modflg++; + } + } + +#ifdef UNDO + copy_to_undostruct(sh, r1, c1, r2, c2, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); +#endif + + if (pad_exceed_width) { + sc_error(" Could not add padding in some cells. Padding exceeded column width"); + return 1; + } + return 0; +} + + +/** + * \brief fix_row_hidden() + * \param[in] struct sheet * sh + * \param[in] int deltar + * \param[in] int ri + * \param[in] int rf + * \details fix hidden rows after undoing ir dr etc.. + * \return none + */ +void fix_row_hidden(struct sheet * sh, int deltar, int ri, int rf) { + int r; + int d = deltar; + + // decrease / for dr + if (deltar > 0) + while (d-- > 0) + for (r = ri; r < rf; r++) + sh->row_hidden[r] = sh->row_hidden[r+1]; + + // increase / for ir + if (deltar < 0) + while (d++ < 0) + for (r = rf; r > ri; r--) + sh->row_hidden[r] = sh->row_hidden[r-1]; + return; +} + + +/** + * \brief fix_col_hidden() + * \details fix hidden cols after undoing ic dc etc.. + * \param[in] struct sheet * sh + * \param[in] int deltac + * \param[in] int ci + * \param[in] int cf + * \return none + */ +void fix_col_hidden(struct sheet * sh, int deltac, int ci, int cf) { + int c; + int d = deltac; + + // decrease / for dc + if (deltac > 0) + while (d-- > 0) + for (c = ci; c < cf; c++) + sh->col_hidden[c] = sh->col_hidden[c+1]; + + // increase / for ic + if (deltac < 0) + while (d++ < 0) + for (c = cf; c > ci; c--) + sh->col_hidden[c] = sh->col_hidden[c-1]; + return; +} + + +/** + * \brief fix_row_frozen() + * \details fix frozen rows after undoing ir dr etc.. + * \param[in] struct sheet * sh + * \param[in] int deltar + * \param[in] int ri + * \param[in] int rf + * \return none + */ +void fix_row_frozen(struct sheet * sh, int deltar, int ri, int rf) { + int r; + int d = deltar; + + // decrease / for dr + if (deltar > 0) + while (d-- > 0) + for (r = ri; r < rf; r++) + sh->row_frozen[r] = sh->row_frozen[r+1]; + + // increase / for ir + if (deltar < 0) + while (d++ < 0) + for (r = rf; r > ri; r--) + sh->row_frozen[r] = sh->row_frozen[r-1]; + return; +} + + +/** + * \brief fix_col_frozen() + * \details fix frozen cols after undoing ic dc etc.. + * \param[in] struct sheet * sh + * \param[in] int deltac + * \param[in] int ci + * \param[in] int cf + * \return none + */ +void fix_col_frozen(struct sheet * sh, int deltac, int ci, int cf) { + int c; + int d = deltac; + + // decrease / for dc + if (deltac > 0) + while (d-- > 0) + for (c = ci; c < cf; c++) + sh->col_frozen[c] = sh->col_frozen[c+1]; + + // increase / for ic + if (deltac < 0) + while (d++ < 0) + for (c = cf; c > ci; c--) + sh->col_frozen[c] = sh->col_frozen[c-1]; + return; +} + + +/** +* \brief convert_string_to_number +* \details converts string content of range of cells to numeric value +* \return 0 on success; -1 on error +*/ +int convert_string_to_number(int r0, int c0, int rn, int cn) { + struct roman * roman = session->cur_doc; + int row, col; + register struct ent ** pp; + wchar_t out[FBUFLEN] = L""; + for (row = r0; row <= rn; row++) { + // ignore hidden rows + //if (row_hidden[row]) continue; + + for (pp = ATBL(roman->cur_sh, roman->cur_sh->tbl, row, col = c0); col <= cn; col++, pp++) { + // ignore hidden cols + //if (col_hidden[col]) continue; + + if (*pp) { + // If a string exists + if ((*pp)->label) { + char * num = str_replace((*pp)->label," ",""); + (*pp)->label[0] = '\0'; + swprintf(out, BUFFERSIZE, L"let %s%d=%s", coltoa(col), row, num); + send_to_interp(out); + free(num); + } + } + } + } + return 0; +} + + +/** + * \brief Compute number of mobile (unfrozen) rows to fit on screen + * + * \details This function finds the number of mobile rows that can fit on + * the screen. This number excludes frozen rows as they never leave the + * screen hence their total height is subtracted from the available screen + * area. This number also excludes hidden rows. Displayed mobile rows are + * considered starting from offscr_sc_rows, however currow must be within + * the displayed rows. If currow is found to be outside the displayed set + * of rows then offscr_sc_rows is adjusted accordingly. + * + * \param[in] struct sheet * sh + * \param[in] last_p If not NULL then the last mobile row to fit is stored there + * + * \return Number of mobile rows displayable on the screen + */ +int calc_mobile_rows(struct sheet * sh, int *last_p) { + int i, row_space, mobile_rows, last; + + /* + * Compute the number of frozen rows and the space they need. + * Eventually this should be added/subtracted when individual rows + * are frozen/unfrozen/enlarged/reduced/deleted and not recomputed + * every time here... or at least have a global flag indicating that + * nothing has changed and that this loop can be skipped. + */ + sh->nb_frozen_rows = 0; + sh->nb_frozen_screenrows = 0; + for (i = 0; i < sh->maxrows; i++) { + if (sh->row_hidden[i]) + continue; + if (sh->row_frozen[i]) { + sh->nb_frozen_rows++; + sh->nb_frozen_screenrows += sh->row_format[i]; + } + } + + /* Adjust display start if currow is above it */ + if (sh->currow < sh->offscr_sc_rows) + sh->offscr_sc_rows = sh->currow; + + /* Determine the space available for mobile rows. */ + row_space = SC_DISPLAY_ROWS - sh->nb_frozen_screenrows; + + /* + * Find how many visible mobile rows can fit in there + * and remember which one is the last to fit. + */ + mobile_rows = 0; + last = sh->offscr_sc_rows; + for (i = sh->offscr_sc_rows; i < sh->maxrows; i++) { + count_rows_downward: + if (sh->row_hidden[i]) + continue; + if (sh->row_frozen[i]) + continue; + if (sh->row_format[i] > row_space) + break; + row_space -= sh->row_format[i]; + mobile_rows++; + last = i; + } + + /* + * If currow is beyond the last row here then we must start over, + * moving backward this time, to properly position start of display. + */ + if (last < sh->currow) { + row_space = SC_DISPLAY_ROWS - sh->nb_frozen_screenrows; + mobile_rows = 0; + last = sh->currow; + for (i = sh->currow; i >= 0; i--) { + if (sh->row_hidden[i]) + continue; + if (sh->row_frozen[i]) + continue; + if (sh->row_format[i] > row_space) + break; + row_space -= sh->row_format[i]; + mobile_rows++; + last = i; + } + sh->offscr_sc_rows = last; + last = sh->currow; + + /* + * Yet if the rows to follow have a smaller height than those we just + * counted then maybe they could fill the remaining space at the + * bottom edge of the screen. + */ + i = last + 1; + if (row_space > 0 && i < sh->maxrows) + goto count_rows_downward; + } + + if (last_p) + *last_p = last; + return mobile_rows; +} + +/** + * \brief Compute number of mobile (unfrozen) columns to fit on screen + * + * \details This function finds the number of mobile columns that can fit on + * the screen. This number excludes frozen columns as they never leave the + * screen, hence their total height is subtracted from the available screen + * area. This number also excludes hidden columns. Displayed mobile columnss + * are considered starting from offscr_sc_cols, however curcol must be within + * the displayed columns. If curcol is found to be outside the displayed set + * of columns then offscr_sc_cols is adjusted accordingly. + * + * \param[in] struct sheet * sh + * \param[in] last_p If not NULL then the last mobile column to fit is stored there + * + * \return Number of mobile columns displayable on the screen + */ +int calc_mobile_cols(struct sheet * sh, int *last_p) { + int i, col_space, mobile_cols, last; + + /* + * Compute the number of frozen columns and the space they need. + * Eventually this should be added/subtracted when individual + * columns are frozen/unfrozen/enlarged/reduced/deleted and not + * recomputed every time here... or at least have a flag indicating + * that nothing has changed and that this loop may be skipped. + */ + sh->nb_frozen_cols = 0; + sh->nb_frozen_screencols = 0; + for (i = 0; i < sh->maxcols; i++) { + if (sh->col_hidden[i]) + continue; + if (sh->col_frozen[i]) { + sh->nb_frozen_cols++; + sh->nb_frozen_screencols += sh->fwidth[i]; + } + } + + /* Adjust display start if curcol is left of it */ + if (sh->curcol < sh->offscr_sc_cols) + sh->offscr_sc_cols = sh->curcol; + + /* Determine the space available for mobile columns. */ + col_space = SC_DISPLAY_COLS - sh->nb_frozen_screencols; + + /* + * Find how many visible mobile columns can fit in there + * and remember which one is the last to fit. + */ + mobile_cols = 0; + last = sh->offscr_sc_cols; + for (i = sh->offscr_sc_cols; i < sh->maxcols; i++) { + count_cols_rightward: + if (sh->col_hidden[i]) + continue; + if (sh->col_frozen[i]) + continue; + if (sh->fwidth[i] > col_space) + break; + col_space -= sh->fwidth[i]; + mobile_cols++; + last = i; + } + + /* + * If curcol is beyond the last column here then we start over, + * moving backward this time, to properly position start of display. + */ + if (last < sh->curcol) { + col_space = SC_DISPLAY_COLS - sh->nb_frozen_screencols; + mobile_cols = 0; + last = sh->curcol; + for (i = sh->curcol; i >= 0; i--) { + if (sh->col_hidden[i]) + continue; + if (sh->col_frozen[i]) + continue; + if (sh->fwidth[i] > col_space) + break; + col_space -= sh->fwidth[i]; + mobile_cols++; + last = i; + } + sh->offscr_sc_cols = last; + last = sh->curcol; + + /* + * Yet if the columns to follow have a smaller width than those we + * just counted then maybe they could fill the remaining space at the + * right edge of the screen. + */ + i = last + 1; + if (col_space > 0 && i < sh->maxcols) + goto count_cols_rightward; + } + + if (last_p) + *last_p = last; + return mobile_cols; +} + + +/** + * \brief pad_and_align + * + * \details This function aligns text of a cell (align = 0 center, + * align = 1 right, align = -1 left). Also adds padding between cells. + * + * \param[in] srt_value + * \param[in] numeric_value + * \param[in] col_width + * \param[in] align + * \param[in] padding + * \param[in] str_out + * \param[in] rowfmt: rowheight + * + * \return resulting string to be printed to the screen + */ +void pad_and_align (char * str_value, char * numeric_value, int col_width, int align, int padding, wchar_t * str_out, int rowfmt) { + int str_len = 0; + int num_len = strlen(numeric_value); + str_out[0] = L'\0'; + + wchar_t wcs_value[BUFFERSIZE] = { L'\0' }; + mbstate_t state; + size_t result; + char * str_in; + + // Here we handle \" and replace them with " + str_in = str_replace(str_value, "\\\"", "\""); + + const char * mbsptr; + mbsptr = str_in; + + // create wcs string based on multibyte string.. + memset( &state, '\0', sizeof state ); + result = mbsrtowcs(wcs_value, &mbsptr, BUFFERSIZE, &state); + if ( result != (size_t)-1 ) + str_len = wcswidth(wcs_value, wcslen(wcs_value)); + + if (str_len == 2 && str_in[0] == '\\') { + wmemset(str_out + wcslen(str_out), str_in[1], col_width); + free(str_in); + return; + } else if (str_len == 3 && str_in[0] == '\\' && str_in[1] == '\\') { + wmemset(str_out + wcslen(str_out), str_in[2], col_width); + free(str_in); + return; + } + + // If padding exceedes column width, returns n number of '-' needed to fill column width + if (padding >= col_width ) { + wmemset(str_out + wcslen(str_out), L' ', col_width); + free(str_in); + return; + } + + // If content exceedes column width, outputs n number of '*' needed to fill column width + if (str_len + num_len + padding > col_width * rowfmt && ! get_conf_int("truncate") && + ! get_conf_int("overlap") && ! get_conf_int("autowrap")) { + if (padding) wmemset(str_out + wcslen(str_out), L' ', padding); + wmemset(str_out + wcslen(str_out), L'*', col_width - padding); + free(str_in); + return; + } + + // padding + if (padding) swprintf(str_out, BUFFERSIZE, L"%*ls", padding, L""); + + // left spaces + int left_spaces = 0; + if (align == 0) { // center align + left_spaces = (col_width - padding - str_len) / 2; + if (num_len > left_spaces) left_spaces = col_width - padding - str_len - num_len; + } else if (align == 1 && str_len && ! num_len) { // right align + left_spaces = col_width - padding - str_len; + } + while (left_spaces-- > 0) add_wchar(str_out, L' ', wcslen(str_out)); + + // add text + if (align != 1 || ! num_len) + swprintf(str_out + wcslen(str_out), BUFFERSIZE, L"%s", str_in); + + // spaces after string value + int spaces = col_width - padding - str_len - num_len; + if (align == 1){ + if(num_len) spaces += str_len; + else spaces = 0; + } + if (align == 0) spaces -= (col_width - padding - str_len) / 2; + while (spaces-- > 0) add_wchar(str_out, L' ', wcslen(str_out)); + + // add number + int fill_with_number = col_width - str_len - padding; + if (num_len && num_len >= fill_with_number) { + swprintf(str_out + wcslen(str_out), BUFFERSIZE, L"%.*s", fill_with_number, & numeric_value[num_len - fill_with_number]); + } else if (num_len) { + swprintf(str_out + wcslen(str_out), BUFFERSIZE, L"%s", numeric_value); + } + + // Similar condition to max width '*' condition above, but just trims instead + if (str_len + num_len + padding > col_width * rowfmt && get_conf_int("truncate")) { + str_out[col_width] = '\0'; + } + + // on each \n chars, replace with n number of L' ' to complete column width + int posnl, leftnl = 0; + while ((posnl = wstr_in_wstr(str_out, L"\\n")) != -1) { + del_range_wchars(str_out, posnl, posnl+1); + if (posnl <= col_width) leftnl = col_width - posnl; + else leftnl = col_width - posnl % col_width; + while (leftnl-- > 0) add_wchar(str_out, L' ', posnl); + } + + free(str_in); + return; +} + + +/** + * \brief Check if the buffer content is a valid command + * + * \details Check if the buffer content is a valid command + * result = 0 or NO_CMD : buf has no command + * result = 1 or EDITION_CMD : buf has a command + * result = 2 or MOVEMENT_CMD : buf has a movement command or a command that do not + * change cell content, and should not be considered by the '.' command + * + * \return result + */ +int is_single_command (struct block * buf, long timeout) { + if (buf->value == L'\0') return NO_CMD; + int result = NO_CMD; + int bs = get_bufsize(buf); + + if (curmode == COMMAND_MODE && bs == 1 && ( buf->value != ctl('r') || + buf->value == ctl('v')) ) { + result = MOVEMENT_CMD; + + } else if ( curmode == COMMAND_MODE && bs == 2 && buf->value == ctl('r') && + (buf->pnext->value - (L'a' - 1) < 1 || buf->pnext->value > 26)) { + result = MOVEMENT_CMD; + + } else if (curmode == INSERT_MODE && bs == 1 && ( buf->value != ctl('r') || + buf->value == ctl('v')) ) { + result = MOVEMENT_CMD; + + } else if (curmode == INSERT_MODE && bs == 2 && buf->value == ctl('r') && + (buf->pnext->value - (L'a' - 1) < 1 || buf->pnext->value > 26)) { + result = MOVEMENT_CMD; + + } else if (curmode == EDIT_MODE && bs == 1) { + result = MOVEMENT_CMD; + + } else if (curmode == NORMAL_MODE && bs == 1) { + // commands for changing mode + if (buf->value == L':') result = MOVEMENT_CMD; + else if (buf->value == L'\\') result = MOVEMENT_CMD; + else if (buf->value == L'<') result = MOVEMENT_CMD; + else if (buf->value == L'>') result = MOVEMENT_CMD; + else if (buf->value == L'=') result = MOVEMENT_CMD; + else if (buf->value == L'e') result = MOVEMENT_CMD; + else if (buf->value == L'E') result = MOVEMENT_CMD; + else if (buf->value == L'v') result = MOVEMENT_CMD; + + else if (buf->value == L'Q') result = MOVEMENT_CMD; /* FOR TEST PURPOSES */ + else if (buf->value == L'A') result = MOVEMENT_CMD; /* FOR TEST PURPOSES */ + else if (buf->value == L'W') result = MOVEMENT_CMD; /* FOR TEST PURPOSES */ + + // movement commands + else if (buf->value == L'j') result = MOVEMENT_CMD; + else if (buf->value == L'k') result = MOVEMENT_CMD; + else if (buf->value == L'h') result = MOVEMENT_CMD; + else if (buf->value == L'l') result = MOVEMENT_CMD; + else if (buf->value == L'0') result = MOVEMENT_CMD; + else if (buf->value == L'$') result = MOVEMENT_CMD; + else if (buf->value == OKEY_HOME) result = MOVEMENT_CMD; + else if (buf->value == OKEY_END) result = MOVEMENT_CMD; + else if (buf->value == L'#') result = MOVEMENT_CMD; + else if (buf->value == L'^') result = MOVEMENT_CMD; + else if (buf->value == OKEY_LEFT) result = MOVEMENT_CMD; + else if (buf->value == OKEY_RIGHT) result = MOVEMENT_CMD; + else if (buf->value == OKEY_DOWN) result = MOVEMENT_CMD; + else if (buf->value == OKEY_UP) result = MOVEMENT_CMD; + else if (buf->value == OKEY_PGUP) result = MOVEMENT_CMD; + else if (buf->value == OKEY_PGDOWN) result = MOVEMENT_CMD; + else if (buf->value == ctl('f')) result = MOVEMENT_CMD; + else if (buf->value == ctl('j')) result = EDITION_CMD; + else if (buf->value == ctl('d')) result = EDITION_CMD; + else if (buf->value == ctl('b')) result = MOVEMENT_CMD; + else if (buf->value == ctl('a')) result = MOVEMENT_CMD; + else if (buf->value == L'G') result = MOVEMENT_CMD; + else if (buf->value == L'H') result = MOVEMENT_CMD; + else if (buf->value == L'M') result = MOVEMENT_CMD; + else if (buf->value == L'L') result = MOVEMENT_CMD; + else if (buf->value == ctl('y')) result = MOVEMENT_CMD; + else if (buf->value == ctl('e')) result = MOVEMENT_CMD; + else if (buf->value == ctl('l')) result = MOVEMENT_CMD; + else if (buf->value == L'w') result = MOVEMENT_CMD; + else if (buf->value == L'b') result = MOVEMENT_CMD; + else if (buf->value == L'/') result = MOVEMENT_CMD; // search + else if (buf->value == L'?') result = MOVEMENT_CMD; // search backwards + else if (buf->value == L'n') result = MOVEMENT_CMD; // repeat last goto cmd + else if (buf->value == L'N') result = MOVEMENT_CMD; // repeat last goto cmd - backwards + + // edition commands + else if (buf->value == L'x') result = EDITION_CMD; // cuts a cell + else if (buf->value == L'u') result = MOVEMENT_CMD; // undo + else if (buf->value == ctl('r')) result = MOVEMENT_CMD; // redo + else if (buf->value == L'@') result = EDITION_CMD; // EvalAll + else if (buf->value == L'{') result = EDITION_CMD; + else if (buf->value == L'}') result = EDITION_CMD; + else if (buf->value == L'|') result = EDITION_CMD; + else if (buf->value == L'p') result = EDITION_CMD; // paste yanked cells below or left + else if (buf->value == L't') result = EDITION_CMD; // paste yanked cells above or right + else if (buf->value == L'-') result = EDITION_CMD; + else if (buf->value == L'+') result = EDITION_CMD; + + else if (isdigit(buf->value) && get_conf_int("numeric") ) + result = MOVEMENT_CMD; // repeat last command + + else if (buf->value == L'.') result = MOVEMENT_CMD; // repeat last command + else if (buf->value == L'y' && is_range_selected() != -1) + result = EDITION_CMD; // yank range + + } else if (curmode == NORMAL_MODE) { + + if (buf->value == L'g' && bs == 2 && ( + buf->pnext->value == L'f' || + buf->pnext->value == L'M' || + buf->pnext->value == L'g' || + buf->pnext->value == L'G' || + buf->pnext->value == L'0' || + buf->pnext->value == L'l' || + buf->pnext->value == L't' || + buf->pnext->value == L'T' || + buf->pnext->value == L'$')) + result = MOVEMENT_CMD; + + else if (buf->value == L'g' && bs > 3 && buf->pnext->value == L'o' && timeout >= COMPLETECMDTIMEOUT) + result = MOVEMENT_CMD; // goto cell + // TODO add validation: buf->pnext->pnext->value must be a letter + + else if (buf->value == L'P' && bs == 2 && ( + buf->pnext->value == L'v' || + buf->pnext->value == L'f' || + buf->pnext->value == L'c' ) ) result = EDITION_CMD; // paste yanked cells below or left + + else if (buf->value == L'T' && bs == 2 && ( + buf->pnext->value == L'v' || + buf->pnext->value == L'f' || + buf->pnext->value == L'c' ) ) result = EDITION_CMD; // paste yanked cells above or right + + else if (buf->value == L'a' && bs == 2 && // autofit + buf->pnext->value == L'a') result = EDITION_CMD; + + else if (buf->value == L'Z' && bs == 2 && timeout >= COMPLETECMDTIMEOUT && // Zap (or hide) col or row + ( buf->pnext->value == L'c' || + buf->pnext->value == L'r')) result = EDITION_CMD; + + else if (buf->value == L'S' && bs == 2 && timeout >= COMPLETECMDTIMEOUT && // Zap (or hide) col or row + ( buf->pnext->value == L'c' || + buf->pnext->value == L'r')) result = EDITION_CMD; + + else if (buf->value == L'y' && bs == 2 && // yank cell + ( buf->pnext->value == L'y' || + buf->pnext->value == L'r' || + buf->pnext->value == L'c') ) result = EDITION_CMD; + + else if (buf->value == L'm' && bs == 2 && // mark + ((buf->pnext->value - (L'a' - 1)) < 1 || + buf->pnext->value > 26)) result = MOVEMENT_CMD; + + else if (buf->value == L'c' && bs == 2 && // mark + ((buf->pnext->value - (L'a' - 1)) < 1 || buf->pnext->value > 26)) result = EDITION_CMD; + + else if (buf->value == L'z' && bs == 2 && // scrolling + ( buf->pnext->value == L'h' || + buf->pnext->value == L'l' || + buf->pnext->value == L'z' || + buf->pnext->value == L'm' || + buf->pnext->value == L'.' || + buf->pnext->value == L't' || + buf->pnext->value == L'b' || + buf->pnext->value == L'H' || + buf->pnext->value == L'L') + ) result = MOVEMENT_CMD; + + else if (buf->value == L'V' && bs == 3 && // Vir + buf->pnext->value == L'i' && + buf->pnext->pnext->value == L'r') + result = MOVEMENT_CMD; + + else if (buf->value == L'd' && bs == 2 && // cuts a cell + buf->pnext->value == L'd') result = EDITION_CMD; + + else if (buf->value == L'\'' && bs == 2 && // tick + ((buf->pnext->value - (L'a' - 1)) < 1 || + buf->pnext->value > 26)) result = MOVEMENT_CMD; + + else if (buf->value == L's' && bs == 2 && // shift cell down or up + ( buf->pnext->value == L'j' || + buf->pnext->value == L'k' || + buf->pnext->value == L'h' || + buf->pnext->value == L'l')) result = EDITION_CMD; + + else if (buf->value == L'i' && bs == 2 && // Insert row or column + ( buf->pnext->value == L'r' || + buf->pnext->value == L'c' )) result = EDITION_CMD; + + else if (buf->value == L'o' && bs == 2 && // Open row or column + ( buf->pnext->value == L'r' || + buf->pnext->value == L'c' )) result = EDITION_CMD; + + else if (buf->value == L'd' && bs == 2 && // Delete row or column + ( buf->pnext->value == L'r' || + buf->pnext->value == L'c' )) result = EDITION_CMD; + + else if (buf->value == L'r' && bs == 2 && // range lock / unlock / valueize + ( buf->pnext->value == L'l' || + buf->pnext->value == L'u' || + buf->pnext->value == L'v' )) result = EDITION_CMD; + + else if (buf->value == L'R' && bs == 3 && // Create range with two marks + // FIXME add better validation + ((buf->pnext->value - (L'a' - 1)) < 1 || + buf->pnext->value > 26) && + ((buf->pnext->pnext->value - (L'a' - 1)) < 1 || + buf->pnext->pnext->value > 26)) result = EDITION_CMD; + + else if (buf->value == L'f' && bs == 2 && // Format col + ( buf->pnext->value == L'>' || + buf->pnext->value == L'<' || + buf->pnext->value == L'h' || + buf->pnext->value == OKEY_LEFT || + buf->pnext->value == L'l' || + buf->pnext->value == OKEY_RIGHT || + buf->pnext->value == L'j' || + buf->pnext->value == OKEY_DOWN || + buf->pnext->value == L'k' || + buf->pnext->value == OKEY_UP || + buf->pnext->value == L'-' || + buf->pnext->value == L'+' || + buf->pnext->value == L'r' || // Freeze row / col / area + buf->pnext->value == L'c' || + buf->pnext->value == L'a' + ) + ) result = EDITION_CMD; + + } else if (curmode == VISUAL_MODE && bs == 1) { + if (buf->value == L'j' || + buf->value == OKEY_DOWN || + buf->value == L'k' || + buf->value == OKEY_UP || + buf->value == L'h' || + buf->value == OKEY_LEFT || + buf->value == L'l' || + buf->value == OKEY_RIGHT || + buf->value == L'$' || + buf->value == L'0' || + buf->value == L'#' || + buf->value == L'^' || + buf->value == L'y' || + buf->value == L'p' || + buf->value == L'P' || + buf->value == L'x' || + buf->value == L'w' || + buf->value == L'b' || + buf->value == L'H' || + buf->value == L'M' || + buf->value == L'L' || + buf->value == L'G' || + buf->value == ctl('f') || + buf->value == ctl('j') || + buf->value == ctl('d') || + buf->value == ctl('b') || + buf->value == ctl('a') || + buf->value == ctl('o') || + buf->value == ctl('k') || + buf->value == L':' + ) + result = MOVEMENT_CMD; + else if (buf->value == L'{' || + buf->value == L'}' || + buf->value == L'f' || + buf->value == L'|') + result = EDITION_CMD; + + } else if (curmode == VISUAL_MODE && bs == 2) { + if ((buf->value == L'\'') || + (buf->value == L'd' && + buf->pnext->value == L'd') || + (buf->value == L's' && ( + buf->pnext->value == L'h' || + buf->pnext->value == L'j' || + buf->pnext->value == L'k' || + buf->pnext->value == L'l' )) + ) { + result = MOVEMENT_CMD; + } else if ((buf->value == L'Z' && ( + buf->pnext->value == L'r' || + buf->pnext->value == L'c' )) || + (buf->value == L'S' && ( + buf->pnext->value == L'r' || + buf->pnext->value == L'c' )) ) { + result = EDITION_CMD; + } else if (buf->value == L'r' && ( + buf->pnext->value == L'l' || + buf->pnext->value == L'u' || + buf->pnext->value == L'v' )) { + result = EDITION_CMD; + } else if (buf->value == L'm' && // mark + ((buf->pnext->value - (L'a' - 1)) < 1 || + buf->pnext->value > 26)) { + result = MOVEMENT_CMD; + } + } + return result; +} diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_command.c sc-im-0.8.3+ds/src/cmds/cmds_command.c --- sc-im-0.8.2+ds/src/cmds/cmds_command.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_command.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,1169 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_command.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include +#include +#include // for isprint() + +#ifndef NO_WORDEXP +#include +#endif + +#include "cmds_command.h" +#include "cmds_visual.h" +#include "cmds_edit.h" +#include "cmds.h" +#include "../sc.h" // for rescol +#include "../conf.h" +#include "../utils/string.h" +#include "../utils/dictionary.h" +#include "../tui.h" +#include "../file.h" +#include "../main.h" +#include "../interp.h" +#include "../actions/hide_show.h" +#include "../exec.h" +#include "../help.h" +#include "../marks.h" +#include "../actions/filter.h" +#include "../maps.h" +#include "../formats/xls.h" +#include "../formats/xlsx.h" +#include "../actions/plot.h" + +#ifdef UNDO +#include "../undo.h" +#endif + +extern char * rev; +extern struct dictionary * user_conf_d; +extern struct session * session; + +wchar_t inputline[BUFFERSIZE]; +extern wchar_t interp_line[BUFFERSIZE]; +int inputline_pos; /**< Position in window. Some chars has 2 chars width */ +// see https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms +int real_inputline_pos; /**< Real position in inputline */ + +static wchar_t * valid_commands[] = { +L"!", +L"addfilter", +L"autofit", +L"ccopy", +L"cellcolor", +L"cmap", +L"cnoremap", +L"color", +L"cpaste", +L"cunmap", +L"datefmt", +L"define_color", +L"delfilter", +L"delfilters", +L"delsheet", +L"e csv", +L"e! csv", +L"e mkd", +L"e! mkd", +L"e tab", +L"e! tab", +L"e tex", +L"e! tex", +L"e txt", +L"e! txt", +L"e xlsx", +L"e! xlsx", +L"fcopy", +L"file", +L"fill", +L"filteroff", +L"filteron", +L"format", +L"formatcol", +L"formatrow", +L"freezecol", +L"freezerow", +L"fsum", +L"h", +L"help", +L"hiddencols", +L"hiddenrows", +L"hidecol", +L"hiderow", +L"imap", +L"inoremap", +L"int", +L"iunmap", +L"load!", +L"load", +L"lock", +L"newsheet", +L"nextsheet", +L"nmap", +L"nnoremap", +L"nunmap", +L"pad", +L"plot", +L"plotedit", +L"prevsheet", +L"q!", +L"q", +L"quit!", +L"quit", +L"redefine_color", +L"refresh", +L"renamesheet", +L"set", +L"showcol", +L"showcols", +L"showfilters", +L"showmaps", +L"showrow", +L"showrows", +L"sort", +L"strtonum", +L"subtotal", +L"trigger", +L"unformat", +L"unfreezecol", +L"unfreezerow", +L"unlock", +L"untrigger", +L"valueize", +L"version", +L"vmap", +L"vnoremap", +L"vunmap", +L"w", +L"wq", +L"x", +(wchar_t *) 0 +}; + +/** + * \brief TODO Document do_commandmode() + * + * \param[in] sb + * + * \return none + */ + +void do_commandmode(struct block * sb) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + + // If a visual selected range exists + int p = is_range_selected(); + struct srange * sr = NULL; + if (p != -1) sr = get_range_by_pos(p); + + + /* + * Normal KEY handlers for this MODE + */ + if (sb->value == OKEY_BS || sb->value == OKEY_BS2) { // BS + if ( ! wcslen(inputline) || ! real_inputline_pos ) return; + int l = wcwidth(inputline[real_inputline_pos - 1]); + real_inputline_pos--; + del_wchar(inputline, real_inputline_pos); + inputline_pos -= l; + ui_show_header(); + +#ifdef HISTORY_FILE + if (commandline_history->pos == 0) + del_wchar(get_line_from_history(commandline_history, commandline_history->pos), real_inputline_pos); // Clean history +#endif + ui_show_header(); + return; + + } else if (sb->value == OKEY_LEFT) { // LEFT + if (inputline_pos) { + real_inputline_pos--; + int l = wcwidth(inputline[real_inputline_pos]); + inputline_pos -= l; + } + ui_show_header(); + return; + + } else if (sb->value == OKEY_RIGHT) { // RIGHT + int max = wcswidth(inputline, wcslen(inputline)); + if (inputline_pos < max) { + int l = wcwidth(inputline[real_inputline_pos++]); + inputline_pos += l; + } + ui_show_header(); + return; + + } else if (sb->value == OKEY_DEL) { // DEL + if (inputline_pos > wcswidth(inputline, wcslen(inputline))) return; + del_wchar(inputline, real_inputline_pos); + +#ifdef HISTORY_FILE + if (commandline_history->pos == 0) + del_wchar(get_line_from_history(commandline_history, commandline_history->pos), real_inputline_pos); // Clean history +#endif + ui_show_header(); + return; + +#ifdef HISTORY_FILE + } else if (sb->value == OKEY_UP || sb->value == ctl('p') || // UP + sb->value == OKEY_DOWN || sb->value == ctl('n')) { // DOWN + + int delta = 0, k = 0, i, cmp; + if (sb->value == OKEY_UP || sb->value == ctl('p')) { // up + for (i=commandline_history->pos; -i+1 < commandline_history->len; i--, k--) + if (wcslen(get_line_from_history(commandline_history, 0))) { + if (! (cmp = wcsncmp(inputline, get_line_from_history(commandline_history, i-1), wcslen(get_line_from_history(commandline_history, 0))))) { + k--; + break; + } else if (commandline_history->len == 2-i && cmp) { + k=0; + break; + } + } else if (!wcslen(get_line_from_history(commandline_history, 0))) { + k--; + break; + } + } else if (sb->value == OKEY_DOWN || sb->value == ctl('n')) { // down + for (i=commandline_history->pos; i != 0; i++, k++) + if (wcslen(get_line_from_history(commandline_history, 0))) { + if (! (cmp = wcsncmp(inputline, get_line_from_history(commandline_history, i+1), wcslen(get_line_from_history(commandline_history, 0))))) { + k++; + break; + } else if (commandline_history->pos == 0 && cmp) { + k=0; + break; + } + } else if (!wcslen(get_line_from_history(commandline_history, 0))) { + k++; + break; + } + } + delta += k; + commandline_history->pos += delta; + wcscpy(inputline, get_line_from_history(commandline_history, commandline_history->pos)); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; +#endif + + } else if (sb->value == ctl('v') ) { // VISUAL SUBMODE + visual_submode = ':'; + chg_mode('v'); + start_visualmode(sh->currow, sh->curcol, sh->currow, sh->curcol); + return; + + } else if (sb->value == ctl('r') && get_bufsize(sb) == 2 && // C-r // FIXME ??? + (sb->pnext->value - (L'a' - 1) < 1 || sb->pnext->value > 26)) { + wchar_t cline [BUFFERSIZE]; + int i, r = get_mark(sb->pnext->value)->row; + if (r != -1) { + swprintf(cline, BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->col), r); + } else { + swprintf(cline, BUFFERSIZE, L"%s%d:", coltoa(get_mark(sb->pnext->value)->rng->tlcol), get_mark(sb->pnext->value)->rng->tlrow); + swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->rng->brcol), get_mark(sb->pnext->value)->rng->brrow); + } + for(i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]); + +#ifdef HISTORY_FILE + if (commandline_history->pos == 0) { // Only if editing the new command + wchar_t * sl = get_line_from_history(commandline_history, 0); + wcscat(sl, cline); // Insert into history + } +#endif + ui_show_header(); + return; + + } else if (sb->value == ctl('f')) { // C-f + wchar_t cline [BUFFERSIZE]; + int i; + struct ent * p1 = *ATBL(sh, sh->tbl, sh->currow, sh->curcol); + if (! p1 || ! p1->format) { + sc_error("cell has no format"); + return; + } + swprintf(cline, BUFFERSIZE, L"%s", p1->format); + for (i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]); + +#ifdef HISTORY_FILE + if (commandline_history->pos == 0) { // Only if editing the new command + wchar_t * sl = get_line_from_history(commandline_history, 0); + wcscat(sl, cline); // Insert into history + } +#endif + ui_show_header(); + return; + + } else if ( sb->value == ctl('w') || sb->value == ctl('b') || + sb->value == OKEY_HOME || sb->value == OKEY_END) { + switch (sb->value) { + case ctl('w'): + real_inputline_pos = for_word(1, 0, 1) + 1; // E + break; + case ctl('b'): + real_inputline_pos = back_word(1); // B + break; + case OKEY_HOME: + real_inputline_pos = 0; // 0 + break; + case OKEY_END: + real_inputline_pos = wcslen(inputline); // $ + break; + } + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == '\t') { // TAB completion + int i, clen = (sizeof(valid_commands) / sizeof(char *)) - 1; + + if (! get_comp()) copy_to_curcmd(inputline); // keep original cmd + + for (i = 0; i < clen; i++) { + if ( ! wcscmp(inputline, valid_commands[i]) ) { + wcscpy(inputline, get_curcmd()); + continue; + } + if ( ! wcsncmp(inputline, valid_commands[i], wcslen(inputline)) + ) { + wcscpy(inputline, valid_commands[i]); + real_inputline_pos = wcslen(inputline); + inputline_pos = wcswidth(inputline, real_inputline_pos); + set_comp(1); + break; + } + } + + // Restore inputline content + if (i == clen) { + wcscpy(inputline, get_curcmd()); + real_inputline_pos = wcslen(inputline); + inputline_pos = wcswidth(inputline, real_inputline_pos); + set_comp(0); + } + + ui_show_header(); + return; + + } else if (sc_isprint(sb->value)) { // Write new char + ins_in_line(sb->value); + ui_show_header(); + +#ifdef HISTORY_FILE + if (commandline_history->pos == 0) { // Only if editing the new command + wchar_t * sl = get_line_from_history(commandline_history, 0); + add_wchar(sl, sb->value, real_inputline_pos-1); // Insert into history + } +#endif + return; + + + /* + * CONFIRM A COMMAND PRESSING ENTER + */ + } else if (find_val(sb, OKEY_ENTER)) { + + if ( ! wcscmp(inputline, L"refresh")) { + sig_winchg(); + + } else if ( ! wcscmp(inputline, L"help") || ! wcscmp(inputline, L"h") ) { + help(); + + } else if ( ! wcscmp(inputline, L"q!") || ! wcscmp(inputline, L"quit!") ) { + shall_quit = 2; + + } else if ( ! wcscmp(inputline, L"q") || ! wcscmp(inputline, L"quit") ) { + shall_quit = 1; + + } else if ( ! wcsncmp(inputline, L"autofit", 7) ) { + wchar_t cline [BUFFERSIZE]; + wcscpy(cline, inputline); + int c = sh->curcol, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + cf = sr->brcol; + } + if ( p != -1 || ! wcscmp(inputline, L"autofit")) { + swprintf(cline, BUFFERSIZE, L"autofit %s:", coltoa(c)); + swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s", coltoa(cf)); + } + send_to_interp(cline); + + } else if ( ! wcsncmp(inputline, L"define_color", 12) ) { + send_to_interp(inputline); + + } else if ( ! wcsncmp(inputline, L"redefine_color", 14) ) { + send_to_interp(inputline); + + } else if ( ! wcsncmp(inputline, L"load", 4) ) { + char name [BUFFERSIZE]; + int name_ok = 0; + int force_rewrite = 0; + #ifndef NO_WORDEXP + size_t len; + wordexp_t p; + #endif + + wcstombs(name, inputline, BUFFERSIZE); + if ( ! wcsncmp(inputline, L"load! ", 6) ) { + force_rewrite = 1; + del_range_chars(name, 4, 4); + } + + del_range_chars(name, 0, 4); + if ( ! strlen(name) ) { + sc_error("Path to file to load is missing !"); + } else if (roman->modflg && ! force_rewrite ) { + sc_error("Changes were made since last save. Use '!' to force the load"); + } else { + #ifdef NO_WORDEXP + name_ok = 1; + #else + wordexp(name, &p, 0); + if ( p.we_wordc < 1 ) { + sc_error("Failed expanding filepath"); + + } else if ( (len = strlen(p.we_wordv[0])) >= sizeof(name) ) { + sc_error("File path too long"); + wordfree(&p); + } else { + memcpy(name, p.we_wordv[0], len+1); + name_ok = 1; + wordfree(&p); + } + #endif + } + + if ( name_ok ) { + if ( ! file_exists(name)) { + sc_error("File %s does not exists!", name); + } else { + delete_structures(); + create_structures(); + // create main session + session = (struct session *) calloc(1, sizeof(struct session)); + load_file(name); + + if (! get_conf_int("nocurses")) { + ui_show_header(); + } + } + } + } else if ( ! wcsncmp(inputline, L"hiderow ", 8) || + ! wcsncmp(inputline, L"showrow ", 8) || + ! wcsncmp(inputline, L"showcol ", 8) || + ! wcsncmp(inputline, L"hidecol ", 8) + ) { + send_to_interp(inputline); + + } else if ( ! wcsncmp(inputline, L"showrows", 8) ) { + if (p != -1) { // only continue if there is a selected range + int r, arg; + sr = get_range_by_pos(p); + r = sr->tlrow; + arg = sr->brrow - sr->tlrow + 1; + show_row(r, arg); + } + + } else if ( ! wcsncmp(inputline, L"showcols", 8) ) { + if (p != -1) { // only continue if there is a selected range + int r, arg; + sr = get_range_by_pos(p); + r = sr->tlcol; + arg = sr->brcol - sr->tlcol + 1; + show_col(r, arg); + } + + // range lock / unlock + } else if ( ! wcsncmp(inputline, L"lock", 4) || ! wcsncmp(inputline, L"unlock", 6) || + ! wcsncmp(inputline, L"valueize", 8) ) { + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + } + if ( ! wcsncmp(inputline, L"lock", 4) ) lock_cells(sh, lookat(sh, r, c), lookat(sh, rf, cf)); + else if ( ! wcsncmp(inputline, L"unlock", 6) ) unlock_cells(sh, lookat(sh, r, c), lookat(sh, rf, cf)); + else if ( ! wcsncmp(inputline, L"valueize", 8) ) valueize_area(sh, r, c, rf, cf); + + } else if ( ! wcsncmp(inputline, L"datefmt", 7)) { + wcscpy(interp_line, inputline); + + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { // in case there is a range selected + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + } + wchar_t cline [BUFFERSIZE]; + wcscpy(cline, interp_line); + int found = wstr_in_wstr(interp_line, L"\""); + if (found != -1) { + del_range_wchars(cline, 0, found-1); + swprintf(interp_line, BUFFERSIZE, L"datefmt %s%d:", coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d %ls", coltoa(cf), rf, cline); + send_to_interp(interp_line); + } + + } else if ( ! wcsncmp(inputline, L"sort ", 5) ) { + wcscpy(interp_line, inputline); + if (p != -1) { // in case there is a range selected + wchar_t cline [BUFFERSIZE]; + wcscpy(cline, interp_line); + int found = wstr_in_wstr(interp_line, L"\""); + if (found != -1) { + del_range_wchars(cline, 0, found-1); + swprintf(interp_line, BUFFERSIZE, L"sort %s%d:", coltoa(sr->tlcol), sr->tlrow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d %ls", coltoa(sr->brcol), sr->brrow, cline); + } + } + sc_info("Sorting.."); + send_to_interp(interp_line); + sc_info("Done."); + + } else if ( ! wcsncmp(inputline, L"subtotal ", 9) ) { + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol, pos, cancel = 0; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + } + if (any_locked_cells(sh, r, c, rf, cf)) { + sc_error("Locked cells encountered. Nothing changed"); + } else { + wchar_t line [BUFFERSIZE]; + wcscpy(line, inputline); + del_range_wchars(line, 0, 8); + if ( + (pos = wstr_in_wstr(line, L"@sum")) != -1 || + (pos = wstr_in_wstr(line, L"@avg")) != -1 || + (pos = wstr_in_wstr(line, L"@max")) != -1 || + (pos = wstr_in_wstr(line, L"@min")) != -1 ) { + add_wchar(line, L'\"', pos); + add_wchar(line, L'\"', pos+5); + } else if ( + (pos = wstr_in_wstr(line, L"@prod")) != -1) { + add_wchar(line, L'\"', pos); + add_wchar(line, L'\"', pos+6); + } else if ( + (pos = wstr_in_wstr(line, L"@count")) != -1) { + add_wchar(line, L'\"', pos); + add_wchar(line, L'\"', pos+7); + } else if ( + (pos = wstr_in_wstr(line, L"@stddev")) != -1) { + add_wchar(line, L'\"', pos); + add_wchar(line, L'\"', pos+8); + } else { + sc_error("Please specify a function to apply the subtotals"); + cancel = 1; + } + if (!cancel) { + swprintf(interp_line, BUFFERSIZE, L"subtotal %s%d:", coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(cf), rf); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); + send_to_interp(interp_line); + unselect_ranges(); + } + } + + } else if ( ! wcsncmp(inputline, L"freezecol", 9) ) { + if (p != -1) { + swprintf(interp_line, BUFFERSIZE, L"freeze %s:", coltoa(sr->tlcol)); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(sr->brcol)); + } else if (! wcscmp(inputline, L"freezecol")) { + swprintf(interp_line, BUFFERSIZE, L"freeze %s", coltoa(sh->curcol)); + } else + swprintf(interp_line, BUFFERSIZE, L"freeze %ls", &inputline[9]); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"freezerow", 9) ) { + if (p != -1) { + swprintf(interp_line, BUFFERSIZE, L"freeze %d:%d", sr->tlrow, sr->brrow); + } else if (! wcscmp(inputline, L"freezerow")) { + swprintf(interp_line, BUFFERSIZE, L"freeze %d", sh->currow); + } else + swprintf(interp_line, BUFFERSIZE, L"freeze %ls", &inputline[9]); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"unfreezecol", 11) ) { + if (p != -1) { + swprintf(interp_line, BUFFERSIZE, L"unfreeze %s:", coltoa(sr->tlcol)); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(sr->brcol)); + } else if (! wcscmp(inputline, L"unfreezecol")) { + swprintf(interp_line, BUFFERSIZE, L"unfreeze %s", coltoa(sh->curcol)); + } else + swprintf(interp_line, BUFFERSIZE, L"unfreeze %ls", &inputline[11]); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"unfreezerow", 11) ) { + if (p != -1) { + swprintf(interp_line, BUFFERSIZE, L"unfreeze %d:%d", sr->tlrow, sr->brrow); + } else if (! wcscmp(inputline, L"unfreezerow")) { + swprintf(interp_line, BUFFERSIZE, L"unfreeze %d", sh->currow); + } else + swprintf(interp_line, BUFFERSIZE, L"unfreeze %ls", &inputline[11]); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"addfilter", 9) ) { + wchar_t cline [BUFFERSIZE]; + char line [BUFFERSIZE]; + wcscpy(cline, inputline); + int found; + if ((found = wstr_in_wstr(cline, L"\"")) != -1) { + del_range_wchars(cline, wcslen(cline), wcslen(cline)); + del_range_wchars(cline, 0, found); + wcstombs(line, cline, BUFFERSIZE); + add_filter(line); + line[strlen(line)-1]='\0'; // remove last " + sc_info("Added filter: %s", line); + } + + } else if ( ! wcsncmp(inputline, L"delfilter ", 10) ) { + wchar_t cline [BUFFERSIZE]; + char line [BUFFERSIZE]; + wcscpy(cline, inputline); + del_range_wchars(cline, 0, 9); + wcstombs(line, cline, BUFFERSIZE); + int id = atoi(line); + if (del_filter(id) == 0) sc_info("Removed filter: %d", id); + + } else if ( ! wcsncmp(inputline, L"delfilters", 10) ) { + if (free_filters() == 0) sc_info("Removed filters"); + + } else if ( ! wcsncmp(inputline, L"filteron", 8) ) { + wcscpy(interp_line, inputline); + if ( ! wcscmp(inputline, L"filteron") && p == -1) { // If there is no selected range and no range in inputline passed + sc_error("Please specify a range or select one"); + } else if (p != -1) { + wchar_t cline [BUFFERSIZE]; + wcscpy(cline, interp_line); + swprintf(interp_line, BUFFERSIZE, L"filteron %s%d:", coltoa(sr->tlcol), sr->tlrow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(sr->brcol), sr->brrow); + send_to_interp(interp_line); + } else { // no range selected. range passed in inputline + send_to_interp(interp_line); + } + + } else if ( ! wcsncmp(inputline, L"filteroff", 9) ) { + disable_filters(); + + } else if ( ! wcsncmp(inputline, L"hiddenrows", 10)) { + show_hiddenrows(); + + } else if ( ! wcsncmp(inputline, L"hiddencols", 10)) { + show_hiddencols(); + + } else if ( ! wcsncmp(inputline, L"showfilters", 11)) { + show_filters(); + + } else if ( ! wcsncmp(inputline, L"int ", 4) ) { // send cmd to interpreter + wcscpy(interp_line, inputline); + del_range_wchars(interp_line, 0, 3); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"fill ", 5) ) { + interp_line[0]=L'\0'; + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + swprintf(interp_line, BUFFERSIZE, L"fill %s%d:", coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(cf), rf); + } + + if (any_locked_cells(sh, r, c, rf, cf)) { + swprintf(interp_line, BUFFERSIZE, L""); + sc_error("Locked cells encountered. Nothing changed"); + } else { + if (p != -1) + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", &inputline[5]); + else + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", inputline); + send_to_interp(interp_line); + } + + } else if ( ! wcsncmp(inputline, L"formatrow ", 10) ) { + int r = sh->currow, rf = sh->currow, i; + if (p != -1) { + r = sr->tlrow; + rf = sr->brrow; + } +#ifdef UNDO + int changed = 0, fmt_ori; + create_undo_action(); +#endif + for (i=r; i<=rf;i++) { +#ifdef UNDO + fmt_ori = sh->row_format[i]; + add_undo_row_format(i, 'R', sh->row_format[i]); +#endif + swprintf(interp_line, BUFFERSIZE, L"format %d %ls", i, &inputline[10]); + send_to_interp(interp_line); +#ifdef UNDO + if (fmt_ori != sh->row_format[i]) changed = 1; + add_undo_row_format(i, 'A', sh->row_format[i]); +#endif + } +#ifdef UNDO + if (! changed) dismiss_undo_item(NULL); + else end_undo_action(); +#endif + + } else if ( ! wcsncmp(inputline, L"formatcol ", 10) ) { + int c = sh->curcol, cf = sh->curcol, i; + if (p != -1) { + c = sr->tlcol; + cf = sr->brcol; + } +#ifdef UNDO + int changed = 0; + int fwidth_ori; + int precision_ori; + int realfmt_ori; + create_undo_action(); +#endif + for (i=c; i<=cf;i++) { +#ifdef UNDO + fwidth_ori = sh->fwidth[i]; + precision_ori = sh->precision[i]; + realfmt_ori = sh->realfmt[i]; + add_undo_col_format(i, 'R', sh->fwidth[i], sh->precision[i], sh->realfmt[i]); +#endif + swprintf(interp_line, BUFFERSIZE, L"format %s", coltoa(i)); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %ls", &inputline[10]); + send_to_interp(interp_line); +#ifdef UNDO + if (sh->fwidth[i] != fwidth_ori || sh->precision[i] != precision_ori || sh->realfmt[i] != realfmt_ori) changed = 1; + add_undo_col_format(i, 'A', sh->fwidth[i], sh->precision[i], sh->realfmt[i]); +#endif + } +#ifdef UNDO + if (! changed) dismiss_undo_item(NULL); + else end_undo_action(); +#endif + + } else if ( ! wcsncmp(inputline, L"format ", 7) ) { + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + swprintf(interp_line, BUFFERSIZE, L"fmt %s%d:", coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); + } else + swprintf(interp_line, BUFFERSIZE, L"fmt %s%d", coltoa(c), r); + + if (any_locked_cells(sh, r, c, rf, cf)) { + sc_error("Locked cells encountered. Nothing changed"); + } else { + int l = wcslen(interp_line); + swprintf(interp_line + l, BUFFERSIZE, L"%ls", inputline); + del_range_wchars(interp_line, l, l + 5); + #ifdef UNDO + create_undo_action(); + copy_to_undostruct(sh, r, c, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); + #endif + send_to_interp(interp_line); + #ifdef UNDO + copy_to_undostruct(sh, r, c, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); + #endif + } + + } else if ( ! wcsncmp(inputline, L"ccopy", 5) ) { + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + } + swprintf(interp_line, BUFFERSIZE, L"ccopy %s%d:", coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"strtonum", 8) ) { + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + } + swprintf(interp_line, BUFFERSIZE, L"strtonum %s%d:", coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"cpaste", 6) ) { + swprintf(interp_line, BUFFERSIZE, L"cpaste"); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"cellcolor ", 10) ) { + #ifdef USECOLORS + interp_line[0]=L'\0'; + wchar_t line [BUFFERSIZE]; + wcscpy(line, inputline); + del_range_wchars(line, 0, 9); + swprintf(interp_line, BUFFERSIZE, L"cellcolor "); + if (p != -1) { + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow); + } + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); + send_to_interp(interp_line); + #else + sc_error("Color support not compiled in"); + chg_mode('.'); + inputline[0] = L'\0'; + #endif + + } else if ( ! wcsncmp(inputline, L"unformat", 8) ) { + #ifdef USECOLORS + interp_line[0]=L'\0'; + wchar_t line [BUFFERSIZE]; + wcscpy(line, inputline); + del_range_wchars(line, 0, 7); + swprintf(interp_line, BUFFERSIZE, L"unformat"); + if (p != -1) { + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow); + } + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); + send_to_interp(interp_line); + #else + sc_error("Color support not compiled in"); + chg_mode('.'); + inputline[0] = L'\0'; + #endif + + } else if ( ! wcsncmp(inputline, L"color ", 6) ) { + #ifdef USECOLORS + char line [BUFFERSIZE]; + wcstombs(line, inputline, BUFFERSIZE); + del_range_chars(line, 0, 5); + chg_color(line); + #else + sc_error("Color support not compiled in"); + chg_mode('.'); + inputline[0] = '\0'; + #endif + + } else if ( ! wcsncmp(inputline, L"trigger ", 8) ) { + interp_line[0]=L'\0'; + wchar_t line [BUFFERSIZE]; + wcscpy(line, inputline); + del_range_wchars(line, 0, 7); + swprintf(interp_line, BUFFERSIZE, L"trigger "); + if (p != -1) { + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow); + } + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"untrigger ", 10) ) { + wcscpy(interp_line, inputline); + send_to_interp(interp_line); + + // Change a config value + } else if ( ! wcsncmp(inputline, L"set ", 4) ) { + change_config_parameter(inputline); + + } else if ( ! wcsncmp(inputline, L"pad ", 4) ) { + int c = sh->curcol, cf = sh->curcol; + if (p != -1) { // in case there is a range selected + c = sr->tlcol; + cf = sr->brcol; + } + wcscpy(interp_line, inputline); // pad 5 + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s:", coltoa(c)); // pad 5 A: + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(cf)); // B + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"plot ", 5) ) { + int r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if (p != -1) { + c = sr->tlcol; + r = sr->tlrow; + rf = sr->brrow; + cf = sr->brcol; + } + wchar_t aux[wcslen(inputline)+1]; + wcscpy(aux, inputline); + del_range_wchars(aux, 0, 4); + swprintf(interp_line, BUFFERSIZE, L"plot \"%ls\" %s%d:", aux, coltoa(c), r); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); + send_to_interp(interp_line); + + } else if ( ! wcsncmp(inputline, L"plotedit ", 9) ) { + wchar_t aux[wcslen(inputline)+1]; + wcscpy(aux, inputline); + del_range_wchars(aux, 0, 8); + plotedit(aux); + + } else if ( ! wcscmp(inputline, L"set") ) { + char valores[get_dict_buffer_size(user_conf_d) + 1]; + get_conf_values(valores); + ui_show_text(valores); + + } else if ( ! wcscmp(inputline, L"version") ) { + ui_show_text(rev); + + } else if ( ! wcscmp(inputline, L"showmaps") ) { + extern int len_maps; + char valores[MAXMAPITEM * len_maps]; + get_mappings(valores); + ui_show_text(valores); + + } else if ( ! wcsncmp(inputline, L"newsheet", 8) || + ! wcsncmp(inputline, L"delsheet", 8) || + ! wcsncmp(inputline, L"nextsheet", 9) || + ! wcsncmp(inputline, L"renamesheet", 11) || + ! wcsncmp(inputline, L"prevsheet", 9)) { + send_to_interp(inputline); + + } else if ( ! wcsncmp(inputline, L"nmap", 4) || + ! wcsncmp(inputline, L"imap", 4) || + ! wcsncmp(inputline, L"vmap", 4) || + ! wcsncmp(inputline, L"cmap", 4) || + ! wcsncmp(inputline, L"inoremap", 8) || + ! wcsncmp(inputline, L"nnoremap", 8) || + ! wcsncmp(inputline, L"vnoremap", 8) || + ! wcsncmp(inputline, L"cnoremap", 8) || + ! wcsncmp(inputline, L"iunmap", 6) || + ! wcsncmp(inputline, L"vunmap", 6) || + ! wcsncmp(inputline, L"cunmap", 6) || + ! wcsncmp(inputline, L"nunmap", 6) ) { + send_to_interp(inputline); + + } else if ( ! wcsncmp(inputline, L"!", 1) ) { + char line [BUFFERSIZE]; + wcstombs(line, inputline, BUFFERSIZE); + int found = str_in_str(line, " "); + if (found == -1) found++; + del_range_chars(line, 0, found); + exec_cmd(line); + + } else if ( ! wcscmp(inputline, L"wq") ) { + wcscpy(inputline, L"x"); + if (savefile() == 0) shall_quit = 1; + + } else if ( inputline[0] == L'w' ) { + savefile(); + + } else if ( ! wcsncmp(inputline, L"file ", 5) ) { + char * curfile = session->cur_doc->name; + char name [BUFFERSIZE]; + int name_ok = 0; + #ifndef NO_WORDEXP + size_t len; + wordexp_t p; + #endif + + wcstombs(name, inputline, BUFFERSIZE); + del_range_chars(name, 0, 4); + + #ifdef NO_WORDEXP + name_ok = 1; + #else + wordexp(name, &p, 0); + if ( p.we_wordc < 1 ) { + sc_error("Failed to expand filename"); + } else if ( (len = strlen(p.we_wordv[0])) >= sizeof(name) ) { + sc_error("File path too long"); + wordfree(&p); + } else { + memcpy(name, p.we_wordv[0], len+1); + name_ok = 1; + wordfree(&p); + } + #endif + + if (name_ok) { + #ifdef AUTOBACKUP + // check if backup of current loaded file exists. + // if it exists, remove it. + if (curfile != NULL && strlen(curfile) && backup_exists(curfile)) remove_backup(curfile); + #endif + if (roman->name == NULL) roman->name = malloc(sizeof(char)*PATHLEN); + strncpy(roman->name, name, PATHLEN - 1); + sc_info("File name set to \"%s\"", roman->name); + } + + } else if ( ! wcscmp(inputline, L"file") ) { + char * curfile = session->cur_doc->name; + if (curfile == NULL || ! curfile) { + sc_info("Current file has no name"); + } else { + sc_info("Current file: \"%s\"", curfile); + } + + } else if ( inputline[0] == L'x' ) { + if (savefile() == 0) shall_quit = 1; + + } else if ( ! wcscmp(inputline, L"fcopy") ) { + fcopy(sh, ""); + + } else if ( ! wcsncmp(inputline, L"fcopy ", 6)) { + wchar_t line [BUFFERSIZE]; + wcscpy(line, inputline); + del_range_wchars(line, 0, 5); + char action[BUFFERSIZE]; + wcstombs(action, line, BUFFERSIZE); + fcopy(sh, action); + + } else if ( ! wcscmp(inputline, L"fsum") ) { + fsum(sh); + + } else if ( + ! wcsncmp(inputline, L"e csv" , 5) || + ! wcsncmp(inputline, L"e! csv" , 6) || + ! wcsncmp(inputline, L"e tex" , 5) || + ! wcsncmp(inputline, L"e! tex" , 6) || + ! wcsncmp(inputline, L"e tab" , 5) || + ! wcsncmp(inputline, L"e! tab" , 6) || + ! wcsncmp(inputline, L"e mkd" , 4) || + ! wcsncmp(inputline, L"e! mkd" , 5) || + ! wcsncmp(inputline, L"e txt" , 5) || + ! wcsncmp(inputline, L"e! txt" , 6) ) { + do_export( p == -1 ? 0 : sr->tlrow, p == -1 ? 0 : sr->tlcol, + p == -1 ? sh->maxrow : sr->brrow, p == -1 ? sh->maxcol : sr->brcol); + + } else if ( + ! wcsncmp(inputline, L"e xlsx" , 6) || + ! wcsncmp(inputline, L"e! xlsx" , 7)) { + char * curfile = session->cur_doc->name; + #ifndef XLSX_EXPORT + sc_error("XLSX export support not compiled in"); + #else + char linea[BUFFERSIZE]; + char filename[PATHLEN] = ""; + int force_rewrite = 0; + if (inputline[1] == L'!') force_rewrite = 1; + wcstombs(linea, inputline, BUFFERSIZE); // Use new variable to keep command history untouched + del_range_chars(linea, 0, 1 + force_rewrite); // Remove 'e' or 'e!' from inputline + + // Get path and file name to write. + // Use parameter if any. + if (strlen(linea) > 5) { // ex. 'xlsx ' + del_range_chars(linea, 0, 4); // remove 'xlsx' + strcpy(filename, linea); + // Use curfile name and '.xlsx' extension + // Remove current '.sc' extension if necessary + } else if (curfile != NULL && strlen(curfile)) { + strcpy(filename, curfile); + char * ext = strrchr(filename, '.'); + if (ext != NULL) del_range_chars(filename, strlen(filename) - strlen(ext), strlen(filename)-1); + sprintf(filename + strlen(filename), ".xlsx"); + } else { + sc_error("No filename specified !"); + } + + if (strlen(filename) > 0 && ! force_rewrite && file_exists(filename)) { + sc_error("File %s already exists. Use \"!\" to force rewrite.", filename); + + #ifdef AUTOBACKUP + // check if backup of filename exists. + // if it exists and '!' is set, remove it. + // if it exists and curfile = fname, remove it. + // else return. + } else if (strlen(filename) && backup_exists(filename) + && ! force_rewrite && ! (strlen(curfile) && ! strcmp(curfile, filename))) { + sc_error("Backup file of %s exists. Use \"!\" to force the write process.", filename); + #endif + } else if (strlen(filename)) { + #ifdef AUTOBACKUP + if (backup_exists(filename)) remove_backup(filename); + #endif + if (export_xlsx(filename) == 0) + sc_info("File \"%s\" written", filename); + } + #endif + + } else { + sc_error("COMMAND NOT FOUND !"); + } + +#ifdef HISTORY_FILE + /* + * if exists in history an item with same text to the command typed + * (counting from the second position) it is moved to the beginning of list. + * (first element in list means last command executed) + */ + del_item_from_history(commandline_history, 0); + int moved = move_item_from_history_by_str(commandline_history, inputline, -1); + if (! moved) add(commandline_history, inputline); + commandline_history->pos = 0; +#endif + + chg_mode('.'); + inputline[0]=L'\0'; + inputline_pos = 0; //ADDED 08/10/2018 + set_comp(0); // unmark tab completion + ui_update(TRUE); + } + return; +} + +/** + * \brief TODO Document ins_in_line() + * + * \param[in] d + * + * \return none + */ + +void ins_in_line(wint_t d) { + add_wchar(inputline, (wchar_t) d, real_inputline_pos++); + inputline_pos += wcwidth((wchar_t) d); + return; +} diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_command.h sc-im-0.8.3+ds/src/cmds/cmds_command.h --- sc-im-0.8.2+ds/src/cmds/cmds_command.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_command.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_command.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for cmds_command.c + */ + +#ifdef HISTORY_FILE +#include "../history.h" +#endif +#include "../buffer.h" + +extern int shall_quit; +extern struct dictionary * user_conf_d; +extern struct history * commandline_history; + +void do_commandmode(struct block * sb); +void ins_in_line(wint_t d); diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_edit.c sc-im-0.8.3+ds/src/cmds/cmds_edit.c --- sc-im-0.8.2+ds/src/cmds/cmds_edit.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_edit.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,710 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_edit.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include +#include + +#include "cmds.h" +#include "cmds_edit.h" +#include "../sc.h" // for rescol +#include "../tui.h" +#include "../buffer.h" +#include "../utils/string.h" +#include "../interp.h" +#include "../marks.h" +#include "../conf.h" +#include "../history.h" + +// this macro is used to determinate a word over a WORD +#define istext(a) (iswalnum(a) || ((a) == L'_')) + +#ifdef INS_HISTORY_FILE +extern char ori_insert_edit_submode; +#endif + +static wint_t wi; /**< char read from stdin */ +extern struct session * session; + +/** + * \brief TODO Document do_editmode() + * + * \param[in] sb + * + * \return none + */ + +void do_editmode(struct block * sb) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int pos; + int initial_position; + + if (sb->value == L'h' || sb->value == OKEY_LEFT) { // LEFT + if (real_inputline_pos) { + real_inputline_pos--; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } + ui_show_header(); + return; + + } else if (sb->value == L'l' || sb->value == OKEY_RIGHT) { // RIGHT + if (real_inputline_pos < wcslen(inputline)-1) { + real_inputline_pos++; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } + ui_show_header(); + return; + + } else if (sb->value == L' ' && ( wcslen(inputline) < (COLS - 14) ) ) { // SPACE + add_wchar(inputline, L' ', real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'^') { // ^ + pos = first_nonblank_char(); + if (pos == -1) return; + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'g') { // ^ + if (ui_getch_b(&wi) == -1 || wi != L'_') return; + pos = last_nonblank_char(); + if (pos == -1) return; + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'0' || sb->value == OKEY_HOME) { // 0 + inputline_pos = 0; + real_inputline_pos = 0; + ui_show_header(); + return; + + } else if (sb->value == L'$' || sb->value == OKEY_END) { // $ + inputline_pos = wcswidth(inputline, wcslen(inputline)) - 1; + real_inputline_pos = wcslen(inputline) - 1; + ui_show_header(); + return; + + } else if (sb->value == L'I') { // I + inputline_pos = 0; + real_inputline_pos = 0; +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + ui_show_header(); + return; + + } else if (sb->value == L'i' || sb->value == L'=') { // i o = +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + ui_show_header(); + return; + + } else if (sb->value == L'x') { // x + del_back_char(); + ui_show_header(); + return; + + } else if (sb->value == L'X') { // X + del_for_char(); + ui_show_header(); + return; + + } else if (sb->value == L'r') { // r + //curs_set(1); + if (ui_getch_b(&wi) != -1) inputline[real_inputline_pos] = wi; + //curs_set(2); + ui_show_header(); + return; + + } else if (find_val(sb, OKEY_ENTER) || sb->value == OKEY_ESC) { // ENTER or ESC + char ope[BUFFERSIZE] = ""; + wchar_t content[BUFFERSIZE] = L""; + wcscpy(content, inputline); + + switch (insert_edit_submode) { + case '=': + strcpy(ope, "let"); + break; + case '<': + strcpy(ope, "leftstring"); + break; + case '>': + strcpy(ope, "rightstring"); + break; + case '\\': + strcpy(ope, "label"); + break; + } + + if (content[0] == L'"') { + del_wchar(content, 0); + } else if (insert_edit_submode != '=' && content[0] != L'"') { + add_wchar(content, L'\"', 0); + add_wchar(content, L'\"', wcslen(content)); + } + + enter_cell_content(sh, sh->currow, sh->curcol, ope, content); + + inputline[0] = L'\0'; + inputline_pos = 0; + real_inputline_pos = 0; + chg_mode('.'); + ui_clr_header(1); + + char * opt = get_conf_value("newline_action"); + switch (opt[0]) { + case 'j': + sh->currow = forw_row(sh, 1)->row; + break; + case 'l': + sh->curcol = forw_col(sh, 1)->col; + break; + } + ui_update(TRUE); + return; + + } else if (sb->value == L'a') { // a + real_inputline_pos++; + inputline_pos = wcswidth(inputline, real_inputline_pos); +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + ui_show_header(); + return; + + } else if (sb->value == L'A') { // A + real_inputline_pos = wcslen(inputline); + inputline_pos = wcswidth(inputline, real_inputline_pos); +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + ui_show_header(); + return; + + } else if (sb->value == L'D') { // D + inputline[real_inputline_pos] = L'\0'; + if (real_inputline_pos == wcslen(inputline) && real_inputline_pos && sb->value == L'D') real_inputline_pos--; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'C') { // C + inputline[real_inputline_pos] = L'\0'; + inputline_pos = wcswidth(inputline, real_inputline_pos); +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + ui_show_header(); + return; + + } else if (sb->value == L's') { // s + del_back_char(); +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + ui_show_header(); + return; + + } else if (sb->value == L'f') { // f + if (ui_getch_b(&wi) == -1) return; + pos = look_for((wchar_t) wi); // this returns real_inputline_pos ! + if (pos != -1) { + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + } + return; + + } else if (sb->value == L't') { // t + if (ui_getch_b(&wi) == -1) return; + int initial_position = inputline_pos; + if (inputline_pos < wcswidth(inputline, wcslen(inputline))) inputline_pos++ ; + pos = look_for((wchar_t) wi); // this returns real_inputline_pos ! + if (pos != -1) { + real_inputline_pos = pos - 1; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } else { + inputline_pos = initial_position; + } + ui_show_header(); + return; + + } else if (sb->value == L'F') { // F + if (ui_getch_b(&wi) == -1) return; + pos = look_back((wchar_t) wi); // this returns real_inputline_pos ! + if (pos != -1) { + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + } + return; + + } else if (sb->value == L'T') { // T + if (ui_getch_b(&wi) == -1) return; + int initial_position = inputline_pos; + if (inputline_pos) inputline_pos--; + pos = look_back((wchar_t) wi); // this returns real_inputline_pos ! + if (pos != -1) { + real_inputline_pos = pos + 1; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } else { + inputline_pos = initial_position; + } + ui_show_header(); + return; + + } else if (sb->value == L'w') { // w + real_inputline_pos = for_word(0, 0, 0); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'W') { // W + real_inputline_pos = for_word(0, 0, 1); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'e') { // e + real_inputline_pos = for_word(1, 0, 0); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'E') { // E + real_inputline_pos = for_word(1, 0, 1); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'b') { // b + real_inputline_pos = back_word(0); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'B') { // B + real_inputline_pos = back_word(1); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == L'R') { // R + //curs_set(1); + if (ui_getch_b(&wi) == -1) return; + wint_t c = wi; + while (c != OKEY_ENTER && c != -1) { + if (iswprint(c)) { + inputline[real_inputline_pos] = c; + ++real_inputline_pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + } + if (ui_getch_b(&wi) == -1) return; + c = wi; + } + //curs_set(2); + + + } else if (sb->value == L'd' || sb->value == L'c') { // d or c + wint_t c, d; + if (ui_getch_b(&wi) != -1) { + c = wi; + switch (c) { + case L'$': + pos = wcswidth(inputline, wcslen(inputline)) - 1; + del_range_wchars(inputline, real_inputline_pos, pos); + if (real_inputline_pos == wcslen(inputline) && real_inputline_pos && sb->value == L'd') real_inputline_pos--; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'f': + if (ui_getch_b(&wi) == -1) return; + d = wi; + pos = look_for((wchar_t) d); // this returns real_inputline_pos ! + if (pos != -1) del_range_wchars(inputline, real_inputline_pos, pos); + break; + + case L't': + if (ui_getch_b(&wi) == -1) return; + initial_position = inputline_pos; + if (inputline_pos < wcswidth(inputline, wcslen(inputline))) inputline_pos++ ; + pos = look_for((wchar_t) wi); + if (pos != -1) { + del_range_wchars(inputline, real_inputline_pos, pos - 1); + inputline_pos = wcswidth(inputline, real_inputline_pos); + } else { + inputline_pos = initial_position; + } + break; + + case L'0': // 0 + del_range_wchars(inputline, 0, real_inputline_pos-1); + real_inputline_pos = 0; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'^': + pos = first_nonblank_char(); + if (pos == -1) return; + del_range_wchars(inputline, pos, real_inputline_pos-1); + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'g': + if (ui_getch_b(&wi) == -1 || wi != L'_') return; + pos = last_nonblank_char(); + if (pos == -1) return; + del_range_wchars(inputline, real_inputline_pos, pos); + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'e': // de or ce + //OK + del_range_wchars(inputline, real_inputline_pos, for_word(1, 0, 0)); + break; + + case L'E': // dE or cE + del_range_wchars(inputline, real_inputline_pos, for_word(1, 0, 1)); + break; + + case L'w': // dw or cw + del_range_wchars(inputline, real_inputline_pos, for_word(0, 1, 0) - 1); + if (real_inputline_pos == wcslen(inputline) && real_inputline_pos && sb->value == L'd') real_inputline_pos--; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'W': // dW or cW + del_range_wchars(inputline, real_inputline_pos, for_word(0, 1, 1) - 1); + if (real_inputline_pos == wcslen(inputline) && real_inputline_pos && sb->value == L'd') real_inputline_pos--; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'b': // db or cb + d = back_word(0); + del_range_wchars(inputline, d, real_inputline_pos-1); + real_inputline_pos = d; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'B': // dB or cB + d = back_word(1); + del_range_wchars(inputline, d, real_inputline_pos-1); + real_inputline_pos = d; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'F': + if (ui_getch_b(&wi) == -1) return; + pos = look_back((wchar_t) wi); + if (pos != -1) del_range_wchars(inputline, pos, real_inputline_pos-1); + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + break; + + case L'T': + if (ui_getch_b(&wi) == -1) return; + initial_position = inputline_pos; + if (inputline_pos) inputline_pos--; + pos = look_back((wchar_t) wi); + + if (pos != -1) { + del_range_wchars(inputline, pos+1, real_inputline_pos-1); + real_inputline_pos = pos; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } else { + inputline_pos = initial_position; + } + break; + + case L'l': // dl or cl + case OKEY_RIGHT: + del_back_char(); + break; + + case L'h': // dh or ch + case OKEY_LEFT: + del_for_char(); + break; + + case L'a': + if (ui_getch_b(&wi) == -1) return; + d = wi; + if ( d == L'W' ) { // daW or caW + c = ( real_inputline_pos && inputline[real_inputline_pos-1] == L' ' ) ? real_inputline_pos : back_word(1); + del_range_wchars(inputline, c, for_word(0, 1, 1) - 1); + real_inputline_pos = (wcslen(inputline) > real_inputline_pos) ? c : wcslen(inputline)-2; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } else if ( d == L'w' ) { // daw or caw + d = ( real_inputline_pos && ! istext( inputline[real_inputline_pos-1]) ) ? real_inputline_pos : back_word(0); + del_range_wchars(inputline, d, for_word(0, 1, 0) - 1); + real_inputline_pos = (wcslen(inputline) > real_inputline_pos) ? d : wcslen(inputline)-2; + inputline_pos = wcswidth(inputline, real_inputline_pos); + } + break; + } + if (sb->value == L'c') { +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = insert_edit_submode; + add(insert_history, L""); +#endif + chg_mode(insert_edit_submode); + } + } + + } + ui_show_header(); + return; +} + +/** + * \brief Looks (forward) for a char in inputline + * + * \param[in] cb + * + * \return position; -1 otherwise + */ + +int look_for(wchar_t cb) { + int c, cpos = inputline_pos; + while (++cpos < wcslen(inputline)) + if ((c = inputline[cpos]) && c == cb) return cpos; + //if (cpos > 0 && cpos == wcslen(inputline)) return real_inputline_pos; + return -1; +} + +/** + * \brief Looks (backwards) for a char in inputline + * + * \param[in] cb + * + * \return position; -1 otherwise + */ + +int look_back(wchar_t cb) { + int c, cpos = inputline_pos; + while (--cpos >= 0) + if ((c = inputline[cpos]) && c == cb) return cpos; + return -1; +} + +/** + * \brief Looks for a first non blank char in inputline + * + * \return position if found; -1 otherwise + */ +int first_nonblank_char() { + int cpos = -1; + while (++cpos < wcslen(inputline)) + if (inputline[cpos] && inputline[cpos] != L' ') return cpos; + return -1; +} + + +/** + * \brief Looks for the last non blank char in inputline + * + * \return position if found; -1 otherwise + */ +int last_nonblank_char() { + int cpos = wcslen(inputline); + while (--cpos > 0) + if (inputline[cpos] && inputline[cpos] != L' ') return cpos; + return -1; +} + +/** + * \brief Move backward one word + * + * \param[in] big_word + * + * \return position + */ + +int back_word(int big_word) { + int c, cpos = real_inputline_pos; + if (inputline[cpos-1] == L' ' ) cpos--; + + while (cpos) + if ((c = inputline[--cpos]) && c == L' ' ) return cpos+1; + else if ( istext( inputline [cpos] ) && ! istext( inputline[cpos - 1] ) && ! big_word ) return cpos; + else if ( ! istext( inputline [cpos] ) && istext( inputline[cpos - 1] ) && ! big_word ) return cpos; + return cpos; +} + +/** + * \brief Move to the end of a word + * + * \details Used for moving forward to the end of a WORD. big_word + * looks for ' ', else looks for istext. + * + * \param[in] end_of_word + * \param[in] delete + * \param[in] big_word + * + * \return position; 0 otherwise + */ + +int for_word(int end_of_word, int delete, int big_word) { + int cpos = real_inputline_pos; + + if (! end_of_word) { // w or W + while ( ++cpos < wcslen(inputline) ) + if ( ! istext( inputline[cpos - 1]) && inputline[cpos] != L' ' && ! big_word ) return cpos; + else if ( inputline[cpos] == L' ' ) return ++cpos; + else if ( ! istext( inputline [cpos] ) && istext( inputline[cpos - 1] ) && ! big_word ) return cpos; + } else { // e or E + if ( inputline[cpos+1] == L' ' ) cpos += 2; + else if ( ! istext( inputline [cpos+1] ) && istext( inputline[cpos] ) && ! big_word ) cpos++; + while ( ++cpos < wcslen(inputline) ) + if ( ( inputline[cpos] == L' ' ) || ( ! istext( inputline [cpos] ) + && istext( inputline[cpos - 1] ) && ! big_word ) ) return --cpos; + } + + if (cpos > 0 && cpos >= wcslen(inputline)) return wcslen(inputline) - 1 + delete; + return 0; +} + + +/** + * \brief del_back_char() + * \return none + */ +void del_back_char() { // x DEL + int max = wcswidth(inputline, wcslen(inputline)); + if (inputline_pos > max) return; + int l = wcwidth(inputline[real_inputline_pos]); + del_wchar(inputline, real_inputline_pos); + if (real_inputline_pos == wcslen(inputline) && wcslen(inputline)) { + inputline_pos -= l; + real_inputline_pos--; + } else if (! wcslen(inputline)) { + inputline_pos = 0; + } + return; +} + + +/** + * \brief del_for_char() + * \return none + */ +void del_for_char() { // X BS + if ( ! wcslen(inputline) || ! real_inputline_pos ) return; + int l = wcwidth(inputline[real_inputline_pos - 1]); + del_wchar(inputline, real_inputline_pos-1); + real_inputline_pos--; + inputline_pos -= l; + return; +} + + +/** + * \brief start_edit_mode() + * \returns: 1 on success; 0 on error + */ +int start_edit_mode(struct block * buf, char type) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + chg_mode(buf->value); + + line[0]='\0'; + inputline[0]=L'\0'; + + struct ent * p1 = lookat(sh, sh->currow, sh->curcol); + + if (type == 'v') { // && p1->flags & is_valid) { // numeric value + if (( ! (p1->expr) ) ) { // || (p1->flags & is_strexpr)) { + (void) swprintf(inputline, BUFFERSIZE, L"%.15g", p1->v); + } else { // expression + linelim = 0; + editexp(sh, sh->currow, sh->curcol); + linelim = -1; + (void) swprintf(inputline, BUFFERSIZE, L"%s", line); + } + insert_edit_submode='='; + + } else if (type == 's') { // string value + if (! ((p1)->label || (p1)->flags & is_strexpr)) { + return 0; + } + if (p1->flags & is_label) { + insert_edit_submode='\\'; + } else if (p1->flags & is_leftflush) { + insert_edit_submode='<'; + } else { + insert_edit_submode='>'; + } + linelim = 0; + edits(sh, sh->currow, sh->curcol, 0); + linelim = -1; + if ((p1)->flags & is_strexpr) swprintf(inputline + wcslen(inputline), BUFFERSIZE, L"\""); + (void) swprintf(inputline + wcslen(inputline), BUFFERSIZE, L"%s", line); + } + inputline_pos = wcswidth(inputline, wcslen(inputline)) - 1; + real_inputline_pos = wcslen(inputline) - 1; + //ui_show_header(); + return 1; +} diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_edit.h sc-im-0.8.3+ds/src/cmds/cmds_edit.h --- sc-im-0.8.2+ds/src/cmds/cmds_edit.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_edit.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_edit.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for cmds_edit.c + */ + +#include "../input.h" + +void do_editmode(struct block * sb); +int start_edit_mode(struct block * buf, char type); + +int for_word(int end_of_word, int delt, int big_word); +int look_for(wchar_t cb); +int look_back(wchar_t cb); +int back_word(int big_word); + +void del_back_char(); +void del_for_char(); + +int first_nonblank_char(); +int last_nonblank_char(); + +wint_t get_key(); diff -Nru sc-im-0.8.2+ds/src/cmds/cmds.h sc-im-0.8.3+ds/src/cmds/cmds.h --- sc-im-0.8.2+ds/src/cmds/cmds.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds.h + * \author Andrés Martinelli + * \date 2021-05-02 + * \brief Header file for cmds.c + */ + +#include +#include "../macros.h" +#include "../sc.h" + +extern char insert_edit_submode; // insert or edit submode +extern wchar_t inputline[BUFFERSIZE]; +extern int inputline_pos; +extern int real_inputline_pos; +extern struct block * lastcmd_buffer; + +int is_single_command (struct block * buf, long timeout); +void enter_cell_content(struct sheet * sh, int r, int c, char * submode, wchar_t * content); +void send_to_interp(wchar_t * oper); // Send command to interpreter +void chg_mode(char strcmd); // Change mode function +int modcheck(); // Verify if open file has been modified +int savefile(); // Save open file +void copyent(struct ent * n, struct sheet * sh_p, struct ent * p, int dr, int dc, int r1, int c1, int r2, int c2, int special); +void flush_saved(); +void insert_row(struct sheet * sh, int after); +void insert_col(struct sheet * sh, int after); +void deleterow(struct sheet * sh, int row, int mult); +void int_deleterow(struct sheet * sh, int row, int mult); +void deletecol(struct sheet * sh, int col, int mult); +void int_deletecol(struct sheet * sh, int col, int mult); +void formatcol(struct sheet * sh, int c); +void del_selected_cells(struct sheet * sh); +struct ent * lookat(struct sheet * sh, int row, int col); // return pointer to 'ent' of cell. Create it if it doesn't exist +void cleanent(struct ent * p); // Initialize 'ent' to zero. Won't free memory +void clearent(struct ent * v); // free 'ent' memory. +int locked_cell(struct sheet * sh, int r, int c); +int any_locked_cells(struct sheet * sh, int r1, int c1, int r2, int c2); +void scroll_left (struct sheet * sh, int n); +void scroll_right (struct sheet * sh, int n); +void scroll_down(struct sheet * sh, int n); +void scroll_up(struct sheet * sh, int n); +struct ent_ptr * tick(char ch); // 'tick' ( ' ) command +struct ent * left_limit(struct sheet * sh); +struct ent * right_limit(struct sheet * sh, int row); +struct ent * goto_top(struct sheet * sh); +struct ent * goto_bottom(struct sheet * sh); +struct ent * forw_row(struct sheet * sh, int arg); +struct ent * back_row(struct sheet * sh, int arg); +struct ent * forw_col(struct sheet * sh, int arg); +struct ent * back_col(struct sheet * sh, int arg); +struct ent * go_home(struct sheet * sh); +struct ent * go_end(struct sheet * sh); +struct ent * go_forward(struct sheet * sh); +struct ent * go_backward(struct sheet * sh); +struct ent * vert_top(struct sheet * sh); +struct ent * vert_middle(struct sheet * sh); +struct ent * vert_bottom(struct sheet * sh); +struct ent * go_bol(struct sheet * sh); +struct ent * go_eol(struct sheet * sh); +struct ent * horiz_middle(struct sheet * sh); +struct ent * goto_last_col(struct sheet * sh); +void select_inner_range(struct sheet * sh, int * vir_tlrow, int * vir_tlcol, int * vir_brrow, int * vir_brcol); +void ljustify(struct sheet * sh, int sr, int sc, int er, int ec); +void rjustify(struct sheet * sh, int sr, int sc, int er, int ec); +void center(struct sheet * sh, int sr, int sc, int er, int ec); +void doformat(struct sheet * sh, int c1, int c2, int w, int p, int r); +void dorowformat(struct sheet * sh, int r, unsigned char size); +int etype(struct enode *e); +void erase_area(struct sheet * sh, int sr, int sc, int er, int ec, int ignorelock, int mark_as_deleted); +void auto_fit(struct sheet * sh, int ci, int cf, int min); +void valueize_area(struct sheet * sh, int sr, int sc, int er, int ec); +void sync_refs(struct sheet * sh); +void syncref(struct sheet * sh, struct enode * e); +int fcopy(struct sheet * sh, char * action); +int fsum(struct sheet * sh); +int pad(struct sheet * sh, int n, int r1, int c1, int r2, int c2); +int convert_string_to_number(int r0, int c0, int rn, int cn); + +void fix_row_hidden(struct sheet * sh, int deltar, int ri, int rf); +void fix_col_hidden(struct sheet * sh, int deltac, int ci, int cf); +void fix_row_frozen(struct sheet * sh, int deltar, int ri, int rf); +void fix_col_frozen(struct sheet * sh, int deltac, int ci, int cf); + +void mark_ent_as_deleted(struct ent * p, int del); +int calc_mobile_rows(struct sheet * sh, int *); +int calc_mobile_cols(struct sheet * sh, int *); + +void pad_and_align (char * str_value, char * numeric_value, int col_width, int align, int padding, wchar_t * str_out, int rowfmt); diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_insert.c sc-im-0.8.3+ds/src/cmds/cmds_insert.c --- sc-im-0.8.2+ds/src/cmds/cmds_insert.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_insert.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,296 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_insert.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include +#include + +#include "cmds_insert.h" +#include "cmds.h" +#include "cmds_visual.h" +#include "../tui.h" +#include "../buffer.h" +#include "../sc.h" // for rescol +#include "../utils/string.h" +#include "../marks.h" +#include "../conf.h" + +#ifdef INS_HISTORY_FILE +char ori_insert_edit_submode; +#endif + +extern void ins_in_line(wint_t d); +extern struct session * session; + +/** + * \brief TODO Document do_insertmode() + * + * \param[in] sb + * + * returns: none + */ + +void do_insertmode(struct block * sb) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + + if (sb->value == ctl('v') ) { // VISUAL SUBMODE + visual_submode = insert_edit_submode; + chg_mode('v'); + start_visualmode(sh->currow, sh->curcol, sh->currow, sh->curcol); + return; + + } else if (sb->value == OKEY_LEFT) { // LEFT + if (inputline_pos) { + real_inputline_pos--; + int l = wcwidth(inputline[real_inputline_pos]); + inputline_pos -= l; + } + ui_show_header(); + return; + + } else if (sb->value == OKEY_RIGHT) { // RIGHT + int max = wcswidth(inputline, wcslen(inputline)); + if (inputline_pos < max) { + int l = wcwidth(inputline[real_inputline_pos++]); + inputline_pos += l; + } + ui_show_header(); + return; + +#ifdef INS_HISTORY_FILE + } else if (sb->value == OKEY_UP || sb->value == ctl('p') || // UP + sb->value == OKEY_DOWN || sb->value == ctl('n')) { // DOWN + + int delta = 0, i, cmp; + if (sb->value == OKEY_UP || sb->value == ctl('p')) { // up + for (i=insert_history->pos; -i+1 < insert_history->len; i--, delta--) + if (wcslen(get_line_from_history(insert_history, 0))) { + if (! (cmp = wcsncmp(inputline, &get_line_from_history(insert_history, i-1)[1], wcslen(get_line_from_history(insert_history, 0))))) { + delta--; + break; + } else if (insert_history->len == 2-i && cmp) { + delta=0; + break; + } + } else if (!wcslen(get_line_from_history(insert_history, 0))) { + delta--; + break; + } + } else if (sb->value == OKEY_DOWN || sb->value == ctl('n')) { // down + for (i=insert_history->pos; i != 0; i++, delta++) + if (wcslen(get_line_from_history(insert_history, 0))) { + if (! (cmp = wcsncmp(inputline, &get_line_from_history(insert_history, i+1)[1], wcslen(get_line_from_history(insert_history, 0))))) { + delta++; + break; + } else if (insert_history->pos == 0 && cmp) { + delta=0; + break; + } + } else if (!wcslen(get_line_from_history(insert_history, 0))) { + delta++; + break; + } + } + insert_history->pos += delta; + + wchar_t word [COLS]; + wcscpy(word, get_line_from_history(insert_history, insert_history->pos)); + if (insert_history->pos == 0) + insert_edit_submode = ori_insert_edit_submode; + else { + insert_edit_submode = word[0]; + del_wchar(word, 0); + } + wcscpy(inputline, word); + inputline_pos = wcswidth(inputline, real_inputline_pos); + + chg_mode(insert_edit_submode); + ui_show_header(); + return; +#endif + + } else if (sb->value == OKEY_BS || sb->value == OKEY_BS2) { // BS + if ( ! wcslen(inputline) || ! real_inputline_pos ) return; + + int l = wcwidth(inputline[real_inputline_pos - 1]); + real_inputline_pos--; + del_wchar(inputline, real_inputline_pos); + inputline_pos -= l; + ui_show_header(); +#ifdef INS_HISTORY_FILE + if (insert_history->pos == 0) + del_wchar(get_line_from_history(insert_history, insert_history->pos), real_inputline_pos); // Clean history +#endif + + } else if (sb->value == OKEY_DEL) { // DEL + int max = wcswidth(inputline, wcslen(inputline)); + if (inputline_pos > max) return; + del_wchar(inputline, real_inputline_pos); +#ifdef INS_HISTORY_FILE + if (insert_history->pos == 0) + del_wchar(get_line_from_history(insert_history, insert_history->pos), real_inputline_pos); // Clean history +#endif + ui_show_header(); + + } else if (sb->value == OKEY_TAB) { // TAB + if (inputline_pos && wcslen(inputline) >= inputline_pos) { + real_inputline_pos--; + int l = wcwidth(inputline[real_inputline_pos]); + inputline_pos -= l; + } + chg_mode(insert_edit_submode == '=' ? 'e' : 'E'); + ui_show_header(); + + } else if (find_val(sb, OKEY_ENTER)) { // ENTER + char ope[BUFFERSIZE] = ""; + wchar_t content[BUFFERSIZE] = L""; + wcscpy(content, inputline); + + switch (insert_edit_submode) { + case '=': + strcpy(ope, "let"); + break; + case '<': + strcpy(ope, "leftstring"); + break; + case '>': + strcpy(ope, "rightstring"); + break; + case '\\': + strcpy(ope, "label"); + break; + } + + if (content[0] == L'"') { + del_wchar(content, 0); + } else if (insert_edit_submode != '=' && content[0] != L'"') { + add_wchar(content, L'\"', 0); + add_wchar(content, L'\"', wcslen(content)); + } + + enter_cell_content(sh, sh->currow, sh->curcol, ope, content); + +#ifdef INS_HISTORY_FILE + /* + * if exists in history an item with same text to the command typed + * (counting from the second position) it is moved to the beginning of list. + * (first element in list means last command executed) + */ + del_item_from_history(insert_history, 0); + wchar_t copy[BUFFERSIZE]; + + swprintf(copy, BUFFERSIZE, L"%c%ls", insert_edit_submode, inputline); + int moved = move_item_from_history_by_str(insert_history, copy, -1); + if (! moved) add(insert_history, copy); + insert_history->pos = 0; +#endif + + inputline[0] = L'\0'; + inputline_pos = 0; + real_inputline_pos = 0; + chg_mode('.'); + //ui_clr_header(1); + + char * opt = get_conf_value("newline_action"); + switch (opt[0]) { + case 'j': + sh->currow = forw_row(sh, 1)->row; + break; + case 'l': + sh->curcol = forw_col(sh, 1)->col; + break; + } + ui_update(TRUE); + return; + + + } else if (sb->value == OKEY_HOME) { // HOME + real_inputline_pos = 0; + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + } else if (sb->value == OKEY_END) { // END + real_inputline_pos = wcslen(inputline); + inputline_pos = wcswidth(inputline, real_inputline_pos); + ui_show_header(); + return; + + // Write new char !! + //} else if ( wcslen(inputline) < (COLS - 16) && sc_isprint(sb->value)) { + } else if ( sc_isprint(sb->value)) { + //DEBUG sc_info("2: %d %lc", sb->value, sb->value); + ins_in_line(sb->value); + ui_show_header(); +#ifdef INS_HISTORY_FILE + if (insert_history->pos == 0) { // Only if editing the new command + wchar_t * sl = get_line_from_history(insert_history, 0); + add_wchar(sl, sb->value, real_inputline_pos-1); // Insert into history + } +#endif + + } else if (sb->value == ctl('r') && get_bufsize(sb) == 2 && // C-r // FIXME ??? + (sb->pnext->value - (L'a' - 1) < 1 || sb->pnext->value > 26)) { + wchar_t cline [BUFFERSIZE]; + int i, r = get_mark(sb->pnext->value)->row; + if (r != -1) { + swprintf(cline, BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->col), r); + } else { + swprintf(cline, BUFFERSIZE, L"%s%d:", coltoa(get_mark(sb->pnext->value)->rng->tlcol), get_mark(sb->pnext->value)->rng->tlrow); + swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->rng->brcol), get_mark(sb->pnext->value)->rng->brrow); + } + for(i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]); + +#ifdef INS_HISTORY_FILE + if (insert_history->pos == 0) { // Only if editing the new command + wchar_t * sl = get_line_from_history(insert_history, 0); + wcscat(sl, cline); // Insert into history + } +#endif + ui_show_header(); + return; + } + return; +} diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_insert.h sc-im-0.8.3+ds/src/cmds/cmds_insert.h --- sc-im-0.8.2+ds/src/cmds/cmds_insert.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_insert.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_insert.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for cmds_insert.c + */ + +#include "../input.h" + +#ifdef INS_HISTORY_FILE +#include "../history.h" +extern struct history * insert_history; +#endif + +void do_insertmode(struct block * sb); diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_normal.c sc-im-0.8.3+ds/src/cmds/cmds_normal.c --- sc-im-0.8.2+ds/src/cmds/cmds_normal.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_normal.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,1219 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_normal.c + * \author Andrés Martinelli + * \date 26/05/2021 + * \brief TODO Write a tbrief file description. + */ + +#include +#include + +#include "cmds.h" +#include "cmds_edit.h" +#include "../yank.h" +#include "../marks.h" +#include "../conf.h" +#include "../tui.h" +#include "../history.h" +#include "../actions/freeze.h" +#include "../actions/hide_show.h" +#include "../actions/shift.h" +#include "../main.h" // for sig_winchg +#include "../interp.h" +#include "../utils/extra.h" +#ifdef UNDO +#include "../undo.h" +#endif + + +#include "../graph.h" +extern graphADT graph; +extern char valores; +extern int cmd_multiplier; +extern void start_visualmode(int tlrow, int tlcol, int brrow, int brcol); +extern void ins_in_line(wint_t d); +extern void openfile_under_cursor(int r, int c); + +extern wchar_t interp_line[BUFFERSIZE]; +extern struct session * session; + +#ifdef HISTORY_FILE +extern struct history * commandline_history; +#endif + +#ifdef INS_HISTORY_FILE +extern struct history * insert_history; +extern char ori_insert_edit_submode; +#endif + +/** + * \brief TODO Document do_normalmode() + * \param[in] buf + * \return none + */ +void do_normalmode(struct block * buf) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int bs = get_bufsize(buf); + struct ent * e; + + switch (buf->value) { + // FOR TEST PURPOSES + case L'A': + //; + //wchar_t t = ui_query_opt(L"show a message. q / a / d to quit", L"qad"); + break; + + case L'W': + break; + + case L'Q': + break; + + // MOVEMENT COMMANDS + case L'j': + case OKEY_DOWN: + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = forw_row(sh, 1)->row; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'k': + case OKEY_UP: + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = back_row(sh, 1)->row; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'h': + case OKEY_LEFT: + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->curcol = back_col(sh, 1)->col; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'l': + case OKEY_RIGHT: + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->curcol = forw_col(sh, 1)->col; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'0': + if (get_conf_int("numeric_zero") == 1 && get_conf_int("numeric") == 1) goto numeric; + case OKEY_HOME: + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->curcol = left_limit(sh)->col; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'$': + case OKEY_END: + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->curcol = right_limit(sh, sh->currow)->col; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'^': + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = goto_top(sh)->row; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'#': + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = goto_bottom(sh)->row; + if (sh->currow == sh->lastrow && sh->curcol == sh->lastcol) sh->currow = go_end(sh)->row; + unselect_ranges(); + ui_update(TRUE); + break; + + // Tick + case L'\'': + if (bs != 2) break; + unselect_ranges(); + struct ent_ptr * ep = tick(buf->pnext->value); + if (sh->row_hidden[ep->vp->row]) { + sc_error("Cell row is hidden"); + if (ep != NULL) free(ep); + break; + } + if (sh->col_hidden[ep->vp->col]) { + sc_error("Cell column is hidden"); + if (ep != NULL) free(ep); + break; + } + if (ep->sheet != NULL) roman->cur_sh = ep->sheet; + roman->cur_sh->lastrow = roman->cur_sh->currow; + roman->cur_sh->lastcol = roman->cur_sh->curcol; + roman->cur_sh->currow = ep->vp->row; + roman->cur_sh->curcol = ep->vp->col; + if (ep != NULL) free(ep); + ui_update(TRUE); + break; + + // CTRL j + case ctl('j'): + { + int p, c = sh->curcol, cf = sh->curcol; + if ( (p = is_range_selected()) != -1) { + struct srange * sr = get_range_by_pos(p); + c = sr->tlcol; + cf = sr->brcol; + } + auto_fit(sh, c, cf, DEFWIDTH); // auto justify columns + ui_update(TRUE); + break; + } + + // CTRL d + case ctl('d'): // set date format using current locate D_FMT format + { + #ifdef USELOCALE + #include + #include + char * loc = NULL; + char * f = NULL; + loc = setlocale(LC_TIME, ""); + if (loc != NULL) { + f = nl_langinfo(D_FMT); + } else { + sc_error("No locale set. Nothing changed"); + } + int p, r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if ( (p = is_range_selected()) != -1) { + struct srange * sr = get_range_by_pos(p); + r = sr->tlrow; + c = sr->tlcol; + rf = sr->brrow; + cf = sr->brcol; + } + if (any_locked_cells(sh, r, c, rf, cf)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } + dateformat(sh, lookat(sh, r, c), lookat(sh, rf, cf), f); + ui_update(TRUE); + break; + #else + sc_info("Build made without USELOCALE enabled"); + #endif + } + + // CTRL f + case ctl('f'): + case OKEY_PGDOWN: + { + int n = calc_mobile_rows(sh, NULL); + if (get_conf_int("half_page_scroll")) n = n / 2; + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = forw_row(sh, n)->row; + unselect_ranges(); + scroll_down(sh, n); + ui_update(TRUE); + break; + } + + // CTRL b + case ctl('b'): + case OKEY_PGUP: + { + int n = calc_mobile_rows(sh, NULL); + if (get_conf_int("half_page_scroll")) n = n / 2; + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = back_row(sh, n)->row; + unselect_ranges(); + scroll_up(sh, n); + ui_update(TRUE); + break; + } + + case L'w': + e = go_forward(sh); + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->currow = e->row; + sh->curcol = e->col; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'b': + e = go_backward(sh); + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->currow = e->row; + sh->curcol = e->col; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'H': + sh->lastrow = sh->currow; + int currow_h = vert_top(sh)->row; + sh->currow = currow_h; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'M': + sh->lastrow = sh->currow; + sh->currow = vert_middle(sh)->row; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'L': + sh->lastrow = sh->currow; + sh->currow = vert_bottom(sh)->row; + unselect_ranges(); + ui_update(TRUE); + break; + + case L'G': // goto end + e = go_end(sh); + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->currow = e->row; + sh->curcol = e->col; + unselect_ranges(); + ui_update(TRUE); + break; + + // GOTO goto + case ctl('a'): + e = go_home(sh); + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->curcol = e->col; + sh->currow = e->row; + unselect_ranges(); + sh->offscr_sc_rows = 0; + sh->offscr_sc_cols = 0; + ui_update(TRUE); + break; + + case L'g': + if (buf->pnext->value == L'0') { // g0 + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->curcol = go_bol(sh)->col; + + } else if (buf->pnext->value == L'$') { // g$ + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->curcol = go_eol(sh)->col; + + } else if (buf->pnext->value == L'f') { // gf + unselect_ranges(); + ui_update(TRUE); + ui_stop_screen(); + openfile_under_cursor(sh->currow, sh->curcol); + ui_start_screen(); + start_default_ucolors(); + set_colors_param_dict(); + + } else if (buf->pnext->value == L'g') { // gg + e = go_home(sh); + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->curcol = e->col; + sh->currow = e->row; + sh->offscr_sc_rows = 0; + sh->offscr_sc_cols = 0; + + } else if (buf->pnext->value == L'G') { // gG + e = go_end(sh); + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = e->row; + sh->curcol = e->col; + + } else if (buf->pnext->value == L'M') { // gM + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->curcol = horiz_middle(sh)->col; + + // goto last cell position + } else if (buf->pnext->value == L'l') { // gl + int newlr = sh->currow; + int newlc = sh->curcol; + sh->curcol = sh->lastcol; + sh->currow = sh->lastrow; + sh->lastrow = newlr; + sh->lastcol = newlc; + + } else if (buf->pnext->value == L't') { // gt + (void) swprintf(interp_line, BUFFERSIZE, L"nextsheet"); + send_to_interp(interp_line); + + } else if (buf->pnext->value == L'T') { // gT + (void) swprintf(interp_line, BUFFERSIZE, L"prevsheet"); + send_to_interp(interp_line); + + } else if (buf->pnext->value == L'o') { // goA4 (goto cell A4) + (void) swprintf(interp_line, BUFFERSIZE, L"goto %s", parse_cell_name(2, buf)); + send_to_interp(interp_line); + } + unselect_ranges(); + ui_update(TRUE); + break; + + // repeat last goto command - backwards + case L'N': + { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + extern struct go_save gs; + if (gs.g_sheet == sh) { + go_previous(); + } else if (gs.g_type == G_NUM) { + num_search(sh, gs.g_n, 0, 0, sh->maxrow, sh->maxcol, 0, gs.g_flow); + } else if (gs.g_type == G_STR) { + gs.g_type = G_NONE; /* Don't free the string */ + str_search(sh, gs.g_s, 0, 0, sh->maxrow, sh->maxcol, 0, gs.g_flow); + } + ui_update(TRUE); + } + break; + + // repeat last goto command + case L'n': + { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + extern struct go_save gs; + if (gs.g_sheet == sh) { + go_last(); + } else if (gs.g_type == G_NUM) { + num_search(sh, gs.g_n, 0, 0, sh->maxrow, sh->maxcol, 0, gs.g_flow); + } else if (gs.g_type == G_STR) { + gs.g_type = G_NONE; /* Don't free the string */ + str_search(sh, gs.g_s, 0, 0, sh->maxrow, sh->maxcol, 0, gs.g_flow); + } + ui_update(TRUE); + } + break; + + // END OF MOVEMENT COMMANDS + case L'/': + { + char cadena[] = ":int goto "; + int i; + for (i=0; icurrow, sh->curcol, sh->currow, sh->curcol); + break; + + // INPUT COMMANDS + case L'=': + case L'\\': + case L'<': + case L'>': + if (locked_cell(sh, sh->currow, sh->curcol)) return; + insert_edit_submode = buf->value; + chg_mode(insert_edit_submode); +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = buf->value; + add(insert_history, L""); +#endif + inputline_pos = 0; + real_inputline_pos = 0; + ui_show_header(); + break; + + // EDITION COMMANDS + // edit cell (v) + case L'e': + if (locked_cell(sh, sh->currow, sh->curcol)) return; + inputline_pos = 0; + real_inputline_pos = 0; + if (start_edit_mode(buf, 'v')) ui_show_header(); + break; + + // edit cell (s) + case L'E': + if (locked_cell(sh, sh->currow, sh->curcol)) return; + inputline_pos = 0; + real_inputline_pos = 0; + if (start_edit_mode(buf, 's')) ui_show_header(); + else { + sc_info("No string value to edit"); + chg_mode('.'); + ui_print_mode(); + ui_show_celldetails(); + } + break; + + // del current cell or range + case L'x': + del_selected_cells(sh); + ui_update(TRUE); + break; + + // format col or freeze range + case L'f': + if (bs != 2) return; + + // freeze row / column or area + if (buf->pnext->value == 'r' || buf->pnext->value == 'c' || buf->pnext->value == 'a') { + int p = is_range_selected(), r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + + if (p != -1) { // mark range + struct srange * sr = get_range_by_pos(p); + r = sr->tlrow; + c = sr->tlcol; + rf = sr->brrow; + cf = sr->brcol; + } + + if (buf->pnext->value == 'r') { + handle_freeze(sh, lookat(sh, r, c), lookat(sh, rf, cf), 1, 'r'); + sc_info("Row%s frozen", r != rf ? "s" : ""); + } else if (buf->pnext->value == 'c') { + handle_freeze(sh, lookat(sh, r, c), lookat(sh, rf, cf), 1, 'c'); + sc_info("Column%s frozen", c != cf ? "s" : ""); + } else if (buf->pnext->value == 'a') { + handle_freeze(sh, lookat(sh, r, c), lookat(sh, rf, cf), 1, 'r'); + handle_freeze(sh, lookat(sh, r, c), lookat(sh, rf, cf), 1, 'c'); + sc_info("Area frozen"); + } + ui_update(FALSE); + break; + + // decrease row height + } else if (buf->pnext->value == 'k' || buf->pnext->value == OKEY_UP) { + +#ifdef UNDO + create_undo_action(); + int fmt_ori = sh->row_format[sh->currow]; + add_undo_row_format(sh->currow, 'R', sh->row_format[sh->currow]); +#endif + swprintf(interp_line, BUFFERSIZE, L"format %d %d", sh->currow, sh->row_format[sh->currow]-1); + send_to_interp(interp_line); +#ifdef UNDO + if (sh->row_format[sh->currow] != fmt_ori) { + add_undo_row_format(sh->currow, 'A', sh->row_format[sh->currow]); + end_undo_action(); + } else dismiss_undo_item(NULL); +#endif + ui_update(TRUE); + break; + + // increase row height + } else if (buf->pnext->value == 'j' || buf->pnext->value == OKEY_DOWN) { + +#ifdef UNDO + create_undo_action(); + int fmt_ori = sh->row_format[sh->currow]; + add_undo_row_format(sh->currow, 'R', sh->row_format[sh->currow]); +#endif + swprintf(interp_line, BUFFERSIZE, L"format %d %d", sh->currow, sh->row_format[sh->currow]+1); + send_to_interp(interp_line); +#ifdef UNDO + if (sh->row_format[sh->currow] != fmt_ori) { + add_undo_row_format(sh->currow, 'A', sh->row_format[sh->currow]); + end_undo_action(); + } else dismiss_undo_item(NULL); +#endif + ui_update(TRUE); + break; + + // change in format + } else { +#ifdef UNDO + create_undo_action(); + add_undo_col_format(sh->curcol, 'R', sh->fwidth[sh->curcol], sh->precision[sh->curcol], sh->realfmt[sh->curcol]); +#endif + formatcol(sh, buf->pnext->value); +#ifdef UNDO + add_undo_col_format(sh->curcol, 'A', sh->fwidth[sh->curcol], sh->precision[sh->curcol], sh->realfmt[sh->curcol]); + end_undo_action(); +#endif + } + break; + + // mark cell or range + case L'm': + if (bs != 2) break; + int p = is_range_selected(); + if (p != -1) { // mark range + struct srange * sr = get_range_by_pos(p); + set_range_mark(buf->pnext->value, sh, sr); + } else // mark cell + set_cell_mark(buf->pnext->value, sh, sh->currow, sh->curcol); + roman->modflg++; + break; + + // copy + case L'c': + { + if (bs != 2) break; + struct mark * m = get_mark(buf->pnext->value); + if ( m == NULL) return; + + + // if m represents a range + if ( m->row == -1 && m->col == -1) { + srange * r = m->rng; + yank_area(sh, r->tlrow, r->tlcol, r->brrow, r->brcol, 'a', cmd_multiplier); + if (paste_yanked_ents(sh, 0, 'c') == -1) { + sc_error("Locked cells encountered. Nothing changed"); + break; + } + + // if m represents just one cell + } else { + struct mark * m = get_mark(buf->pnext->value); + struct ent * p = lookat(sh, m->row, m->col); + struct ent * n; + int c1; + +#ifdef UNDO + create_undo_action(); +#endif + for (c1 = sh->curcol; cmd_multiplier-- && cmd_multiplier > -1 && c1 < sh->maxcols; c1++) { + if ((n = * ATBL(sh, sh->tbl, sh->currow, c1))) { + if (n->flags & is_locked) + continue; + if (! p) { + clearent(n); + continue; + } + } else { + if (! p) break; + n = lookat(sh, sh->currow, c1); + } +#ifdef UNDO + // added for #244 - 22/03/2018 + ents_that_depends_on_range(sh, n->row, n->col, n->row, n->col); + copy_to_undostruct(sh, sh->currow, c1, sh->currow, c1, UNDO_DEL, HANDLE_DEPS, NULL); +#endif + copyent(n, sh, p, sh->currow - get_mark(buf->pnext->value)->row, c1 - get_mark(buf->pnext->value)->col, 0, 0, sh->maxrow, sh->maxcol, 0); + + n->row += sh->currow - get_mark(buf->pnext->value)->row; + n->col += c1 - get_mark(buf->pnext->value)->col; + + n->flags |= is_changed; + if (n->expr) EvalJustOneVertex(sh, n, 1); + +#ifdef UNDO + copy_to_undostruct(sh, sh->currow, c1, sh->currow, c1, UNDO_ADD, HANDLE_DEPS, NULL); +#endif + } +#ifdef UNDO + extern struct ent_ptr * deps; + if (deps != NULL) free(deps); + deps = NULL; + end_undo_action(); +#endif + } + + ui_update(TRUE); + break; + } + + // range lock / unlock / valueize + case L'r': + { + int p, r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if ( (p = is_range_selected()) != -1) { + struct srange * sr = get_range_by_pos(p); + r = sr->tlrow; + c = sr->tlcol; + rf = sr->brrow; + cf = sr->brcol; + } + if (buf->pnext->value == L'l') { + lock_cells(sh, lookat(sh, r, c), lookat(sh, rf, cf)); + } else if (buf->pnext->value == L'u') { // watch out if you do C-r and u too quickly ! + unlock_cells(sh, lookat(sh, r, c), lookat(sh, rf, cf)); + } else if (buf->pnext->value == L'v') { + valueize_area(sh, r, c, rf, cf); + } + ui_update(TRUE); + break; + } + + // create range with two marks + case L'R': + if (bs == 3) { + create_range(buf->pnext->value, buf->pnext->pnext->value, NULL, NULL); + ui_update(TRUE); + } + break; + + // Zr Zc - Zap col or row - Show col or row - Sr Sc + case L'Z': + case L'S': + { + int rs, r = sh->currow, c = sh->curcol, arg = cmd_multiplier; + struct srange * sr; + if ( (rs = is_range_selected()) != -1) { + sr = get_range_by_pos(rs); + cmd_multiplier = 1; + r = sr->tlrow; + c = sr->tlcol; + arg = buf->pnext->value == L'r' ? sr->brrow - sr->tlrow + 1 : sr->brcol - sr->tlcol + 1; + } + if (buf->value == L'Z' && buf->pnext->value == L'r') { + hide_row(r, arg); + } else if (buf->value == L'Z' && buf->pnext->value == L'c') { + hide_col(c, arg); + } else if (buf->value == L'S' && buf->pnext->value == L'r') { + show_row(r, arg); + } else if (buf->value == L'S' && buf->pnext->value == L'c') { + show_col(c, arg); + } + cmd_multiplier = 0; + ui_update(TRUE); + break; + } + + // shift range or cell + case L's': + { + int p, r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if ( (p = is_range_selected()) != -1) { + struct srange * sr = get_range_by_pos(p); + r = sr->tlrow; + c = sr->tlcol; + rf = sr->brrow; + cf = sr->brcol; + } + shift(sh, r, c, rf, cf, buf->pnext->value); + unselect_ranges(); + rebuild_graph(); + ui_update(TRUE); + break; + } + + // delete row or column, or selected cell or range + case L'd': + { + if (bs != 2) return; + int ic = cmd_multiplier; // orig + + // deleterow + if (buf->pnext->value == L'r') { + deleterow(sh, sh->currow, ic); + if (cmd_multiplier > 1) cmd_multiplier = 0; + + // deletecol + } else if (buf->pnext->value == L'c') { + deletecol(sh, sh->curcol, ic); + if (cmd_multiplier > 1) cmd_multiplier = 0; + + } else if (buf->pnext->value == L'd') { + del_selected_cells(sh); + } + + rebuild_graph(); + ui_update(TRUE); + break; + } + + // insert row or column + case L'i': + { + if (bs != 2) return; +#ifdef UNDO + create_undo_action(); +#endif + + if (buf->pnext->value == L'r') { +#ifdef UNDO + save_undo_range_shift(1, 0, sh->currow, 0, sh->currow, sh->maxcol); +#endif + fix_marks(sh, 1, 0, sh->currow, sh->maxrow, 0, sh->maxcol); + insert_row(sh, 0); +#ifdef UNDO + add_undo_row_format(sh->currow, 'A', sh->row_format[sh->currow]); +#endif + + } else if (buf->pnext->value == L'c') { +#ifdef UNDO + save_undo_range_shift(0, 1, 0, sh->curcol, sh->maxrow, sh->curcol); +#endif + fix_marks(sh, 0, 1, 0, sh->maxrow, sh->curcol, sh->maxcol); + insert_col(sh, 0); +#ifdef UNDO + add_undo_col_format(sh->curcol, 'A', sh->fwidth[sh->curcol], sh->precision[sh->curcol], sh->realfmt[sh->curcol]); +#endif + } +#ifdef UNDO + end_undo_action(); +#endif + rebuild_graph(); + ui_update(TRUE); + break; + } + + // open row or column + case L'o': + { + if (bs != 2) return; +#ifdef UNDO + create_undo_action(); +#endif + if (buf->pnext->value == L'r') { +#ifdef UNDO + save_undo_range_shift(1, 0, sh->currow+1, 0, sh->currow+1, sh->maxcol); +#endif + fix_marks(sh, 1, 0, sh->currow+1, sh->maxrow, 0, sh->maxcol); + insert_row(sh, 1); +#ifdef UNDO + add_undo_row_format(sh->currow, 'A', sh->row_format[sh->currow]); +#endif + + } else if (buf->pnext->value == L'c') { +#ifdef UNDO + save_undo_range_shift(0, 1, 0, sh->curcol+1, sh->maxrow, sh->curcol+1); +#endif + fix_marks(sh, 0, 1, 0, sh->maxrow, sh->curcol+1, sh->maxcol); + insert_col(sh, 1); +#ifdef UNDO + add_undo_col_format(sh->curcol, 'A', sh->fwidth[sh->curcol], sh->precision[sh->curcol], sh->realfmt[sh->curcol]); +#endif + } +#ifdef UNDO + end_undo_action(); +#endif + rebuild_graph(); + ui_update(TRUE); + break; + } + + case L'y': + // yank row + if ( bs == 2 && buf->pnext->value == L'r') { + yank_area(sh, sh->currow, 0, sh->currow + cmd_multiplier - 1, sh->maxcol, 'r', cmd_multiplier); + if (cmd_multiplier > 1) cmd_multiplier = 0; + + // yank col + } else if ( bs == 2 && buf->pnext->value == L'c') { + yank_area(sh, 0, sh->curcol, sh->maxrow, sh->curcol + cmd_multiplier - 1, 'c', cmd_multiplier); + if (cmd_multiplier > 1) cmd_multiplier = 0; + + // yank cell + } else if ( bs == 2 && buf->pnext->value == L'y' && is_range_selected() == -1) { + yank_area(sh, sh->currow, sh->curcol, sh->currow, sh->curcol, 'e', cmd_multiplier); + + // yank range + } else if ( bs == 1 && is_range_selected() != -1) { + srange * r = get_selected_range(); + yank_area(sh, r->tlrow, r->tlcol, r->brrow, r->brcol, 'a', cmd_multiplier); + } + break; + + // paste cell below or left + case L'p': + if (paste_yanked_ents(sh, 0, 'a') == -1) { + sc_error("Locked cells encountered. Nothing changed"); + break; + } + ui_update(TRUE); + break; + + case L'P': + case L'T': + if (bs != 2) break; + if (buf->pnext->value == L'v' || buf->pnext->value == L'f' || buf->pnext->value == L'c') { + int res = buf->value == L'P' ? paste_yanked_ents(sh, 0, buf->pnext->value) : paste_yanked_ents(sh, 1, buf->pnext->value); // paste cell above or right + if (res == -1) { + sc_error("Locked cells encountered. Nothing changed"); + break; + } + ui_update(TRUE); + } + break; + + // paste cell above or right + case L't': + if (paste_yanked_ents(sh, 1, 'a') == -1) { + sc_error("Locked cells encountered. Nothing changed"); + break; + } + ui_update(TRUE); + break; + + // select inner range - Vir + case L'V': + if (buf->value == L'V' && bs == 3 && + buf->pnext->value == L'i' && buf->pnext->pnext->value == L'r') { + int tlrow = sh->currow; + int brrow = sh->currow; + int tlcol = sh->curcol; + int brcol = sh->curcol; + int * tlr = &tlrow; + int * brr = &brrow; + int * tlc = &tlcol; + int * brc = &brcol; + select_inner_range(sh, tlr, tlc, brr, brc); + start_visualmode(*tlr, *tlc, *brr, *brc); + } + break; + + // autofit + case L'a': + if ( bs != 2 ) break; + + if (buf->pnext->value == L'a') { + int p, r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + if ( (p = is_range_selected()) != -1) { + struct srange * sr = get_range_by_pos(p); + r = sr->tlrow; + c = sr->tlcol; + rf = sr->brrow; + cf = sr->brcol; + } + if (any_locked_cells(sh, r, c, rf, cf)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } + wchar_t cline [BUFFERSIZE]; + swprintf(cline, BUFFERSIZE, L"autofit %s:", coltoa(c)); + swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s", coltoa(cf)); + send_to_interp(cline); + ui_update(TRUE); + } + break; + + // scroll + case L'z': + if ( bs != 2 ) break; + int scroll = 0; + + switch (buf->pnext->value) { + case L'l': + scroll_right(sh, 1); + break; + + case L'h': + scroll_left(sh, 1); + break; + + case L'H': + scroll = calc_mobile_cols(sh, NULL); + if (get_conf_int("half_page_scroll")) scroll /= 2; + scroll_left(sh, scroll); + break; + + case L'L': + scroll = calc_mobile_cols(sh, NULL); + if (get_conf_int("half_page_scroll")) scroll /= 2; + scroll_right(sh, scroll); + break; + + case L'm': + ; + int i = 0, c = 0, ancho = sh->rescol; + sh->offscr_sc_cols = 0; + for (i = 0; i < sh->curcol; i++) { + for (c = i; c < sh->curcol; c++) { + if (! sh->col_hidden[c]) ancho += sh->fwidth[c]; + if (ancho >= SC_DISPLAY_COLS/2) { + ancho = sh->rescol; + break; + } + } + if (c == sh->curcol) break; + } + sh->offscr_sc_cols = i; + break; + + case L't': + case L'b': + case L'z': + case L'.': + { + int i = 0, r = sh->offscr_sc_rows-1; + + if (buf->pnext->value == L't') { + while (i < SC_DISPLAY_ROWS && r < sh->currow) { + r++; + if (sh->row_frozen[r]) continue; + i++; + } + scroll_down(sh, --i); + + } else if (buf->pnext->value == L'b') { + int hidden = 0; + while (i < SC_DISPLAY_ROWS) { + r++; + if (sh->row_hidden[r]) { hidden++; continue; } + else if (r < sh->offscr_sc_rows && ! (sh->row_frozen[r])) continue; + else if (sh->row_frozen[r]) continue; + i++; + } + scroll_up(sh, r-sh->currow-hidden); + + } else if (buf->pnext->value == L'z' || buf->pnext->value == L'.') { + while (i < SC_DISPLAY_ROWS && r <= sh->currow) { + r++; + if (sh->row_frozen[r]) continue; + i++; + } + int top = --i; + i = 0, r = sh->offscr_sc_rows-1; + while (i < SC_DISPLAY_ROWS) { + r++; + if (r < sh->offscr_sc_rows && ! (sh->row_frozen[r])) continue; + i++; + } + int bottom = r-sh->currow; + int scroll = (-top + bottom)/2; + if (scroll < 0) + scroll_down(sh, -scroll); + else if (scroll > 0) + scroll_up(sh, scroll); + } + break; + } + } + ui_update(TRUE); + break; + + // scroll up a line + case ctl('y'): + scroll_up(sh, 1); + ui_update(TRUE); + break; + + // scroll down a line + case ctl('e'): + scroll_down(sh, 1); + ui_update(TRUE); + break; + + // undo + case L'u': + #ifdef UNDO + do_undo(); + ui_update(TRUE); + #else + sc_error("Build was done without UNDO support"); + #endif + break; + + // redo + case ctl('r'): + #ifdef UNDO + do_redo(); + ui_update(TRUE); + #else + sc_error("Build was done without UNDO support"); + #endif + break; + + case L'{': // left align + case L'}': // right align + case L'|': // center align + { + int p, r = sh->currow, c = sh->curcol, rf = sh->currow, cf = sh->curcol; + struct srange * sr; + if ( (p = is_range_selected()) != -1) { + sr = get_range_by_pos(p); + r = sr->tlrow; + c = sr->tlcol; + rf = sr->brrow; + cf = sr->brcol; + } + if (any_locked_cells(sh, r, c, rf, cf)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } +#ifdef UNDO + create_undo_action(); +#endif + if (buf->value == L'{') swprintf(interp_line, BUFFERSIZE, L"leftjustify %s", v_name(r, c)); + else if (buf->value == L'}') swprintf(interp_line, BUFFERSIZE, L"rightjustify %s", v_name(r, c)); + else if (buf->value == L'|') swprintf(interp_line, BUFFERSIZE, L"center %s", v_name(r, c)); + if (p != -1) swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L":%s", v_name(rf, cf)); +#ifdef UNDO + copy_to_undostruct(sh, r, c, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); +#endif + send_to_interp(interp_line); +#ifdef UNDO + copy_to_undostruct(sh, r, c, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); +#endif + ui_update(TRUE); + break; + } + + case ctl('l'): + sig_winchg(); + break; + + case L'@': + EvalAll(); + ui_update(TRUE); + break; + + // increase or decrease numeric value of cell or range + case L'-': + case L'+': + { + int r, c, tlrow = sh->currow, tlcol = sh->curcol, brrow = sh->currow, brcol = sh->curcol; + if ( is_range_selected() != -1 ) { + struct srange * sr = get_selected_range(); + tlrow = sr->tlrow; + tlcol = sr->tlcol; + brrow = sr->brrow; + brcol = sr->brcol; + } + if (any_locked_cells(sh, tlrow, tlcol, brrow, brcol)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } + if (get_conf_int("numeric") == 1) goto numeric; + struct ent * p; +#ifdef UNDO + create_undo_action(); + copy_to_undostruct(sh, tlrow, tlcol, brrow, brcol, UNDO_DEL, IGNORE_DEPS, NULL); +#endif + int arg = cmd_multiplier; + int mf = roman->modflg; // keep original modflg + for (r = tlrow; r <= brrow; r++) { + for (c = tlcol; c <= brcol; c++) { + p = *ATBL(sh, sh->tbl, r, c); + if ( ! p ) { + continue; + } else if (p->expr && !(p->flags & is_strexpr)) { + //sc_error("Can't increment / decrement a formula"); + continue; + } else if (p->flags & is_valid) { + p->v += buf->value == L'+' ? (double) arg : - 1 * (double) arg; + if (mf == roman->modflg) roman->modflg++; // increase just one time + } + } + } +#ifdef UNDO + copy_to_undostruct(sh, tlrow, tlcol, brrow, brcol, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); +#endif + if (get_conf_int("autocalc")) EvalRange(sh, tlrow, tlcol, brrow, brcol); + cmd_multiplier = 0; + ui_update(TRUE); + } + break; + + // input of numbers + default: + numeric: + if ( (isdigit(buf->value) || buf->value == L'-' || buf->value == L'+' || + ( buf->value == L'.' && get_conf_int("numeric_decimal") )) && + get_conf_int("numeric") ) { + if (locked_cell(sh, sh->currow, sh->curcol)) return; + insert_edit_submode='='; + chg_mode(insert_edit_submode); +#ifdef INS_HISTORY_FILE + ori_insert_edit_submode = buf->value; + add(insert_history, L""); +#endif + inputline_pos = 0; + real_inputline_pos = 0; + ins_in_line(buf->value); + ui_show_header(); + } + } + return; +} diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_normal.h sc-im-0.8.3+ds/src/cmds/cmds_normal.h --- sc-im-0.8.2+ds/src/cmds/cmds_normal.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_normal.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_normal.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for cmds_normal.c + */ + +#include "../input.h" +extern int shall_quit; + +void do_normalmode (struct block * buf); + +extern struct history * commandline_history; diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_visual.c sc-im-0.8.3+ds/src/cmds/cmds_visual.c --- sc-im-0.8.2+ds/src/cmds/cmds_visual.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_visual.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,602 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_visuals.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include + +#include "cmds.h" +#include "../utils/string.h" +#include "../tui.h" +#include "../buffer.h" +#include "../marks.h" +#include "../macros.h" +#include "../conf.h" +#include "../actions/hide_show.h" +#include "../actions/shift.h" +#include "../yank.h" +#include "../actions/freeze.h" +#include "../history.h" +#include "../interp.h" +#ifdef UNDO +#include "../undo.h" +#endif + +extern int offscr_sc_rows, offscr_sc_cols; +extern unsigned int curmode; +extern int cmd_multiplier; +extern struct history * commandline_history; +extern struct session * session; + +char visual_submode = '0'; +srange * r; // SELECTED RANGE! +int moving = FALSE; + +/** + * \brief TODO Document start_visualmode() + * + * \param[in] tlrow + * \param[in] tlcol + * \param[in] brrow + * \param[in] brcol + * + * \return none + */ + +void start_visualmode(int tlrow, int tlcol, int brrow, int brcol) { + unselect_ranges(); + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + + struct srange * sr = get_range_by_marks('\t', '\t'); // visual mode selected range + if (sr != NULL) del_ranges_by_mark('\t'); + + r = (srange *) malloc (sizeof(srange)); + r->tlrow = tlrow; + r->tlcol = tlcol; + r->brrow = brrow; + r->brcol = brcol; + r->orig_row = sh->currow; // original row before starting selection + r->orig_col = sh->curcol; // original col before starting selection + r->startup_row = sh->currow; // original row position before entering visual mode + r->startup_col = sh->curcol; // original col position before entering visual mode + r->marks[0] = '\t'; + r->marks[1] = '\t'; + r->selected = 1; + r->pnext = NULL; + + // add visual selected range at start of list + if (ranges == NULL) ranges = r; + else { + r->pnext = ranges; + ranges = r; + } + + if (visual_submode == '0') { // Started visual mode with 'v' command + ui_update(TRUE); + moving = FALSE; + } else { // Started visual mode with 'C-v' command + ui_update(TRUE); + moving = TRUE; + } + return; +} + +/** + * \brief TODO Document exit_visualmode() + * + * \return none + */ + +void exit_visualmode() { + struct roman * roman = session->cur_doc; + moving = FALSE; + visual_submode = '0'; + r->selected = 0; + roman->cur_sh->currow = r->startup_row; + roman->cur_sh->curcol = r->startup_col; + del_ranges_by_mark('\t'); + return; +} + +/** + * \brief TODO Document do_visualmode() + * + * \param[in] buf + * + * \return none + */ + +void do_visualmode(struct block * buf) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + + // we are moving (previous to a 'C-o' keypress) + if (moving == TRUE) { + switch (buf->value) { + case L'j': + case OKEY_DOWN: + sh->currow = forw_row(sh, 1)->row; + break; + + case L'k': + case OKEY_UP: + sh->currow = back_row(sh, 1)->row; + break; + + case L'h': + case OKEY_LEFT: + sh->curcol = back_col(sh, 1)->col; + break; + + case L'l': + case OKEY_RIGHT: + sh->curcol = forw_col(sh, 1)->col; + break; + + case ctl('o'): + moving = FALSE; + r->orig_row = sh->currow; + r->orig_col = sh->curcol; + break; + + case OKEY_ENTER: + sc_info("Press to begin selection or key to exit VISUAL MODE"); + return; + + } + r->tlrow = sh->currow; + r->tlcol = sh->curcol; + r->brrow = sh->currow; + r->brcol = sh->curcol; + + ui_update(FALSE); + return; + } + + // started visual mode with 'C-v' + // ENTER or 'C-k' : Confirm selection + // 'C-k' only works if started visualmode with 'C-v' + if ((buf->value == OKEY_ENTER || buf->value == ctl('k')) && visual_submode != '0') { + wchar_t cline [BUFFERSIZE]; + swprintf(cline, BUFFERSIZE, L"%ls%d", coltoa(r->tlcol), r->tlrow); + if (r->tlrow != r->brrow || r->tlcol != r->brcol) + swprintf(cline + wcslen(cline), BUFFERSIZE, L":%ls%d", coltoa(r->brcol), r->brrow); + swprintf(inputline + wcslen(inputline), BUFFERSIZE, L"%ls", cline); + + real_inputline_pos += wcslen(cline); + inputline_pos = wcswidth(inputline, real_inputline_pos); + + char c = visual_submode; + exit_visualmode(); + chg_mode(c); + + ui_show_header(); + return; + + // moving to TRUE + //} else if (buf->value == ctl('m')) { + // moving = TRUE; + + // MOVEMENT COMMANDS + // UP - ctl(b) + } else if (buf->value == OKEY_UP || buf->value == L'k' || buf->value == ctl('b') ) { + int n, i; + if (buf->value == ctl('b')) { + n = SC_DISPLAY_ROWS; + if (get_conf_value("half_page_scroll")) n = n / 2; + } else n = 1; + + for (i=0; i < n; i++) + if (r->orig_row < r->brrow && r->tlrow < r->brrow) { + while (sh->row_hidden[-- r->brrow]); + sh->currow = r->brrow; + } else if (r->tlrow <= r->brrow && r->tlrow-1 >= 0) { + int newrow = r->tlrow; + while (newrow > 0 && sh->row_hidden[-- newrow]); + if (! sh->row_hidden[newrow]) { + sh->currow = r->tlrow = newrow; + } + } + + // DOWN - ctl('f') + } else if (buf->value == OKEY_DOWN || buf->value == L'j' || buf->value == ctl('f')) { + int n, i; + if (buf->value == ctl('f')) { + n = SC_DISPLAY_ROWS; + if (get_conf_value("half_page_scroll")) n = n / 2; + } else n = 1; + + for (i=0; i < n; i++) + if (r->orig_row <= r->tlrow && r->tlrow <= r->brrow) { + while (r->brrow+1 < sh->maxrows && sh->row_hidden[++ r->brrow]); + sh->currow = r->brrow; + } else if (r->tlrow < r->brrow) { + while (sh->row_hidden[++ r->tlrow]); + sh->currow = r->tlrow; + } + + // LEFT + } else if (buf->value == OKEY_LEFT || buf->value == L'h') { + if (r->orig_col < r->brcol && r->tlcol < r->brcol) { + while (sh->col_hidden[-- r->brcol]); + sh->curcol = r->brcol; + } else if (r->tlcol <= r->brcol && r->tlcol-1 >= 0) { + while (sh->col_hidden[-- r->tlcol]); + sh->curcol = r->tlcol; + } + + // RIGHT + } else if (buf->value == OKEY_RIGHT || buf->value == L'l') { + if (r->orig_col <= r->tlcol && r->tlcol <= r->brcol && r->brcol+2 < sh->maxcols) { + while (sh->col_hidden[++ r->brcol]); + sh->curcol = r->brcol; + } else if (r->tlcol <= r->brcol) { + while (sh->col_hidden[++ r->tlcol]); + sh->curcol = r->tlcol; + } + + // 0 + } else if (buf->value == L'0') { + r->brcol = r->tlcol; + r->tlcol = left_limit(sh)->col; + sh->curcol = r->tlcol; + + // $ + } else if (buf->value == L'$') { + int s = right_limit(sh, sh->currow)->col; + r->tlcol = r->brcol; + r->brcol = r->brcol > s ? r->brcol : s; + sh->curcol = r->brcol; + + // ^ + } else if (buf->value == L'^') { + r->brrow = r->tlrow; + r->tlrow = goto_top(sh)->row; + sh->currow = r->tlrow; + + // # + } else if (buf->value == L'#') { + int s = goto_bottom(sh)->row; + if (s == r->brrow) s = go_end(sh)->row; + //r->tlrow = r->brrow; + r->brrow = r->brrow > s ? r->brrow : s; + //r->brrow = s; + sh->currow = r->brrow; + + // ctl(a) + } else if (buf->value == ctl('a')) { + if (r->tlrow == 0 && r->tlcol == 0) return; + struct ent * e = go_home(sh); + r->tlrow = e->row; + r->tlcol = e->col; + r->brrow = r->orig_row; + r->brcol = r->orig_col; + sh->currow = r->tlrow; + sh->curcol = r->tlcol; + + // G + } else if (buf->value == L'G') { + struct ent * e = go_end(sh); + r->tlrow = r->orig_row; + r->tlcol = r->orig_col; + r->brrow = e->row; + r->brcol = e->col; + sh->currow = r->tlrow; + sh->curcol = r->tlcol; + + // ' + } else if (buf->value == L'\'') { + // if we receive a mark of a range, just return. + if (get_mark(buf->pnext->value)->row == -1) { + sc_error("That is a mark of a range. Returning."); + return; + } + + struct ent_ptr * ep = tick(buf->pnext->value); + if (ep == NULL) { + sc_error("No mark. Returning."); + return; + } else if (ep->sheet != NULL && ep->sheet != roman->cur_sh) { + sc_error("Cell marked is on other sheet. Dismissing."); + if (ep != NULL) free(ep); + return; + } + + if (sh->row_hidden[ep->vp->row]) { + sc_error("Cell row is hidden"); + if (ep != NULL) free(ep); + return; + } else if (sh->col_hidden[ep->vp->col]) { + sc_error("Cell column is hidden"); + if (ep != NULL) free(ep); + return; + } + r->tlrow = r->tlrow < ep->vp->row ? r->tlrow : ep->vp->row; + r->tlcol = r->tlcol < ep->vp->col ? r->tlcol : ep->vp->col; + r->brrow = r->brrow > ep->vp->row ? r->brrow : ep->vp->row; + r->brcol = r->brcol > ep->vp->col ? r->brcol : ep->vp->col; + if (ep != NULL) free(ep); + + // w + } else if (buf->value == L'w') { + struct ent * e = go_forward(sh); + if (e->col > r->orig_col) { + r->brcol = e->col; + r->tlcol = r->orig_col; + } else { + r->tlcol = e->col; + r->brcol = r->orig_col; + } + r->brrow = e->row; + r->tlrow = r->orig_row; + sh->curcol = e->col; + sh->currow = e->row; + + // b + } else if (buf->value == L'b') { + struct ent * e = go_backward(sh); + if (e->col <= r->orig_col) { + r->tlcol = e->col; + r->brcol = r->orig_col; + } else { + r->brcol = e->col; + r->tlcol = r->orig_col; + } + r->tlrow = e->row; + r->brrow = r->orig_row; + sh->curcol = e->col; + sh->currow = e->row; + + // H + } else if (buf->value == L'H') { + r->brrow = r->tlrow; + r->tlrow = vert_top(sh)->row; + sh->currow = r->tlrow; + + // M + } else if (buf->value == L'M') { + r->tlrow = r->orig_row; + int rm = vert_middle(sh)->row; + if (r->orig_row < rm) r->brrow = rm; + else r->tlrow = rm; + sh->currow = r->tlrow; + + // L + } else if (buf->value == L'L') { + r->tlrow = r->orig_row; + r->brrow = vert_bottom(sh)->row; + sh->currow = r->brrow; + + // mark a range + } else if (buf->value == L'm' && get_bufsize(buf) == 2) { + del_ranges_by_mark(buf->pnext->value); + srange * rn = create_range('\0', '\0', lookat(sh, r->tlrow, r->tlcol), lookat(sh, r->brrow, r->brcol)); + set_range_mark(buf->pnext->value, sh, rn); + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // auto_fit + } else if (buf->value == ctl('j')) { + auto_fit(sh, r->tlcol, r->brcol, DEFWIDTH); // auto justify columns + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // datefmt with locale D_FMT format + } else if (buf->value == ctl('d')) { + #ifdef USELOCALE + #include + #include + char * loc = NULL; + char * f = NULL; + loc = setlocale(LC_TIME, ""); + if (loc != NULL) { + f = nl_langinfo(D_FMT); + } else { + sc_error("No locale set. Nothing changed"); + } + if (any_locked_cells(sh, r->tlrow, r->tlcol, r->brrow, r->brcol)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } + dateformat(sh, lookat(sh, r->tlrow, r->tlcol), lookat(sh, r->brrow, r->brcol), f); + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + #else + sc_info("Build made without USELOCALE enabled"); + #endif + + // EDITION COMMANDS + // yank + } else if (buf->value == 'y') { + yank_area(sh, r->tlrow, r->tlcol, r->brrow, r->brcol, 'a', 1); + + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // 'p' normal paste + // 'P' Works like 'p' except that all cell references are adjusted. + } else if (buf->value == 'P' || buf->value == 'p') { + struct ent_ptr * yl = get_yanklist(); + int type_paste = (buf->value == 'P') ? 'c' : 'a' ; + int row, col; + if( yl != NULL) { + int colsize = -(yl->vp->col); //calculate colsize for correct repeating if paste area is bigger than yank area + int rowsize = -(yl->vp->row); //calculate rowsize + while (yl->next != NULL) { yl = yl->next; } //get the last one to calculated size of yank_area + colsize += (yl->vp->col +1); //calculate size + rowsize += (yl->vp->row +1); //calculate size +#ifdef DEBUG + char str[20]; + sprintf(str, "RowSize:%d ColSize:%d Type Paste:%d", rowsize, colsize, type_paste); +#endif + for (row = r->tlrow; row <= r->brrow; row += rowsize) { + for (col = r->tlcol; col <= r->brcol; col += colsize) { + sh->currow = row; + sh->curcol = col; + paste_yanked_ents(sh, 0, type_paste); + } + } + exit_visualmode(); + chg_mode('.'); + ui_show_header(); +#ifdef DEBUG + sc_info(str); +#endif +#ifndef DEBUG + sc_info("Nice Pasting :-)"); +#endif + } + else{ + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + sc_info("Nothing to Paste"); + } + + // left / right / center align + } else if (buf->value == L'{' || buf->value == L'}' || buf->value == L'|') { + if (any_locked_cells(sh, r->tlrow, r->tlcol, r->brrow, r->brcol)) { + sc_error("Locked cells encountered. Nothing changed"); + return; + } + extern wchar_t interp_line[BUFFERSIZE]; + if (buf->value == L'{') swprintf(interp_line, BUFFERSIZE, L"leftjustify %s", v_name(r->tlrow, r->tlcol)); + else if (buf->value == L'}') swprintf(interp_line, BUFFERSIZE, L"rightjustify %s", v_name(r->tlrow, r->tlcol)); + else if (buf->value == L'|') swprintf(interp_line, BUFFERSIZE, L"center %s", v_name(r->tlrow, r->tlcol)); + swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L":%s", v_name(r->brrow, r->brcol)); +#ifdef UNDO + create_undo_action(); + copy_to_undostruct(sh, r->tlrow, r->tlcol, r->brrow, r->brcol, UNDO_DEL, IGNORE_DEPS, NULL); +#endif + send_to_interp(interp_line); +#ifdef UNDO + copy_to_undostruct(sh, r->tlrow, r->tlcol, r->brrow, r->brcol, UNDO_ADD, IGNORE_DEPS, NULL); + end_undo_action(); +#endif + cmd_multiplier = 0; + + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // freeze a range + } else if (buf->value == L'f') { + handle_freeze(sh, lookat(sh, r->tlrow, r->tlcol), lookat(sh, r->brrow, r->brcol), 1, 'r'); + handle_freeze(sh, lookat(sh, r->tlrow, r->tlcol), lookat(sh, r->brrow, r->brcol), 1, 'c'); + + cmd_multiplier = 0; + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + sc_info("Area frozen"); + + // range lock / unlock // valueize + } else if ( buf->value == L'r' && (buf->pnext->value == L'l' || buf->pnext->value == L'u' || + buf->pnext->value == L'v' )) { + if (buf->pnext->value == L'l') { + lock_cells(sh, lookat(sh, r->tlrow, r->tlcol), lookat(sh, r->brrow, r->brcol)); + } else if (buf->pnext->value == L'u') { + unlock_cells(sh, lookat(sh, r->tlrow, r->tlcol), lookat(sh, r->brrow, r->brcol)); + } else if (buf->pnext->value == L'v') { + valueize_area(sh, r->tlrow, r->tlcol, r->brrow, r->brcol); + } + cmd_multiplier = 0; + + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // Zr Zc - Zap col or row + } else if ( (buf->value == L'Z' || buf->value == L'S') && (buf->pnext->value == L'c' || buf->pnext->value == L'r')) { + int arg = buf->pnext->value == L'r' ? r->brrow - r->tlrow + 1 : r->brcol - r->tlcol + 1; + if (buf->value == L'Z' && buf->pnext->value == L'r') { + hide_row(r->tlrow, arg); + } else if (buf->value == L'Z' && buf->pnext->value == L'c') { + hide_col(r->tlcol, arg); + } else if (buf->value == L'S' && buf->pnext->value == L'r') { + show_row(r->tlrow, arg); + } else if (buf->value == L'S' && buf->pnext->value == L'c') { + show_col(r->tlcol, arg); + } + cmd_multiplier = 0; + + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // delete selected range + } else if (buf->value == L'x' || (buf->value == L'd' && buf->pnext->value == L'd') ) { + del_selected_cells(sh); + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + // shift range + } else if (buf->value == L's') { + shift(sh, r->tlrow, r->tlcol, r->brrow, r->brcol, buf->pnext->value); + exit_visualmode(); + chg_mode('.'); + ui_show_header(); + + } else if (buf->value == L':') { + chg_mode(':'); + ui_show_header(); +#ifdef HISTORY_FILE + add(commandline_history, L""); +#endif + ui_handle_cursor(); + inputline_pos = 0; + real_inputline_pos = 0; + return; + } + + if (visual_submode == '0') + ui_update(TRUE); + else { + ui_update(FALSE); + } +} diff -Nru sc-im-0.8.2+ds/src/cmds/cmds_visual.h sc-im-0.8.3+ds/src/cmds/cmds_visual.h --- sc-im-0.8.2+ds/src/cmds/cmds_visual.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/cmds_visual.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file cmds_visual.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for cmds_visual.c + */ + +void start_visualmode(int tlrow, int tlcol, int brrow, int brcol); +void exit_visualmode(); +void do_visualmode(struct block * sb); +extern char visual_submode; diff -Nru sc-im-0.8.2+ds/src/cmds/tags sc-im-0.8.3+ds/src/cmds/tags --- sc-im-0.8.2+ds/src/cmds/tags 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds/tags 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,109 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ +!_TAG_OUTPUT_FILESEP slash /slash or backslash/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/ +!_TAG_PROC_CWD /home/mongo/scim/src/cmds/ // +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 5.9.0 /2b88b80ac/ +any_locked_cells cmds.c /^int any_locked_cells(struct sheet * sh, int r1, int c1, int r2, int c2) {$/;" f typeref:typename:int +auto_fit cmds.c /^void auto_fit(struct sheet * sh, int ci, int cf, int min) {$/;" f typeref:typename:void +back_col cmds.c /^struct ent * back_col(struct sheet * sh, int arg) {$/;" f typeref:struct:ent * +back_row cmds.c /^struct ent * back_row(struct sheet * sh, int arg) {$/;" f typeref:struct:ent * +back_word cmds_edit.c /^int back_word(int big_word) {$/;" f typeref:typename:int +calc_mobile_cols cmds.c /^int calc_mobile_cols(struct sheet * sh, int *last_p) {$/;" f typeref:typename:int +calc_mobile_rows cmds.c /^int calc_mobile_rows(struct sheet * sh, int *last_p) {$/;" f typeref:typename:int +center cmds.c /^void center(struct sheet * sh, int sr, int sc, int er, int ec) {$/;" f typeref:typename:void +chg_mode cmds.c /^void chg_mode(char strcmd){$/;" f typeref:typename:void +cleanent cmds.c /^void cleanent(struct ent * p) {$/;" f typeref:typename:void +clearent cmds.c /^void clearent(struct ent * v) {$/;" f typeref:typename:void +convert_string_to_number cmds.c /^int convert_string_to_number(int r0, int c0, int rn, int cn) {$/;" f typeref:typename:int +copye cmds.c /^struct enode * copye(struct enode *e, struct sheet * sh, int Rdelta, int Cdelta, int r1, int c1,/;" f typeref:struct:enode * +copyent cmds.c /^void copyent(struct ent * n, struct sheet * sh_p, struct ent * p, int dr, int dc, int r1, int c1/;" f typeref:typename:void +deletecol cmds.c /^void deletecol(struct sheet * sh, int col, int mult) {$/;" f typeref:typename:void +deleterow cmds.c /^void deleterow(struct sheet * sh, int row, int mult) {$/;" f typeref:typename:void +del_back_char cmds_edit.c /^void del_back_char() { \/\/ x DEL$/;" f typeref:typename:void +del_for_char cmds_edit.c /^void del_for_char() { \/\/ X BS$/;" f typeref:typename:void +del_selected_cells cmds.c /^void del_selected_cells(struct sheet * sh) {$/;" f typeref:typename:void +doformat cmds.c /^void doformat(struct sheet * sh, int c1, int c2, int w, int p, int r) {$/;" f typeref:typename:void +dorowformat cmds.c /^void dorowformat(struct sheet * sh, int r, unsigned char size) {$/;" f typeref:typename:void +do_commandmode cmds_command.c /^void do_commandmode(struct block * sb) {$/;" f typeref:typename:void +do_editmode cmds_edit.c /^void do_editmode(struct block * sb) {$/;" f typeref:typename:void +do_insertmode cmds_insert.c /^void do_insertmode(struct block * sb) {$/;" f typeref:typename:void +do_normalmode cmds_normal.c /^void do_normalmode(struct block * buf) {$/;" f typeref:typename:void +do_visualmode cmds_visual.c /^void do_visualmode(struct block * buf) {$/;" f typeref:typename:void +enter_cell_content cmds.c /^void enter_cell_content(struct sheet * sh, int r, int c, char * submode, wchar_t * content) {$/;" f typeref:typename:void +erase_area cmds.c /^void erase_area(struct sheet * sh, int sr, int sc, int er, int ec, int ignorelock, int mark_as_d/;" f typeref:typename:void +etype cmds.c /^int etype(struct enode *e) {$/;" f typeref:typename:int +exit_visualmode cmds_visual.c /^void exit_visualmode() {$/;" f typeref:typename:void +fcopy cmds.c /^int fcopy(struct sheet * sh, char * action) {$/;" f typeref:typename:int +first_nonblank_char cmds_edit.c /^int first_nonblank_char() {$/;" f typeref:typename:int +fix_col_frozen cmds.c /^void fix_col_frozen(struct sheet * sh, int deltac, int ci, int cf) {$/;" f typeref:typename:void +fix_col_hidden cmds.c /^void fix_col_hidden(struct sheet * sh, int deltac, int ci, int cf) {$/;" f typeref:typename:void +fix_row_frozen cmds.c /^void fix_row_frozen(struct sheet * sh, int deltar, int ri, int rf) {$/;" f typeref:typename:void +fix_row_hidden cmds.c /^void fix_row_hidden(struct sheet * sh, int deltar, int ri, int rf) {$/;" f typeref:typename:void +flush_saved cmds.c /^void flush_saved() {$/;" f typeref:typename:void +formatcol cmds.c /^void formatcol(struct sheet * sh, int c) {$/;" f typeref:typename:void +forw_col cmds.c /^struct ent * forw_col(struct sheet * sh, int arg) {$/;" f typeref:struct:ent * +forw_row cmds.c /^struct ent * forw_row(struct sheet * sh, int arg) {$/;" f typeref:struct:ent * +for_word cmds_edit.c /^int for_word(int end_of_word, int delete, int big_word) {$/;" f typeref:typename:int +freeents cmds.c /^struct ent * freeents = NULL; \/\/ keep deleted ents around before sync_refs$/;" v typeref:struct:ent * +fsum cmds.c /^int fsum(struct sheet * sh) {$/;" f typeref:typename:int +goto_bottom cmds.c /^struct ent * goto_bottom(struct sheet * sh) {$/;" f typeref:struct:ent * +goto_last_col cmds.c /^struct ent * goto_last_col(struct sheet * sh) {$/;" f typeref:struct:ent * +goto_top cmds.c /^struct ent * goto_top(struct sheet * sh) {$/;" f typeref:struct:ent * +go_backward cmds.c /^struct ent * go_backward(struct sheet * sh) {$/;" f typeref:struct:ent * +go_bol cmds.c /^struct ent * go_bol(struct sheet * sh) {$/;" f typeref:struct:ent * +go_end cmds.c /^struct ent * go_end(struct sheet * sh) {$/;" f typeref:struct:ent * +go_eol cmds.c /^struct ent * go_eol(struct sheet * sh) {$/;" f typeref:struct:ent * +go_forward cmds.c /^struct ent * go_forward(struct sheet * sh) {$/;" f typeref:struct:ent * +go_home cmds.c /^struct ent * go_home(struct sheet * sh) {$/;" f typeref:struct:ent * +horiz_middle cmds.c /^struct ent * horiz_middle(struct sheet * sh) {$/;" f typeref:struct:ent * +inputline cmds_command.c /^wchar_t inputline[BUFFERSIZE];$/;" v typeref:typename:wchar_t[] +inputline_pos cmds_command.c /^int inputline_pos; \/**< Position in window. Some chars has 2 chars width *\/$/;" v typeref:typename:int +insert_col cmds.c /^void insert_col(struct sheet * sh, int after) {$/;" f typeref:typename:void +insert_edit_submode cmds.c /^char insert_edit_submode;$/;" v typeref:typename:char +insert_row cmds.c /^void insert_row(struct sheet * sh, int after) {$/;" f typeref:typename:void +ins_in_line cmds_command.c /^void ins_in_line(wint_t d) {$/;" f typeref:typename:void +interp_line cmds.c /^wchar_t interp_line[BUFFERSIZE];$/;" v typeref:typename:wchar_t[] +int_deletecol cmds.c /^void int_deletecol(struct sheet * sh, int col, int mult) {$/;" f typeref:typename:void +int_deleterow cmds.c /^void int_deleterow(struct sheet * sh, int row, int mult) {$/;" f typeref:typename:void +istext cmds_edit.c /^#define istext(/;" d file: +is_single_command cmds.c /^int is_single_command (struct block * buf, long timeout) {$/;" f typeref:typename:int +last_nonblank_char cmds_edit.c /^int last_nonblank_char() {$/;" f typeref:typename:int +left_limit cmds.c /^struct ent * left_limit(struct sheet * sh) {$/;" f typeref:struct:ent * +ljustify cmds.c /^void ljustify(struct sheet * sh, int sr, int sc, int er, int ec) {$/;" f typeref:typename:void +locked_cell cmds.c /^int locked_cell(struct sheet * sh, int r, int c) {$/;" f typeref:typename:int +lookat cmds.c /^struct ent * lookat(struct sheet * sh, int row, int col) {$/;" f typeref:struct:ent * +look_back cmds_edit.c /^int look_back(wchar_t cb) {$/;" f typeref:typename:int +look_for cmds_edit.c /^int look_for(wchar_t cb) {$/;" f typeref:typename:int +mark_ent_as_deleted cmds.c /^void mark_ent_as_deleted(struct ent * p, int delete) {$/;" f typeref:typename:void +moving cmds_visual.c /^int moving = FALSE;$/;" v typeref:typename:int +ori_insert_edit_submode cmds_insert.c /^char ori_insert_edit_submode;$/;" v typeref:typename:char +pad cmds.c /^int pad(struct sheet * sh, int n, int r1, int c1, int r2, int c2) {$/;" f typeref:typename:int +pad_and_align cmds.c /^void pad_and_align (char * str_value, char * numeric_value, int col_width, int align, int paddin/;" f typeref:typename:void +r cmds_visual.c /^srange * r; \/\/ SELECTED RANGE!$/;" v typeref:typename:srange * +real_inputline_pos cmds_command.c /^int real_inputline_pos; \/**< Real position in inputline *\/$/;" v typeref:typename:int +right_limit cmds.c /^struct ent * right_limit(struct sheet * sh, int row) {$/;" f typeref:struct:ent * +rjustify cmds.c /^void rjustify(struct sheet * sh, int sr, int sc, int er, int ec) {$/;" f typeref:typename:void +scroll_down cmds.c /^void scroll_down(struct sheet * sh, int n) {$/;" f typeref:typename:void +scroll_left cmds.c /^void scroll_left(struct sheet * sh, int n) {$/;" f typeref:typename:void +scroll_right cmds.c /^void scroll_right(struct sheet * sh, int n) {$/;" f typeref:typename:void +scroll_up cmds.c /^void scroll_up(struct sheet * sh, int n) {$/;" f typeref:typename:void +select_inner_range cmds.c /^void select_inner_range(struct sheet * sh, int * vir_tlrow, int * vir_tlcol, int * vir_brrow, in/;" f typeref:typename:void +send_to_interp cmds.c /^void send_to_interp(wchar_t * oper) {$/;" f typeref:typename:void +start_edit_mode cmds_edit.c /^int start_edit_mode(struct block * buf, char type) {$/;" f typeref:typename:int +start_visualmode cmds_visual.c /^void start_visualmode(int tlrow, int tlcol, int brrow, int brcol) {$/;" f typeref:typename:void +syncref cmds.c /^void syncref(struct sheet * sh, struct enode * e) {$/;" f typeref:typename:void +sync_refs cmds.c /^void sync_refs(struct sheet * sh) {$/;" f typeref:typename:void +tick cmds.c /^struct ent_ptr * tick(char ch) {$/;" f typeref:struct:ent_ptr * +valid_commands cmds_command.c /^static wchar_t * valid_commands[] = {$/;" v typeref:typename:wchar_t * [] file: +valueize_area cmds.c /^void valueize_area(struct sheet * sh, int sr, int sc, int er, int ec) {$/;" f typeref:typename:void +vert_bottom cmds.c /^struct ent * vert_bottom(struct sheet * sh) {$/;" f typeref:struct:ent * +vert_middle cmds.c /^struct ent * vert_middle(struct sheet * sh) {$/;" f typeref:struct:ent * +vert_top cmds.c /^struct ent * vert_top(struct sheet * sh) {$/;" f typeref:struct:ent * +visual_submode cmds_visual.c /^char visual_submode = '0';$/;" v typeref:typename:char +wi cmds_edit.c /^static wint_t wi; \/**< char read from stdin *\/$/;" v typeref:typename:wint_t file: diff -Nru sc-im-0.8.2+ds/src/cmds.c sc-im-0.8.3+ds/src/cmds.c --- sc-im-0.8.2+ds/src/cmds.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2925 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds.c - * \author Andrés Martinelli - * \date 05/04/2021 - * \brief TODO Write brief file description - */ - -#include -#include // for isdigit -#include -#include -#include -#include "main.h" -#include "maps.h" -#include "yank.h" -#include "marks.h" -#include "cmds.h" -#include "buffer.h" -#include "tui.h" -#include "conf.h" // for conf parameters -#include "xmalloc.h" // for scxfree -#include "vmtbl.h" // for growtbl -#include "utils/string.h" // for add_char -#include "y.tab.h" // for yyparse -#include "dep_graph.h" -#include "freeze.h" -#ifdef UNDO -#include "undo.h" -#endif - -void syncref(register struct enode *e); -extern int shall_quit; -char insert_edit_submode; -struct ent * freeents = NULL; // keep deleted ents around before sync_refs -wchar_t interp_line[BUFFERSIZE]; -extern graphADT graph; -extern int yyparse(void); - -int offscr_sc_rows = 0, offscr_sc_cols = 0; // off screen spreadsheet rows and columns -int nb_frozen_rows = 0, nb_frozen_cols = 0; // total number of frozen rows/cols -int nb_frozen_screenrows = 0; // screen rows occupied by those frozen rows -int nb_frozen_screencols = 0; // screen cols occupied by those frozen columns - -/** - * \brief Maintain ent strucs until they are release for deletion by sync_refs. - * - * \details This structure is used to keep ent structs around before - * they are actually deleted (memory freed) to allow the sync_refs - * routine a chance to fix the variable references. If delete flag - * is set, is_deleted flag of an ent is set. - * - * \param[in] p - * \param[in] delete - * - * \return none - */ -void mark_ent_as_deleted(register struct ent * p, int delete) { - if (p == NULL) return; - if (delete) p->flags |= is_deleted; - - p->next = freeents; /* put this ent on the front of freeents */ - freeents = p; - - return; -} - - -/** - * \brief TODO Write brief description - * - * \details Iterates throw freeents (ents marked as deleted). Calls - * clearent for freeing ents contents memory and free ent pointer. This - * function should always be called at exit. This is mandatory, just in - * case we want to UNDO any changes. - * TODO: any malloc of ents should check here before asking for memory - * - * \return none - */ -void flush_saved() { - register struct ent * p; - register struct ent * q; - - p = freeents; - while (p != NULL) { - (void) clearent(p); - q = p->next; - free(p); - p = q; - } - freeents = NULL; - return; -} - - -/** - * \brief TODO Write brief description - * - * \details Used to remove references to deleted struct ents. - * - * \details Note that the deleted structure must still be hanging - * around before the call, but not referenced by an entry in tbl. - * - * \return none - */ -// TODO Improve this function such that it does not traverse the whole table -void sync_refs() { - int i, j; - register struct ent * p; - for (i=0; i <= maxrow; i++) - for (j=0; j <= maxcol; j++) - if ( (p = *ATBL(tbl, i, j)) && p->expr ) { - syncref(p->expr); - } - return; -} - - -/** - * \brief TODO Write brief description - * - * Used to remove a reference to deleted a single struct ent. - * - * Note that the deleted structure must still be hanging around before the - * call, but not referenced by an entry in tbl. - * - * Example usage: - * @code - * syncref(); - * @endcode - * returns: none - */ -void syncref(register struct enode * e) { - if ( e == NULL ) { - return; - } else if ( e->op == ERR_ ) { - e->e.o.left = NULL; - e->e.o.right = NULL; - return; - } else if ( e->op == REF_ ) { - e->op = REF_; - e->e.o.left = NULL; - e->e.o.right = NULL; - return; - } else if (e->op & REDUCE) { - e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col); - e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col); - } else { - switch (e->op) { - case 'v': - if (e->e.v.vp->flags & is_deleted) { - //e->op = ERR_; - //e->e.o.left = NULL; - //e->e.o.right = NULL; - break; - } else if (e->e.v.vp->flags & may_sync) - e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col); - break; - case 'k': - break; - case '$': - break; - default: - syncref(e->e.o.right); - syncref(e->e.o.left); - break; - } - } - return; -} - - -/** - * \brief TODO Write brief description - * - * \param[in] col - * \param[in] mult - * - * \return none - */ -void deletecol(int col, int mult) { - if (any_locked_cells(0, col, maxrow, col + mult)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } -#ifdef UNDO - create_undo_action(); - // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range(0, col, maxrow, col - 1 + mult); - copy_to_undostruct(0, col, maxrow, col - 1 + mult, UNDO_DEL, HANDLE_DEPS, NULL); - save_undo_range_shift(0, -mult, 0, col, maxrow, col - 1 + mult); - - int i; - for (i=col; i < col + mult; i++) { - add_undo_col_format(i, 'R', fwidth[i], precision[i], realfmt[i]); - if (col_hidden[i]) undo_hide_show(-1, i, 's', 1); - else undo_hide_show(-1, i, 'h', 1); - // TODO undo col_frozen - } -#endif - - fix_marks(0, -mult, 0, maxrow, col + mult -1, maxcol); - if (!loading) yank_area(0, col, maxrow, col + mult - 1, 'c', mult); - - // do the job - int_deletecol(col, mult); - - // if (get_conf_int("autocalc")) EvalAll(); - - if (!loading) modflg++; - -#ifdef UNDO - // here we save in undostruct, just the ents that depends on the deleted one (after change) - copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); - - extern struct ent_ptr * deps; - if (deps != NULL) free(deps); - deps = NULL; - - end_undo_action(); -#endif - return; -} - - -/** - * \brief TODO Write a brief description - * - * \details Delete a column. Parameters col = column to delete - * multi = cmds multiplier. (commonly 1) - * - * \param[in] col - * \param[in] mult - * - * \return none - */ -void int_deletecol(int col, int mult) { - register struct ent ** pp; - int r, c, i; - - while (mult--) { - // mark ent of column to erase with is_deleted flag - for (r = 0; r <= maxrow; r++) { - pp = ATBL(tbl, r, col); - if ( *pp != NULL ) { - mark_ent_as_deleted(*pp, TRUE); - //clearent(*pp); - //free(*pp); - *pp = NULL; - } - } - - rebuild_graph(); // Rebuild of graph is needed. - //But shouldnt! TODO - - // Copy references from right column cells to left column (which gets removed) - for (r = 0; r <= maxrow; r++) { - for (c = col; c < maxcol; c++) { - pp = ATBL(tbl, r, c); - - // nota: pp[1] = ATBL(tbl, r, c+1); - if ( pp[1] != NULL ) pp[1]->col--; - pp[0] = pp[1]; - } - - // Free last column memory (Could also initialize 'ent' to zero with `cleanent`). - pp = ATBL(tbl, r, maxcol); - *pp = (struct ent *) 0; - } - - // Fix columns precision and width - for (i = col; i < maxcols - 2; i++) { - fwidth[i] = fwidth[i+1]; - precision[i] = precision[i+1]; - realfmt[i] = realfmt[i+1]; - col_hidden[i] = col_hidden[i+1]; - col_frozen[i] = col_frozen[i+1]; - } - - for (; i < maxcols - 1; i++) { - fwidth[i] = DEFWIDTH; - precision[i] = DEFPREC; - realfmt[i] = DEFREFMT; - col_hidden[i] = FALSE; - col_frozen[i] = FALSE; - } - - maxcol--; - sync_refs(); - EvalAll(); - //flush_saved(); // we have to flush_saved only at exit. - //this is because we have to keep ents in case we want to UNDO - } - - return; -} - - -/** - * \brief TODO Write a brief description - * - * \details Copy cell (struct ent). "special" indicates special treatment - * when merging two cells for the "pm" command, merging formate only for - * the "pf" command, or for adjusting cell references when transposing - * with the "pt" command. r1, c1, r2, and c2 define the range in which the - * dr and dc values should be used. Special =='u' means special copy from - * spreadsheet to undo struct. Since its mandatory to make isolated copies - * of p->expr->e.o.right.e.v.vp and p->expr->e.o.right.e.v.vp - * - * \param[in] n - * \param[in] p - * \param[in] dr - * \param[in] dc - * \param[in] r1 - * \param[in] c1 - * \param[in] r2 - * \param[in] c2 - * \param[in] special - * \return none - */ -void copyent(register struct ent * n, register struct ent * p, int dr, int dc, int r1, int c1, int r2, int c2, int special) { - if (!n || !p) { - sc_error("copyent: internal error"); - return; - } - - n->flags = may_sync; - if (p->flags & is_deleted) - n->flags |= is_deleted; - - if (special != 'f') { - if (p->flags & is_valid) { - n->v = p->v; - n->flags |= p->flags & is_valid; - } - if (special != 'v' && p->expr && special != 'u') { - n->expr = copye(p->expr, dr, dc, r1, c1, r2, c2, special == 't'); -#ifdef UNDO - } else if (special == 'u' && p->expr) { // from spreadsheet to undo - n->expr = copye(p->expr, dr, dc, r1, c1, r2, c2, 2); -#endif - } - if (p->expr && p->flags & is_strexpr) - n->flags |= is_strexpr; - else if (p->expr) - n->flags &= ~is_strexpr; - - if (p->label) { - if (n->label) scxfree(n->label); - n->label = scxmalloc((unsigned) (strlen(p->label) + 1)); - (void) strcpy(n->label, p->label); - n->flags &= ~is_leftflush; - n->flags |= ((p->flags & is_label) | (p->flags & is_leftflush)); - } - n->flags |= p->flags & is_locked; - } - if (p->format && special != 'v') { - if (n->format) scxfree(n->format); - n->format = scxmalloc((unsigned) (strlen(p->format) + 1)); - (void) strcpy(n->format, p->format); - } else if (special != 'v' && special != 'f') - n->format = NULL; - - if (special != 'v') { - n->pad = p->pad; - if (n->ucolor) { // remove current cellcolor format in n ent - free(n->ucolor); - n->ucolor = NULL; - } - if (p->ucolor) { // copy new cellcolor format from p to n ent - n->ucolor = (struct ucolor *) malloc (sizeof(struct ucolor)); - n->ucolor->fg = p->ucolor->fg; - n->ucolor->bg = p->ucolor->bg; - n->ucolor->bold = p->ucolor->bold; - n->ucolor->italic = p->ucolor->italic; - n->ucolor->dim = p->ucolor->dim; - n->ucolor->reverse = p->ucolor->reverse; - n->ucolor->standout = p->ucolor->standout; - n->ucolor->underline = p->ucolor->underline; - n->ucolor->blink = p->ucolor->blink; - } - } - - // used for undoing / redoing cells that has errors - n->cellerror = p->cellerror; - - if (special == 'c' && n->expr) - EvalJustOneVertex(n, 0); - - n->flags |= is_changed; - n->row = p->row; - n->col = p->col; - return; -} - - -/** - * \brief TODO Write brief description - * \return NUM; STR; etc. - */ -int etype(register struct enode *e) { - if (e == (struct enode *)0) - return NUM; - switch (e->op) { - case UPPER: case LOWER: case CAPITAL: - case O_SCONST: case '#': case DATE: case FMT: case STINDEX: - case EXT: case LUA: case SVAL: case SUBSTR: - return (STR); - - case '?': - case IF: - return (etype(e->e.o.right->e.o.left)); - - case 'f': - return (etype(e->e.o.right)); - - case O_VAR: { - register struct ent *p; - p = e->e.v.vp; - if (p->expr) - return (p->flags & is_strexpr ? STR : NUM); - else if (p->label) - return (STR); - else - return (NUM); - } - - default: - return (NUM); - } - return -1; -} - - -/** - * \brief TODO Write a brief function description - * \details ignorelock is used when sorting so that locked cells - * can still be sorted - * \param[in] sr - * \param[in] sc - * \param[in] er - * \param[in] ec - * \param[in] ignorelock - * \param[in] mark_as_deleted - * \return none - */ -void erase_area(int sr, int sc, int er, int ec, int ignorelock, int mark_as_deleted) { - int r, c; - struct ent **pp; - - if (sr > er) { - r = sr; sr = er; er = r; - } - - if (sc > ec) { - c = sc; sc = ec; ec = c; - } - - if (sr < 0) - sr = 0; - if (sc < 0) - sc = 0; - checkbounds(&er, &ec); - - /* mark the ent as deleted - * Do a lookat() for the upper left and lower right cells of the range - * being erased to make sure they are included in the delete buffer so - * that pulling cells always works correctly even if the cells at one - * or more edges of the range are all empty. - */ - (void) lookat(sr, sc); - (void) lookat(er, ec); - for (r = sr; r <= er; r++) { - for (c = sc; c <= ec; c++) { - pp = ATBL(tbl, r, c); - if (*pp && (!((*pp)->flags & is_locked) || ignorelock)) { - - /* delete vertex in graph - only if this vertex is not referenced by other */ - vertexT * v = getVertex(graph, *pp, 0); - if (v != NULL && v->back_edges == NULL ) - destroy_vertex(*pp); - - if (mark_as_deleted) { - mark_ent_as_deleted(*pp, TRUE); - } else { - clearent(*pp); // free memory - cleanent(*pp); // fill ent with empty values - mark_ent_as_deleted(*pp, FALSE); - } - *pp = NULL; - } - } - } - return; -} - - -/** - * \brief TODO Write a brief function description - * \details Function to copy an expression. It returns the copy. - * special = 1 means transpose - * special = 2 means copy from spreadsheet to undo struct - * \param[in] e - * \param[in] Rdelta - * \param[in] Cdelta - * \param[in] r1 - * \param[in] c1 - * \param[in] r2 - * \param[in] c2 - * \param[in] special - * \return none - */ -struct enode * copye(register struct enode *e, int Rdelta, int Cdelta, int r1, int c1, int r2, int c2, int special) { - register struct enode * ret; - static struct enode * range = NULL; - - if (e == (struct enode *) 0) { - ret = (struct enode *) 0; - - } else if (e->op & REDUCE) { - int newrow, newcol; - ret = (struct enode *) scxmalloc((unsigned) sizeof (struct enode)); - ret->op = e->op; - ret->e.r.left.expr = e->e.r.left.expr ? copye(e->e.r.left.expr, Rdelta, Cdelta, r1, c1, r2, c2, special) : NULL; // important to initialize - ret->e.r.right.expr = e->e.r.right.expr ? copye(e->e.r.right.expr, Rdelta, Cdelta, r1, c1, r2, c2, special) : NULL; // important to initialize - newrow = e->e.r.left.vf & FIX_ROW || e->e.r.left.vp->row < r1 || e->e.r.left.vp->row > r2 || e->e.r.left.vp->col < c1 || e->e.r.left.vp->col > c2 ? e->e.r.left.vp->row : special == 1 ? r1 + Rdelta + e->e.r.left.vp->col - c1 : e->e.r.left.vp->row + Rdelta; - newcol = e->e.r.left.vf & FIX_COL || e->e.r.left.vp->row < r1 || e->e.r.left.vp->row > r2 || e->e.r.left.vp->col < c1 || e->e.r.left.vp->col > c2 ? e->e.r.left.vp->col : special == 1 ? c1 + Cdelta + e->e.r.left.vp->row - r1 : e->e.r.left.vp->col + Cdelta; - ret->e.r.left.vp = lookat(newrow, newcol); - ret->e.r.left.vf = e->e.r.left.vf; - newrow = e->e.r.right.vf & FIX_ROW || e->e.r.right.vp->row < r1 || e->e.r.right.vp->row > r2 || e->e.r.right.vp->col < c1 || e->e.r.right.vp->col > c2 ? e->e.r.right.vp->row : special == 1 ? r1 + Rdelta + e->e.r.right.vp->col - c1 : e->e.r.right.vp->row + Rdelta; - newcol = e->e.r.right.vf & FIX_COL || e->e.r.right.vp->row < r1 || e->e.r.right.vp->row > r2 || e->e.r.right.vp->col < c1 || e->e.r.right.vp->col > c2 ? e->e.r.right.vp->col : special == 1 ? c1 + Cdelta + e->e.r.right.vp->row - r1 : e->e.r.right.vp->col + Cdelta; - ret->e.r.right.vp = lookat(newrow, newcol); - ret->e.r.right.vf = e->e.r.right.vf; - } else { - struct enode *temprange=0; - ret = (struct enode *) scxmalloc((unsigned) sizeof (struct enode)); - ret->e.r.left.expr = e->e.r.left.expr ? copye(e->e.r.left.expr, Rdelta, Cdelta, r1, c1, r2, c2, special) : NULL; // important to initialize - ret->e.r.right.expr = e->e.r.right.expr ? copye(e->e.r.right.expr, Rdelta, Cdelta, r1, c1, r2, c2, special) : NULL; // important to initialize - ret->e.r.left.vp = e->e.r.left.vp; - ret->e.r.right.vp = e->e.r.right.vp; - ret->op = e->op; - switch (ret->op) { - case SUM: - case PROD: - case AVG: - case COUNT: - case STDDEV: - case MAX: - case MIN: - temprange = range; - range = e->e.o.left; - r1 = 0; - c1 = 0; - r2 = maxrow; - c2 = maxcol; - } - switch (ret->op) { - case 'v': - { - int newrow, newcol; - if (range && e->e.v.vp->row >= range->e.r.left.vp->row && e->e.v.vp->row <= range->e.r.right.vp->row && e->e.v.vp->col >= range->e.r.left.vp->col && e->e.v.vp->col <= range->e.r.right.vp->col) { - newrow = range->e.r.left.vf & FIX_ROW ? e->e.v.vp->row : e->e.v.vp->row + Rdelta; - newcol = range->e.r.left.vf & FIX_COL ? e->e.v.vp->col : e->e.v.vp->col + Cdelta; - } else { - newrow = e->e.v.vf & FIX_ROW || e->e.v.vp->row < r1 || e->e.v.vp->row > r2 || e->e.v.vp->col < c1 || e->e.v.vp->col > c2 ? e->e.v.vp->row : special == 1 ? r1 + Rdelta + e->e.v.vp->col - c1 : e->e.v.vp->row + Rdelta; - newcol = e->e.v.vf & FIX_COL || e->e.v.vp->row < r1 || e->e.v.vp->row > r2 || e->e.v.vp->col < c1 || e->e.v.vp->col > c2 ? e->e.v.vp->col : special == 1 ? c1 + Cdelta + e->e.v.vp->row - r1 : e->e.v.vp->col + Cdelta; - } - ret->e.v.vp = lookat(newrow, newcol); - ret->e.v.vf = e->e.v.vf; - break; - } - case 'k': - ret->e.k = e->e.k; - break; - case 'f': - case 'F': - if ((range && ret->op == 'F') || (!range && ret->op == 'f')) - Rdelta = Cdelta = 0; - ret->e.o.left = copye(e->e.o.left, Rdelta, Cdelta, r1, c1, r2, c2, special); - ret->e.o.right = (struct enode *)0; - break; - case '$': - case EXT: - ret->e.s = scxmalloc((unsigned) strlen(e->e.s)+1); - (void) strcpy(ret->e.s, e->e.s); - if (e->op == '$') /* Drop through if ret->op is EXT */ - break; - default: - if (e->op == ERR_) { - //ret->e.o.left = NULL; - //ret->e.o.right = NULL; - //ret->e.o.right = (struct enode *)0; - break; /* fix #108 */ - } - ret->e.o.left = copye(e->e.o.left, Rdelta, Cdelta, r1, c1, r2, c2, special); - ret->e.o.right = copye(e->e.o.right, Rdelta, Cdelta, r1, c1, r2, c2, special); - break; - } - switch (ret->op) { - case SUM: - case PROD: - case AVG: - case COUNT: - case STDDEV: - case MAX: - case MIN: - range = temprange; - } - } - return ret; -} - - -/** - * \brief dorowformat() - * \details: apply a row format in lines(size) to a row (r) - * \param[in] r - * \param[in] size - * \return none - */ -void dorowformat(int r, unsigned char size) { - if (size < 1 || size > UCHAR_MAX || size > LINES - RESROW - 1) { sc_error("Invalid row format"); return; } - - if (r >= maxrows && !growtbl(GROWROW, 0, r)) r = maxrows-1 ; - checkbounds(&r, &curcol); - row_format[r] = size; - if (! loading) modflg++; - return; -} - - -/** - * \brief TODO Write brief function description - * \details Note: Modified 9/17/90 THA to handle more formats. - * \param[in] c1 - * \param[in] c2 - * \param[in] w - * \param[in] p - * \param[in] r - * \return none - */ -void doformat(int c1, int c2, int w, int p, int r) { - register int i; - int crows = 0; - int ccols = c2; - - if (c1 >= maxcols && !growtbl(GROWCOL, 0, c1)) c1 = maxcols-1 ; - if (c2 >= maxcols && !growtbl(GROWCOL, 0, c2)) c2 = maxcols-1 ; - - if (w == 0) { - sc_info("Width too small - setting to 1"); - w = 1; - } - - if (! get_conf_int("nocurses") && w > COLS - rescol - 2) { - sc_info("Width too large - Maximum = %d", COLS - rescol - 2); - w = COLS - rescol - 2; - } - - if (p > w) { - sc_info("Precision too large"); - p = w; - } - - checkbounds(&crows, &ccols); - if (ccols < c2) { - sc_error("Format statement failed to create implied column %d", c2); - return; - } - - for (i = c1; i <= c2; i++) - fwidth[i] = w, precision[i] = p, realfmt[i] = r; - - modflg++; - return; - -} - - -/** - * \brief TODO Document formatcol) - * \param[in] c - * \return none - */ -void formatcol(int c) { - int arg = 1; - int i; - - switch (c) { - case '<': - case 'h': - case OKEY_LEFT: - for (i = curcol; i < curcol + arg; i++) { - if (fwidth[i] <= 2) { - sc_error("Cannot resize column any longer"); - return; - } - fwidth[i]--; - if (fwidth[i] <= 1) - fwidth[i] = 1; - } - modflg++; - break; - case '>': - case 'l': - case OKEY_RIGHT: - for (i = curcol; i < curcol + arg; i++) { - fwidth[i]++; - if (fwidth[i] > COLS - rescol - 2) - fwidth[i] = COLS - rescol - 2; - } - modflg++; - break; - case '-': - for (i = curcol; i < curcol + arg; i++) { - precision[i]--; - if (precision[i] < 0) - precision[i] = 0; - } - modflg++; - break; - case '+': - for (i = curcol; i < curcol + arg; i++) - precision[i]++; - modflg++; - break; - } - sc_info("Current format is %d %d %d", fwidth[curcol], precision[curcol], realfmt[curcol]); - ui_update(TRUE); - return; -} - - -/** - * \brief TODO Document insert_row() - * \details Insert a single rox. It will be inserted before currow. - * if after is 0; after if it is 1. - * \param[in] after - * \returnsnone - */ -void insert_row(int after) { - int r, c; - struct ent ** tmprow, ** pp, ** qq; - struct ent * p; - int lim = maxrow - currow + 1; - - if (currow > maxrow) maxrow = currow; - maxrow++; - lim = maxrow - lim + after; - if (maxrow >= maxrows && ! growtbl(GROWROW, maxrow, 0)) return; - - tmprow = tbl[maxrow]; - for (r = maxrow; r > lim; r--) { - row_hidden[r] = row_hidden[r-1]; - row_frozen[r] = row_frozen[r-1]; - row_format[r] = row_format[r-1]; - tbl[r] = tbl[r-1]; - for (c = 0, pp = ATBL(tbl, r, 0); c < maxcols; c++, pp++) - if (*pp) (*pp)->row = r; - } - tbl[r] = tmprow; // the last row is never used - row_format[r] = 1; - - // if padding exists in the old currow, we copy it to the new row! - for (c = 0; c < maxcols; c++) { - if (r >= 0 && (qq = ATBL(tbl, r+1, c)) && (*qq) && (*qq)->pad) { - p = lookat(r, c); - p->pad = (*qq)->pad; - } - } - - modflg++; - return; -} - - -/** - * \brief Insert new column - * \details Insert a cingle column. The column will be inserted - * BEFORE CURCOL if after is 0; - * AFTER CURCOL if it is 1. - * \param[in] after - * \return none - */ -void insert_col(int after) { - int r, c; - register struct ent ** pp, ** qq; - struct ent * p; - int lim = maxcol - curcol - after + 1; - - if (curcol + after > maxcol) - maxcol = curcol + after; - maxcol++; - - if ((maxcol >= maxcols) && !growtbl(GROWCOL, 0, maxcol)) - return; - - for (c = maxcol; c >= curcol + after + 1; c--) { - fwidth[c] = fwidth[c-1]; - precision[c] = precision[c-1]; - realfmt[c] = realfmt[c-1]; - col_hidden[c] = col_hidden[c-1]; - col_frozen[c] = col_frozen[c-1]; - } - for (c = curcol + after; c - curcol - after < 1; c++) { - fwidth[c] = DEFWIDTH; - precision[c] = DEFPREC; - realfmt[c] = DEFREFMT; - col_hidden[c] = FALSE; - col_frozen[c] = FALSE; - } - - for (r=0; r <= maxrow; r++) { - pp = ATBL(tbl, r, maxcol); - for (c = lim; --c >= 0; pp--) - if ((pp[0] = pp[-1])) pp[0]->col++; - - pp = ATBL(tbl, r, curcol + after); - for (c = curcol + after; c - curcol - after < 1; c++, pp++) - *pp = (struct ent *) 0; - } - - // if padding exists in the old curcol, we copy it to the new col! - for (r = 0; r < maxrows; r++) { - if (c >= 0 && (qq = ATBL(tbl, r, c+1)) && (*qq) && (*qq)->pad) { - p = lookat(r, c); - p->pad = (*qq)->pad; - } - } - - curcol += after; - modflg++; - return; -} - - -/** - * \brief Delete a row - * \param[in] row - * \param[in] mult - * \return none - */ -void deleterow(int row, int mult) { - if (any_locked_cells(row, 0, row + mult - 1, maxcol)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } -#ifdef UNDO - create_undo_action(); - // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range(row, 0, row + mult - 1, maxcol); - copy_to_undostruct(row, 0, row + mult - 1, maxcol, UNDO_DEL, HANDLE_DEPS, NULL); - save_undo_range_shift(-mult, 0, row, 0, row - 1 + mult, maxcol); - int i; - for (i=row; i < row + mult; i++) { - add_undo_row_format(i, 'R', row_format[currow]); - if (row_hidden[i]) undo_hide_show(i, -1, 's', 1); - //else undo_hide_show(i, -1, 'h', 1); - } -#endif - - fix_marks(-mult, 0, row + mult - 1, maxrow, 0, maxcol); - if (!loading) yank_area(row, 0, row + mult - 1, maxcol, 'r', mult); - - // do the job - int_deleterow(row, mult); - - //flush_saved(); // we have to flush only at exit. this is in case we want to UNDO - - if (!loading) modflg++; - -#ifdef UNDO - // here we save in undostruct, just the ents that depends on the deleted one (after the change) - copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); - - extern struct ent_ptr * deps; - if (deps != NULL) free(deps); - deps = NULL; - - end_undo_action(); -#endif - return; -} - - -/** - * \brief Delete a row - * \details Delete a row - internal function - * \param[in] row row to delete - * \param[in] multi commands multiplier (usually 1) - * \return none - */ -void int_deleterow(int row, int mult) { - register struct ent ** pp; - register struct ent * q; - int r, c; - - //if (currow > maxrow) return; - - while (mult--) { - // we need to decrease row of the row that we delete if - // other cells refers to this one. - for (c = 0; c < maxcols; c++) { - if (row <= maxrow) { - pp = ATBL(tbl, row, c); - if ((q = *ATBL(tbl, row, c)) != NULL && q->row > 0) q->row--; - } - } - sync_refs(); - - // and after that the erase_area of the deleted row - erase_area(row, 0, row, maxcol, 0, 1); //important: this mark the ents as deleted - - // and we decrease ->row of all rows after the deleted one - for (r = row; r < maxrows - 1; r++) { - for (c = 0; c < maxcols; c++) { - if (r <= maxrow) { - pp = ATBL(tbl, r, c); - pp[0] = *ATBL(tbl, r+1, c); - if ( pp[0] ) pp[0]->row--; - } - } - //update row_hidden and row_format here - row_hidden[r] = row_hidden[r+1]; - row_frozen[r] = row_frozen[r+1]; - row_format[r] = row_format[r+1]; - } - - rebuild_graph(); //TODO CHECK HERE WHY REBUILD IS NEEDED. See NOTE1 in shift.c - sync_refs(); - EvalAll(); - maxrow--; - } - return; -} - - -/** - * \brief Document ljustify() - * \param[in] sr - * \param[in] sc - * \param[in] er - * \param[in] ec - * \return none - */ -void ljustify(int sr, int sc, int er, int ec) { - struct ent *p; - int i, j; - - if (sr > er) { - i = sr; - sr = er; - er = i; - } - if (sc > ec) { - i = sc; - sc = ec; - ec = i; - } - for (i = sr; i <= er; i++) { - for (j = sc; j <= ec; j++) { - p = *ATBL(tbl, i, j); - if (p && p->label) { - p->flags &= ~is_label; - p->flags |= is_leftflush | is_changed; - modflg++; - } - } - } - return; -} - - -/** - * \brief TODO Document rjustify() - * \param[in] sr - * \param[in] sc - * \param[in] er - * \param[in] ec - * \return none - */ -void rjustify(int sr, int sc, int er, int ec) { - struct ent *p; - int i, j; - - if (sr > er) { - i = sr; - sr = er; - er = i; - } - if (sc > ec) { - i = sc; - sc = ec; - ec = i; - } - for (i = sr; i <= er; i++) { - for (j = sc; j <= ec; j++) { - p = *ATBL(tbl, i, j); - if (p && p->label) { - p->flags &= ~(is_label | is_leftflush); - p->flags |= is_changed; - modflg++; - } - } - } - return; -} - - -/** - * \brief TODO Document center() - * \param[in] sr - * \param[in] sc - * \param[in] er - * \param[in] ec - * \return none - */ -void center(int sr, int sc, int er, int ec) { - struct ent *p; - int i, j; - - if (sr > er) { - i = sr; - sr = er; - er = i; - } - if (sc > ec) { - i = sc; - sc = ec; - ec = i; - } - for (i = sr; i <= er; i++) { - for (j = sc; j <= ec; j++) { - p = *ATBL(tbl, i, j); - if (p && p->label) { - p->flags &= ~is_leftflush; - p->flags |= is_label | is_changed; - modflg++; - } - } - } - return; -} - - -/** - * @brief TODO Document chg_mode - * \param[in] strcmd - * \return none - */ -void chg_mode(char strcmd){ - lastmode = curmode; - switch (strcmd) { - case '=': - curmode = INSERT_MODE; - break; - case '<': - curmode = INSERT_MODE; - break; - case '>': - curmode = INSERT_MODE; - break; - case '\\': - curmode = INSERT_MODE; - break; - case 'E': - curmode = EDIT_MODE; - break; - case 'e': - curmode = EDIT_MODE; - break; - case ':': - curmode = COMMAND_MODE; - break; - case '.': - curmode = NORMAL_MODE; - break; - case 'v': - curmode = VISUAL_MODE; - break; - } - return; -} - - -/** - * \brief Delete selected cells - * \details Delete selected cell or range of cells. - * \return none - */ -void del_selected_cells() { - int tlrow = currow; - int tlcol = curcol; - int brrow = currow; - int brcol = curcol; - - // is we delete a range - if (is_range_selected() != -1) { - srange * r = get_selected_range(); - tlrow = r->tlrow; - tlcol = r->tlcol; - brrow = r->brrow; - brcol = r->brcol; - } - - if (any_locked_cells(tlrow, tlcol, brrow, brcol)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } - - if (is_range_selected() != -1) - yank_area(tlrow, tlcol, brrow, brcol, 'a', 1); - else - yank_area(tlrow, tlcol, brrow, brcol, 'e', 1); - -#ifdef UNDO - create_undo_action(); - // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range(tlrow, tlcol, brrow, brcol); - copy_to_undostruct(tlrow, tlcol, brrow, brcol, UNDO_DEL, HANDLE_DEPS, NULL); -#endif - - erase_area(tlrow, tlcol, brrow, brcol, 0, 0); //important: this erases the ents, but does NOT mark them as deleted - modflg++; - sync_refs(); - //flush_saved(); DO NOT UNCOMMENT! flush_saved shall not be called other than at exit. - - EvalRange(tlrow, tlcol, brrow, brcol); - -#ifdef UNDO - // here we save in undostruct, all the ents that depends on the deleted one (after the change) - copy_to_undostruct(tlrow, tlcol, brrow, brcol, UNDO_ADD, HANDLE_DEPS, NULL); - extern struct ent_ptr * deps; - if (deps != NULL) free(deps); - deps = NULL; - end_undo_action(); -#endif - - return; -} - - -/** - * \brief Enter cell content on a cell - * \details Enter cell content on a cell. - * Covers commands LET, LABEL, LEFTSTRING, and RIGHTSTRING - * \param[in] r - * \param[in] c - * \param[in] submode - * \param[in] content - * \return none - */ -void enter_cell_content(int r, int c, char * submode, wchar_t * content) { - (void) swprintf(interp_line, BUFFERSIZE, L"%s %s = %ls", submode, v_name(r, c), content); - send_to_interp(interp_line); - if (get_conf_int("autocalc") && ! loading) EvalRange(r, c, r, c); -} - - -/** - * @brief Send command to interpreter - * \details Send command to interpreter - * wide_char version - * \param[in] oper - * \return none - */ -void send_to_interp(wchar_t * oper) { - if (get_conf_int("nocurses")) { - int pos = -1; - if ((pos = wstr_in_wstr(oper, L"\n")) != -1) - oper[pos] = L'\0'; - sc_debug("Interp GOT: %ls", oper); - } - wcstombs(line, oper, BUFFERSIZE); - - linelim = 0; - yyparse(); - linelim = -1; - line[0]='\0'; - // commented on 28/04/2021. EvalAll should be used only on certain ocasions. - // Use EvalRange instead when possible, and certainly not here everytime sending to interp. - //if (get_conf_int("autocalc") && ! loading) EvalAll(); - return; -} - - -/** - * \brief Return a pointer to a cell's [struct ent *] - * Return a pointer to a cell's [struct ent *], creating if needed - * \param[in] row - * \param[in] col - * \return none - */ -struct ent * lookat(int row, int col) { - register struct ent **pp; - - checkbounds(&row, &col); - pp = ATBL(tbl, row, col); - if ( *pp == NULL) { - *pp = (struct ent *) malloc( (unsigned) sizeof(struct ent) ); - (*pp)->label = (char *) 0; - (*pp)->flags = may_sync; - (*pp)->expr = (struct enode *) 0; - (*pp)->trigger = (struct trigger *) 0; - (*pp)->v = (double) 0.0; - (*pp)->format = (char *) 0; - (*pp)->cellerror = CELLOK; - (*pp)->next = NULL; - (*pp)->ucolor = NULL; - (*pp)->pad = 0; - } - (*pp)->row = row; - (*pp)->col = col; - if (row > maxrow) maxrow = row; - if (col > maxcol) maxcol = col; - return (*pp); -} - - -/** - * \brief Blank an ent - * \param[in] p - * \return none - */ -void cleanent(struct ent * p) { - if (!p) return; - p->label = (char *) 0; - // do not uncomment. if so mod erase_area. - //p->row = 0; - //p->col = 0; - - p->flags = may_sync; - p->expr = (struct enode *) 0; - p->v = (double) 0.0; - p->format = (char *) 0; - p->cellerror = CELLOK; - p->next = NULL; - p->ucolor = NULL; - p->pad = 0; - return; -} - - -/** - * \brief Free memory of an ent and its contents - * \param[in] v - * \return none - */ -void clearent(struct ent * v) { - if (!v) return; - - label(v, "", -1); - v->v = (double)0; - - if (v->expr) efree(v->expr); - v->expr = NULL; - - if (v->format) scxfree(v->format); - v->format = NULL; - - if (v->ucolor) free(v->ucolor); - v->ucolor = NULL; - - v->flags = is_changed; - - modflg++; - - return; -} - - -/** - * \brief Moves curcol back one displayed column - * \param[in] arg - * \return lookat - */ -struct ent * back_col(int arg) { - int c = curcol; - - while (--arg >= 0) { - if (c) { - curcol = --c; - } else { - sc_info ("At column A"); - break; - } - while (col_hidden[c] && c) { - curcol = --c; - } - } - if (curcol < offscr_sc_cols) - offscr_sc_cols = curcol; - - return lookat(currow, c); -} - - -/** - * \brief Moves curcol forward one displayed column - * \param[in] arg - * \return lookat - */ -struct ent * forw_col(int arg) { - int c = curcol; - - while (--arg >= 0) { - if (c < maxcols - 1) { - c++; - } else { - if (! growtbl(GROWCOL, 0, arg)) { /* get as much as needed */ - sc_error("cannot grow"); - return lookat(currow, curcol); - } else { - c++; - } - } - while (col_hidden[c] && c < maxcols - 1) { - c++; - } - - } - return lookat(currow, c); -} - - -/** - * \brief Move currow forward one displayed row - * \param[in] arg - * \return lookat - */ -struct ent * forw_row(int arg) { - int r = currow; - - while (arg--) { - if (r < maxrows - 1) - r++; - else { - if (! growtbl(GROWROW, arg, 0)) { - sc_error("cannot grow"); - return lookat(currow, curcol); - } else - r++; - } - while (row_hidden[r] && r < maxrows - 1) r++; - } - return lookat(r, curcol); -} - - -/** - * \brief Moves currow backward on displayed row - * \return lookat - */ -struct ent * back_row(int arg) { - int r = currow; - - while (--arg >= 0) { - if (r) { - --r; - } else { - sc_info ("At row 0"); - break; - } - while (row_hidden[r] && r) --r; - } - return lookat(r, curcol); -} - - -/** - * \brief Document scroll_down() - * \param[in] n - * \return none - */ -void scroll_down(int n) { - while (n--) { - int last, currow_orig = currow; - /* find last mobile row */ - calc_mobile_rows(&last); - /* move to next non-hidden non-frozen row */ - do { - lookat(++last, curcol); - if (last >= maxrows) - return; - } while (row_hidden[last] || row_frozen[last]); - /* this will adjust offscr_sc_rows */ - currow = last; - calc_mobile_rows(NULL); - /* restore currow */ - currow = currow_orig; - if (currow < offscr_sc_rows) - currow = offscr_sc_rows; - unselect_ranges(); - } -} - - -/** - * @brief Document scroll_up() - * \param[in] n - * \return none - */ -void scroll_up(int n) { - while (n--) { - int first, last, currow_orig = currow; - /* move to previous non-hidden non-frozen row */ - first = offscr_sc_rows; - do { - if (--first < 0) - return; - } while (row_hidden[first] || row_frozen[first]); - offscr_sc_rows = first; - /* find corresponding last mobile row */ - currow = first; - calc_mobile_rows(&last); - /* restore/adjust currow */ - currow = currow_orig; - if (currow > last) - currow = last; - unselect_ranges(); - } -} - - -/** - * \brief TODO Document go_home() - * \return lookat - */ -struct ent * go_home() { - return lookat(0, 0); -} - - -/** - * \brief vert_top() - for command H in normal mode - * \return lookat - */ -struct ent * vert_top() { - int r = offscr_sc_rows; - while (row_hidden[r] || row_frozen[r]) r++; - return lookat(r, curcol); -} - - -/** - * \brief vert_bottom() - for command L in normal mode - * \return lookat - */ -struct ent * vert_bottom() { - int last; - calc_mobile_rows(&last); - return lookat(last, curcol); -} - - -/** - * \brief vert_middle() - for command M in normal mode - * \return lookat - */ -struct ent * vert_middle() { - int i; - int midscreen_pos = (LINES - RESROW - RESCOLHEADER - 1)/2; - int curr_pos = 0; - int mobile_rows = calc_mobile_rows(NULL); - - for (i = 0; i < maxrows; i++) { - if (row_hidden[i]) - continue; - if (! row_frozen[i]) { - if (i < offscr_sc_rows) - continue; - if (--mobile_rows < 0) - continue; - } - - /* compare middle of current row against middle of screen */ - if (curr_pos + (row_format[i] - 1)/2 >= midscreen_pos) - return lookat(i, curcol); - - curr_pos += row_format[i]; - } - return NULL; -} - - -/** - * \brief go_end(): go to last valid cell of grid - * \return lookat; NULL otherwise - */ -struct ent * go_end() { - int r = 0, c = 0; - int raux = r, caux = c; - register struct ent *p; - do { - if (c < maxcols - 1) - c++; - else { - if (r < maxrows - 1) { - r++; - c = 0; - } else break; - } - if (VALID_CELL(p, r, c) && ! col_hidden[c] && ! row_hidden[r]) { raux = r; caux = c; } - } while ( r < maxrows || c < maxcols ); - if ( ! VALID_CELL(p, r, c) && ! col_hidden[c] && ! row_hidden[r] ) - return lookat(raux, caux); - return NULL; -} - - -/** - * \brief TODO Document tick() - * \details if ticks a cell, returns struct ent * - * if ticks a range, return struct ent * to top left cell - * \return lookat; NULL otherwise - */ -struct ent * tick(char ch) { - int r, c; - struct mark * m = get_mark(ch); - //tick cell - r = m->row; - - if (r != -1) { - checkbounds(&r, &curcol); - return lookat(r, m->col); - } - - // tick range - if (curmode != VISUAL_MODE) { - r = m->rng->tlrow; - c = m->rng->tlcol; - m->rng->selected = 1; - checkbounds(&r, &c); - return lookat(r, c); - } - return NULL; -} - - -/** - * \brief TODO Document scroll_right() - * \param[in] n - * \return none - */ -void scroll_right(int n) { - while (n--) { - int last, curcol_orig = curcol; - /* find last mobile column */ - calc_mobile_cols(&last); - /* move to next non-hidden non-frozen column */ - do { - lookat(currow, ++last); - if (last >= maxcols) - return; - } while (col_hidden[last] || col_frozen[last]); - /* this will adjust offscr_sc_cols */ - curcol = last; - calc_mobile_cols(NULL); - /* restore curcol */ - curcol = curcol_orig; - if (curcol < offscr_sc_cols) - curcol = offscr_sc_cols; - unselect_ranges(); - } -} - -/** - * @brief TODO Document scroll_left() - * \param[in] n - * \return none - */ -void scroll_left(int n) { - while (n--) { - int first, last, curcol_orig = curcol; - /* move to previous non-hidden non-frozen column */ - first = offscr_sc_cols; - do { - if (--first < 0) - return; - } while (col_hidden[first] || col_frozen[first]); - offscr_sc_cols = first; - /* find corresponding last mobile column */ - curcol = first; - calc_mobile_cols(&last); - /* restore/adjust curcol */ - curcol = curcol_orig; - if (curcol > last) - curcol = last; - unselect_ranges(); - } -} - - -/** - * \brief TODO Document left_limit() - * - * \return lookat - */ -struct ent * left_limit() { - int c = 0; - while ( col_hidden[c] && c < curcol ) c++; - return lookat(currow, c); -} - - -/** - * \brief right_limit() - * \details get the last valid cell to the right - * \param[in] row where to check - * \return lookat - */ -struct ent * right_limit(int row) { - register struct ent *p; - int c = maxcols - 1; - while ( (! VALID_CELL(p, row, c) && c > 0) || col_hidden[c]) c--; - return lookat(row, c); -} - - -/** - * \brief TODO Document goto_top() - * - * \return lookat - */ -struct ent * goto_top() { - int r = 0; - while ( row_hidden[r] && r < currow ) r++; - return lookat(r, curcol); -} - - -/** - * \brief TODO Document goto_bottom() - * - * \return lookat - */ -// FIXME to handle freeze rows/cols -struct ent * goto_bottom() { - register struct ent *p; - int r = maxrows - 1; - while ( (! VALID_CELL(p, r, curcol) && r > 0) || row_hidden[r]) r--; - return lookat(r, curcol); -} - - -/** - * \brief TODO Document goto_last_col() - * traverse the table and see which is the max column that has content - * this is because maxcol changes when moving cursor. - * this function is used when exporting files - * \return lookat - */ -struct ent * goto_last_col() { - int r, mr = maxrows; - int c, mc = 0; - register struct ent *p; - int rf = 0; - - for (r=0; r= mc && VALID_CELL(p, r, c)) { mc = c; rf = r; } - } - } - return lookat(rf, mc); -} - - -/** - * @brief TODO Document go_forward() - * - * \return lookat - */ -struct ent * go_forward() { - int r = currow, c = curcol; - int r_ori = r, c_ori = c; - register struct ent * p; - do { - if (c < maxcols - 1) { - c++; - } else { - if (r < maxrows - 1) { - r++; - c = 0; - } else break; - } - if (VALID_CELL(p, r, c) && ! col_hidden[c] && ! row_hidden[r] ) - return lookat(r, c); - } while (r < maxrows || c < maxcols); - - return lookat(r_ori, c_ori); -} - - -/** - * \brief TODO Document go_bol() - * - * \return lookat - */ -struct ent * go_bol() { - return lookat(currow, offscr_sc_cols); -} - - -/** - * \brief TODO Document go_eol() - * \return none - */ -struct ent * go_eol() { - int last_col; - calc_mobile_cols(&last_col); - return lookat(currow, last_col); -} - - -/** - * \brief TODO Document horiz_middle() - * \return lookat; NULL otherwise - */ -struct ent * horiz_middle() { - int i; - int midscreen_pos = (COLS - rescol - 1)/2; - int curr_pos = 0; - int mobile_cols = calc_mobile_cols(NULL); - - for (i = 0; i < maxcols; i++) { - if (col_hidden[i]) - continue; - if (! col_frozen[i]) { - if (i < offscr_sc_cols) - continue; - if (--mobile_cols < 0) - continue; - } - - /* compare middle of current col against middle of screen */ - if (curr_pos + (fwidth[i] - 1)/2 >= midscreen_pos) - return lookat(currow, i); - - curr_pos += fwidth[i]; - } - return NULL; -} - - -/** - * \brief TODO Document go_backward() - * - * \return lookat - */ -struct ent * go_backward() { - int r = currow, c = curcol; - int r_ori = r, c_ori = c; - register struct ent * p; - do { - if (c) - c--; - else { - if (r) { - r--; - c = maxcols - 1; - } else break; - } - if ( VALID_CELL(p, r, c) && ! col_hidden[c] && ! row_hidden[r] ) - return lookat(r, c); - } while ( currow || curcol ); - - return lookat(r_ori, c_ori); -} - - -/** - * \brief TODO Document auto_justify() - * - * \param[in] ci - * \param[in] cf - * \param[in] min - * - * \return none - */ -void auto_justify(int ci, int cf, int min) { - // column width is not set below the min value - int r, c, sum = 0; - char field[1024] = ""; - struct ent * p; - wchar_t widestring[BUFFERSIZE] = { L'\0' }; - mbstate_t state; - size_t result; - const char * mbsptr; - -#ifdef UNDO - create_undo_action(); -#endif - - checkbounds(&maxrow, &cf); - - for (c = ci; c <= cf; c++) { -#ifdef UNDO - add_undo_col_format(c, 'R', fwidth[c], precision[c], realfmt[c]); -#endif - fwidth[c] = min; - for (r = 0; r <= maxrow; r++) { - if ((p = *ATBL(tbl, r, c)) != NULL) { - sum = 0; - if (p->pad) sum += p->pad; - if (p->label) { - memset( &state, '\0', sizeof state ); - mbsptr = p->label; - result = mbsrtowcs(widestring, &mbsptr, BUFFERSIZE, &state); - if ( result != (size_t)-1 ) - sum += wcswidth(widestring, wcslen(widestring)); - } - if (p->flags & is_valid) { - sprintf(field, "%.*f", precision[c], p->v); - sum += strlen(field); - } - if (sum > fwidth[c] && sum < COLS-rescol) - fwidth[c] = sum; - } - } -#ifdef UNDO - add_undo_col_format(c, 'A', fwidth[c], precision[c], realfmt[c]); -#endif - } -#ifdef UNDO - end_undo_action(); -#endif - - return; -} - - -/** - * \brief Delete a cell expression and turn into constant - * - * \details Deletes the expression associated with a cell and - * turns it into a constant containing whatever was on the screen. - * - * \param[in] sr - * \param[in] sc - * \param[in] er - * \param[in] ec - * - * \return none - */ -void valueize_area(int sr, int sc, int er, int ec) { - int r, c; - struct ent *p; - - if (sr > er) { - r = sr; sr = er; er= r; - } - - if (sc > ec) { - c = sc; sc = ec; ec= c; - } - - if (sr < 0) - sr = 0; - if (sc < 0) - sc = 0; - checkbounds(&er, &ec); - - #ifdef UNDO - create_undo_action(); - copy_to_undostruct(sr, sc, er, ec, UNDO_DEL, IGNORE_DEPS, NULL); - #endif - for (r = sr; r <= er; r++) { - for (c = sc; c <= ec; c++) { - p = *ATBL(tbl, r, c); - if (p && p->flags & is_locked) { - sc_error(" Cell %s%d is locked", coltoa(c), r); - continue; - } - if (p && p->expr) { - efree(p->expr); - p->expr = (struct enode *)0; - p->flags &= ~is_strexpr; - - // TODO move this to depgraph ? - vertexT * v_cur = getVertex(graph, p, 0); - if (v_cur != NULL) { // just in case - - // for each edge in edges, we look for the reference to the vertex we are deleting, and we erase it! - edgeT * e = v_cur->edges; - while (e != NULL) { // && v_cur->back_edges == NULL) { - delete_reference(v_cur, e->connectsTo, 1); - - // delete vertex only if it end up having no edges, no expression, no value, no label.... - if (e->connectsTo->edges == NULL && e->connectsTo->back_edges == NULL && !e->connectsTo->ent->expr && !(e->connectsTo->ent->flags & is_valid) && ! e->connectsTo->ent->label) - destroy_vertex(e->connectsTo->ent); - // WARNING: an orphan vertex now represents an ent that has an enode thats - // need to be evaluated, but do not depend in another cell. - e = e->next; - } - - destroy_list_edges(v_cur->edges); - v_cur->edges = NULL; - - /* delete vertex in graph - only if this vertex is not referenced by other */ - if (v_cur->back_edges == NULL ) destroy_vertex(p); - } - } - } - } - #ifdef UNDO - copy_to_undostruct(sr, sc, er, ec, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); - #endif - sc_info("Removed formulas from range"); - return; -} - - -/** - * \brief TODO Document select_inner_range() - * \param[in] vir_tlrow - * \param[in] vir_tlcol - * \param[in] vir_brrow - * \param[in] vir_brcol - * \return none - */ -void select_inner_range(int * vir_tlrow, int * vir_tlcol, int * vir_brrow, int * vir_brcol) { - struct ent * p; - int rr, cc, r, c, mf = 1; - - while (mf != 0) { - mf = 0; - for (rr = *vir_tlrow; rr <= *vir_brrow; rr++) { - for (cc = *vir_tlcol; cc <= *vir_brcol; cc++) - for (r=-1; r<=1; r++) - for (c=-1; c<=1; c++) { - if (r == 0 && c == 0) continue; - else if (rr + r < 0 || cc + c < 0 || rr + r > maxrow || cc + c > maxcol) continue; - p = *ATBL(tbl, rr + r, cc + c); - if ( p != NULL && (p->label || p->flags & is_valid) ) { - if (*vir_brcol < cc + c) { - *vir_brcol = cc + c; - mf=1; - } - if (*vir_brrow < rr + r) { - *vir_brrow = rr + r; - mf=1; - } - if (*vir_tlcol > cc + c) { - *vir_tlcol = cc + c; - mf=1; - } - if (*vir_tlrow > rr + r) { - *vir_tlrow = rr + r; - mf = 1; - } - } - } - if (mf) break; - } // rr - } - return; -} - - -/** - * \brief Check if cell is locked - * - * \return 1 if cell if locked; 0 otherwise - */ -int locked_cell(int r, int c) { - struct ent *p = *ATBL(tbl, r, c); - if (p && (p->flags & is_locked)) { - sc_error("Cell %s%d is locked", coltoa(c), r) ; - return 1; - } - return 0; -} - - -/** - * \brief Check if area contains locked cells - * - * \param[in] r1 - * \param[in] c1 - * \param[in] r2 - * \param[in] c2 - * - * \return 1 if area contains a locked cell; 0 otherwise - */ -int any_locked_cells(int r1, int c1, int r2, int c2) { - int r, c; - struct ent * p ; - - for (r = r1; r <= r2; r++) - for (c = c1; c <= c2; c++) { - p = *ATBL(tbl, r, c); - if (p && (p->flags & is_locked)) - return 1; - } - return 0; -} - - -/** - * \brief sum special command - * \return none - */ -int fsum() { - int r = currow, c = curcol; - struct ent * p; - - if (r > 0 && (*ATBL(tbl, r-1, c) != NULL) && (*ATBL(tbl, r-1, c))->flags & is_valid) { - for (r = currow-1; r >= 0; r--) { - p = *ATBL(tbl, r, c); - if (p == NULL) break; - if (! (p->flags & is_valid)) break; - } - if (currow != r) { - swprintf(interp_line, BUFFERSIZE, L"let %s%d = @SUM(", coltoa(curcol), currow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d:", coltoa(curcol), r+1); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d)", coltoa(curcol), currow-1); - } - } else if (c > 0 && (*ATBL(tbl, r, c-1) != NULL) && (*ATBL(tbl, r, c-1))->flags & is_valid) { - for (c = curcol-1; c >= 0; c--) { - p = *ATBL(tbl, r, c); - if (p == NULL) break; - if (! (p->flags & is_valid)) break; - } - if (curcol != c) { - swprintf(interp_line, BUFFERSIZE, L"let %s%d = @SUM(", coltoa(curcol), currow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d:", coltoa(c+1), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d)", coltoa(curcol-1), r); - } - } - - if ((currow != r || curcol != c) && wcslen(interp_line)) - send_to_interp(interp_line); - EvalRange(currow, curcol, currow, curcol); - return 0; -} - - -/** - * \brief fcopy special command - * \param[in] action - * \return -1 on error; 0 otherwise - */ -int fcopy(char * action) { - int r, ri, rf, c, ci, cf; - struct ent * pdest; - struct ent * pact; - int p = is_range_selected(); - struct srange * sr = NULL; - if (p != -1) sr = get_range_by_pos(p); - - if (p == -1) { // no range selected - // fail if the cursor is on the first column - if (curcol == 0) { - sc_error("Can't fcopy with no arguments while on column 'A'"); - return -1; - } - - ri = currow; - ci = curcol; - cf = curcol; - for (r=ri+1; rflags & is_valid ; r++) {} - rf = --r; - } else { // range is selected - ri = sr->tlrow; - ci = sr->tlcol; - cf = sr->brcol; - rf = sr->brrow; - } - - // check if all cells that will be copied to somewhere have a formula in them - if (! strcmp(action, "") || ! strcmp(action, "cells")) { - if (! *ATBL(tbl, ri, ci) ) goto formula_not_found; - if (! (*ATBL(tbl, ri, ci))->expr) goto formula_not_found; - } else if (! strcmp(action, "c") || ! strcmp(action, "columns")) { - for (c=ci; c<=cf; c++) { - if (! *ATBL(tbl, ri, c) ) goto formula_not_found; - if (! (*ATBL(tbl, ri, c))->expr) goto formula_not_found; - } - } else if (! strcmp(action, "r") || ! strcmp(action, "rows")) { - for (r=ri; r<=rf; r++) { - if (! *ATBL(tbl, r, ci) ) goto formula_not_found; - if (! (*ATBL(tbl, r, ci))->expr) goto formula_not_found; - } - } else { - sc_error("Invalid parameter"); - } - - goto all_formulas_found; - - formula_not_found: - sc_error("At least 1 formula not found. Nothing changed"); - return -1; - - all_formulas_found: - - if (any_locked_cells(ri, ci, rf, cf)) { - swprintf(interp_line, BUFFERSIZE, L""); - sc_error("Locked cells encountered. Nothing changed"); - return -1; - } -#ifdef UNDO - create_undo_action(); - copy_to_undostruct(ri, ci, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); -#endif - - if (! strcmp(action, "")) { - // copy first column down (old behavior), for backwards compatibility - pact = *ATBL(tbl, ri, ci); - for (r=ri+1; r<=rf; r++) { - pdest = lookat(r, ci); - copyent(pdest, pact, r - ri, 0, 0, 0, maxrows, maxcols, 'c'); - } - } else if (! strcmp(action, "c") || ! strcmp(action, "columns")) { - // copy all selected columns down - for (c=ci; c<=cf; c++) { - pact = *ATBL(tbl, ri, c); - for (r=ri+1; r<=rf; r++) { - pdest = lookat(r, c); - copyent(pdest, pact, r - ri, 0, 0, 0, maxrows, maxcols, 'c'); - } - } - } else if (! strcmp(action, "r") || ! strcmp(action, "rows")) { - // copy all selected rows right - for (r=ri; r<=rf; r++) { - pact = *ATBL(tbl, r, ci); - for (c=ci+1; c<=cf; c++) { - pdest = lookat(r, c); - copyent(pdest, pact, 0, c - ci, 0, 0, maxrows, maxcols, 'c'); - } - } - } else if (! strcmp(action, "cells")) { - // copy selected cell down and right - pact = *ATBL(tbl, ri, ci); - for (r=ri; r<=rf; r++) { - for(c=(r==ri?ci+1:ci); c<=cf; c++) { - pdest = lookat(r, c); - copyent(pdest, pact, r - ri, c - ci, 0, 0, maxrows, maxcols, 'c'); - } - } - } - EvalRange(ri, ci, rf, cf); - -#ifdef UNDO - copy_to_undostruct(ri, ci, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); -#endif - - return 0; -} - - -/** - * \brief Add padding to cells - * - * \details Add padding to cells. This set padding of a range. - * - * \return -1 if locked cell is encountered; 1 if padding exceeded - * column width; 0 otherwise - */ -int pad(int n, int r1, int c1, int r2, int c2) { - int r, c; - struct ent * p ; - int pad_exceed_width = 0; - - if (any_locked_cells(r1, c1, r2, c2)) { - sc_info("Locked cells encountered. Nothing changed"); - return -1; - } - -#ifdef UNDO - create_undo_action(); - copy_to_undostruct(r1, c1, r2, c2, UNDO_DEL, IGNORE_DEPS, NULL); -#endif - - for (r = r1; r <= r2; r++) { - for (c = c1; c <= c2; c++) { - if (n > fwidth[c]) { - pad_exceed_width = 1; - continue; - } - if ((p = *ATBL(tbl, r, c)) != NULL) p->pad = n; - modflg++; - } - } - -#ifdef UNDO - copy_to_undostruct(r1, c1, r2, c2, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); -#endif - - if (pad_exceed_width) { - sc_error(" Could not add padding in some cells. Padding exceeded column width"); - return 1; - } - return 0; -} - - -/** - * \brief fix_row_hidden - * \details fix hidden rows after undoing ir dr etc.. - * \return none - */ -void fix_row_hidden(int deltar, int ri, int rf) { - int r; - int d = deltar; - - // decrease / for dr - if (deltar > 0) - while (d-- > 0) - for (r = ri; r < rf; r++) - row_hidden[r] = row_hidden[r+1]; - - // increase / for ir - if (deltar < 0) - while (d++ < 0) - for (r = rf; r > ri; r--) - row_hidden[r] = row_hidden[r-1]; - return; -} - - -/** - * \brief fix_col_hidden - * \details fix hidden cols after undoing ic dc etc.. - * \return none - */ -void fix_col_hidden(int deltac, int ci, int cf) { - int c; - int d = deltac; - - // decrease / for dc - if (deltac > 0) - while (d-- > 0) - for (c = ci; c < cf; c++) - col_hidden[c] = col_hidden[c+1]; - - // increase / for ic - if (deltac < 0) - while (d++ < 0) - for (c = cf; c > ci; c--) - col_hidden[c] = col_hidden[c-1]; - return; -} - - -/** - * \brief fix_row_frozen - * \details fix frozen rows after undoing ir dr etc.. - * \return none - */ -void fix_row_frozen(int deltar, int ri, int rf) { - int r; - int d = deltar; - - // decrease / for dr - if (deltar > 0) - while (d-- > 0) - for (r = ri; r < rf; r++) - row_frozen[r] = row_frozen[r+1]; - - // increase / for ir - if (deltar < 0) - while (d++ < 0) - for (r = rf; r > ri; r--) - row_frozen[r] = row_frozen[r-1]; - return; -} - - -/** - * \brief fix_col_frozen - * \details fix frozen cols after undoing ic dc etc.. - * \return none - */ -void fix_col_frozen(int deltac, int ci, int cf) { - int c; - int d = deltac; - - // decrease / for dc - if (deltac > 0) - while (d-- > 0) - for (c = ci; c < cf; c++) - col_frozen[c] = col_frozen[c+1]; - - // increase / for ic - if (deltac < 0) - while (d++ < 0) - for (c = cf; c > ci; c--) - col_frozen[c] = col_frozen[c-1]; - return; -} - - -/** - * \brief Compute number of mobile (unfrozen) rows to fit on screen - * - * \details This function finds the number of mobile rows that can fit on - * the screen. This number excludes frozen rows as they never leave the - * screen hence their total height is subtracted from the available screen - * area. This number also excludes hidden rows. Displayed mobile rows are - * considered starting from offscr_sc_rows, however currow must be within - * the displayed rows. If currow is found to be outside the displayed set - * of rows then offscr_sc_rows is adjusted accordingly. - * - * \param[in] last_p If not NULL then the last mobile row to fit is stored there - * - * \return Number of mobile rows displayable on the screen - */ -int calc_mobile_rows(int *last_p) { - int i, row_space, mobile_rows, last; - - /* - * Compute the number of frozen rows and the space they need. - * Eventually this should be added/subtracted when individual rows - * are frozen/unfrozen/enlarged/reduced/deleted and not recomputed - * every time here... or at least have a global flag indicating that - * nothing has changed and that this loop can be skipped. - */ - nb_frozen_rows = 0; - nb_frozen_screenrows = 0; - for (i = 0; i < maxrows; i++) { - if (row_hidden[i]) - continue; - if (row_frozen[i]) { - nb_frozen_rows++; - nb_frozen_screenrows += row_format[i]; - } - } - - /* Adjust display start if currow is above it */ - if (currow < offscr_sc_rows) - offscr_sc_rows = currow; - - /* Determine the space available for mobile rows. */ - row_space = LINES - RESROW - RESCOLHEADER - nb_frozen_screenrows; - - /* - * Find how many visible mobile rows can fit in there - * and remember which one is the last to fit. - */ - mobile_rows = 0; - last = offscr_sc_rows; - for (i = offscr_sc_rows; i < maxrows; i++) { - if (row_hidden[i]) - continue; - if (row_frozen[i]) - continue; - if (row_format[i] > row_space) - break; - row_space -= row_format[i]; - mobile_rows++; - last = i; - } - - /* - * If currow is beyond the last row here then we must start over, - * moving backward this time, to properly position start of display. - */ - if (last < currow) { - row_space = LINES - RESROW - RESCOLHEADER - nb_frozen_screenrows; - mobile_rows = 0; - last = currow; - for (i = currow; i >= 0; i--) { - if (row_hidden[i]) - continue; - if (row_frozen[i]) - continue; - if (row_format[i] > row_space) - break; - row_space -= row_format[i]; - mobile_rows++; - last = i; - } - offscr_sc_rows = last; - } - - if (last_p) - *last_p = last; - return mobile_rows; -} - -/** - * \brief Compute number of mobile (unfrozen) columns to fit on screen - * - * \details This function finds the number of mobile columns that can fit on - * the screen. This number excludes frozen columns as they never leave the - * screen, hence their total height is subtracted from the available screen - * area. This number also excludes hidden columns. Displayed mobile columnss - * are considered starting from offscr_sc_cols, however curcol must be within - * the displayed columns. If curcol is found to be outside the displayed set - * of columns then offscr_sc_cols is adjusted accordingly. - * - * \param[in] last_p If not NULL then the last mobile column to fit is stored there - * - * \return Number of mobile columns displayable on the screen - */ -int calc_mobile_cols(int *last_p) { - int i, col_space, mobile_cols, last; - - /* - * Compute the number of frozen columns and the space they need. - * Eventually this should be added/subtracted when individual - * columns are frozen/unfrozen/enlarged/reduced/deleted and not - * recomputed every time here... or at least have a flag indicating - * that nothing has changed and that this loop may be skipped. - */ - nb_frozen_cols = 0; - nb_frozen_screencols = 0; - for (i = 0; i < maxcols; i++) { - if (row_frozen[i]) - continue; - if (col_frozen[i]) { - nb_frozen_cols++; - nb_frozen_screencols += fwidth[i]; - } - } - - /* Adjust display start if curcol is left of it */ - if (curcol < offscr_sc_cols) - offscr_sc_cols = curcol; - - /* Determine the space available for mobile columns. */ - col_space = COLS - rescol - nb_frozen_screencols; - - /* - * Find how many visible mobile columns can fit in there - * and remember which one is the last to fit. - */ - mobile_cols = 0; - last = offscr_sc_cols; - for (i = offscr_sc_cols; i < maxcols; i++) { - if (col_hidden[i]) - continue; - if (col_frozen[i]) - continue; - if (fwidth[i] > col_space) - break; - col_space -= fwidth[i]; - mobile_cols++; - last = i; - } - - /* - * If curcol is beyond the last column here then we start over, - * moving backward this time, to properly position start of display. - */ - if (last < curcol) { - col_space = COLS - rescol - nb_frozen_screencols; - mobile_cols = 0; - last = curcol; - for (i = curcol; i >= 0; i--) { - if (col_hidden[i]) - continue; - if (col_frozen[i]) - continue; - if (fwidth[i] > col_space) - break; - col_space -= fwidth[i]; - mobile_cols++; - last = i; - } - offscr_sc_cols = last; - } - - if (last_p) - *last_p = last; - return mobile_cols; -} - - -/** - * \brief pad_and_align - * - * \details This function aligns text of a cell (align = 0 center, - * align = 1 right, align = -1 left). Also adds padding between cells. - * - * \param[in] srt_value - * \param[in] numeric_value - * \param[in] col_width - * \param[in] align - * \param[in] padding - * \param[in] str_out - * \param[in] rowfmt: rowheight - * - * \return resulting string to be printed to the screen - */ -void pad_and_align (char * str_value, char * numeric_value, int col_width, int align, int padding, wchar_t * str_out, int rowfmt) { - int str_len = 0; - int num_len = strlen(numeric_value); - str_out[0] = L'\0'; - - wchar_t wcs_value[BUFFERSIZE] = { L'\0' }; - mbstate_t state; - size_t result; - char * str_in; - - // Here we handle \" and replace them with " - str_in = str_replace(str_value, "\\\"", "\""); - - const char * mbsptr; - mbsptr = str_in; - - // create wcs string based on multibyte string.. - memset( &state, '\0', sizeof state ); - result = mbsrtowcs(wcs_value, &mbsptr, BUFFERSIZE, &state); - if ( result != (size_t)-1 ) - str_len = wcswidth(wcs_value, wcslen(wcs_value)); - - if (str_len == 2 && str_in[0] == '\\') { - wmemset(str_out + wcslen(str_out), str_in[1], col_width); - free(str_in); - return; - } else if (str_len == 3 && str_in[0] == '\\' && str_in[1] == '\\') { - wmemset(str_out + wcslen(str_out), str_in[2], col_width); - free(str_in); - return; - } - - // If padding exceedes column width, returns n number of '-' needed to fill column width - if (padding >= col_width ) { - wmemset(str_out + wcslen(str_out), L' ', col_width); - free(str_in); - return; - } - - // If content exceedes column width, outputs n number of '*' needed to fill column width - if (str_len + num_len + padding > col_width * rowfmt && ! get_conf_int("truncate") && - ! get_conf_int("overlap") && ! get_conf_int("autowrap")) { - if (padding) wmemset(str_out + wcslen(str_out), L' ', padding); - wmemset(str_out + wcslen(str_out), L'*', col_width - padding); - free(str_in); - return; - } - - // padding - if (padding) swprintf(str_out, BUFFERSIZE, L"%*ls", padding, L""); - - // left spaces - int left_spaces = 0; - if (align == 0) { // center align - left_spaces = (col_width - padding - str_len) / 2; - if (num_len > left_spaces) left_spaces = col_width - padding - str_len - num_len; - } else if (align == 1 && str_len && ! num_len) { // right align - left_spaces = col_width - padding - str_len; - } - while (left_spaces-- > 0) add_wchar(str_out, L' ', wcslen(str_out)); - - // add text - if (align != 1 || ! num_len) - swprintf(str_out + wcslen(str_out), BUFFERSIZE, L"%s", str_in); - - // spaces after string value - int spaces = col_width - padding - str_len - num_len; - if (align == 1){ - if(num_len) spaces += str_len; - else spaces = 0; - } - if (align == 0) spaces -= (col_width - padding - str_len) / 2; - while (spaces-- > 0) add_wchar(str_out, L' ', wcslen(str_out)); - - // add number - int fill_with_number = col_width - str_len - padding; - if (num_len && num_len >= fill_with_number) { - swprintf(str_out + wcslen(str_out), BUFFERSIZE, L"%.*s", fill_with_number, & numeric_value[num_len - fill_with_number]); - } else if (num_len) { - swprintf(str_out + wcslen(str_out), BUFFERSIZE, L"%s", numeric_value); - } - - // Similar condition to max width '*' condition above, but just trims instead - if (str_len + num_len + padding > col_width * rowfmt && get_conf_int("truncate")) { - str_out[col_width] = '\0'; - } - - // on each \n chars, replace with n number of L' ' to complete column width - int posnl, leftnl = 0; - while ((posnl = wstr_in_wstr(str_out, L"\\n")) != -1) { - del_range_wchars(str_out, posnl, posnl+1); - if (posnl <= col_width) leftnl = col_width - posnl; - else leftnl = col_width - posnl % col_width; - while (leftnl-- > 0) add_wchar(str_out, L' ', posnl); - } - - free(str_in); - return; -} - - -/** - * \brief Check if the buffer content is a valid command - * - * \details Check if the buffer content is a valid command - * result = 0 or NO_CMD : buf has no command - * result = 1 or EDITION_CMD : buf has a command - * result = 2 or MOVEMENT_CMD : buf has a movement command or a command that do not - * change cell content, and should not be considered by the '.' command - * - * \return result - */ -int is_single_command (struct block * buf, long timeout) { - if (buf->value == L'\0') return NO_CMD; - int result = NO_CMD; - int bs = get_bufsize(buf); - - if (curmode == COMMAND_MODE && bs == 1 && ( buf->value != ctl('r') || - buf->value == ctl('v')) ) { - result = MOVEMENT_CMD; - - } else if ( curmode == COMMAND_MODE && bs == 2 && buf->value == ctl('r') && - (buf->pnext->value - (L'a' - 1) < 1 || buf->pnext->value > 26)) { - result = MOVEMENT_CMD; - - } else if (curmode == INSERT_MODE && bs == 1 && ( buf->value != ctl('r') || - buf->value == ctl('v')) ) { - result = MOVEMENT_CMD; - - } else if (curmode == INSERT_MODE && bs == 2 && buf->value == ctl('r') && - (buf->pnext->value - (L'a' - 1) < 1 || buf->pnext->value > 26)) { - result = MOVEMENT_CMD; - - } else if (curmode == EDIT_MODE && bs == 1) { - result = MOVEMENT_CMD; - - } else if (curmode == NORMAL_MODE && bs == 1) { - // commands for changing mode - if (buf->value == L':') result = MOVEMENT_CMD; - else if (buf->value == L'\\') result = MOVEMENT_CMD; - else if (buf->value == L'<') result = MOVEMENT_CMD; - else if (buf->value == L'>') result = MOVEMENT_CMD; - else if (buf->value == L'=') result = MOVEMENT_CMD; - else if (buf->value == L'e') result = MOVEMENT_CMD; - else if (buf->value == L'E') result = MOVEMENT_CMD; - else if (buf->value == L'v') result = MOVEMENT_CMD; - - else if (buf->value == L'Q') result = MOVEMENT_CMD; /* FOR TEST PURPOSES */ - else if (buf->value == L'A') result = MOVEMENT_CMD; /* FOR TEST PURPOSES */ - else if (buf->value == L'W') result = MOVEMENT_CMD; /* FOR TEST PURPOSES */ - - // movement commands - else if (buf->value == L'j') result = MOVEMENT_CMD; - else if (buf->value == L'k') result = MOVEMENT_CMD; - else if (buf->value == L'h') result = MOVEMENT_CMD; - else if (buf->value == L'l') result = MOVEMENT_CMD; - else if (buf->value == L'0') result = MOVEMENT_CMD; - else if (buf->value == L'$') result = MOVEMENT_CMD; - else if (buf->value == OKEY_HOME) result = MOVEMENT_CMD; - else if (buf->value == OKEY_END) result = MOVEMENT_CMD; - else if (buf->value == L'#') result = MOVEMENT_CMD; - else if (buf->value == L'^') result = MOVEMENT_CMD; - else if (buf->value == OKEY_LEFT) result = MOVEMENT_CMD; - else if (buf->value == OKEY_RIGHT) result = MOVEMENT_CMD; - else if (buf->value == OKEY_DOWN) result = MOVEMENT_CMD; - else if (buf->value == OKEY_UP) result = MOVEMENT_CMD; - else if (buf->value == OKEY_PGUP) result = MOVEMENT_CMD; - else if (buf->value == OKEY_PGDOWN) result = MOVEMENT_CMD; - else if (buf->value == ctl('f')) result = MOVEMENT_CMD; - else if (buf->value == ctl('j')) result = EDITION_CMD; - else if (buf->value == ctl('d')) result = EDITION_CMD; - else if (buf->value == ctl('b')) result = MOVEMENT_CMD; - else if (buf->value == ctl('a')) result = MOVEMENT_CMD; - else if (buf->value == L'G') result = MOVEMENT_CMD; - else if (buf->value == L'H') result = MOVEMENT_CMD; - else if (buf->value == L'M') result = MOVEMENT_CMD; - else if (buf->value == L'L') result = MOVEMENT_CMD; - else if (buf->value == ctl('y')) result = MOVEMENT_CMD; - else if (buf->value == ctl('e')) result = MOVEMENT_CMD; - else if (buf->value == ctl('l')) result = MOVEMENT_CMD; - else if (buf->value == L'w') result = MOVEMENT_CMD; - else if (buf->value == L'b') result = MOVEMENT_CMD; - else if (buf->value == L'/') result = MOVEMENT_CMD; // search - else if (buf->value == L'?') result = MOVEMENT_CMD; // search backwards - else if (buf->value == L'n') result = MOVEMENT_CMD; // repeat last goto cmd - else if (buf->value == L'N') result = MOVEMENT_CMD; // repeat last goto cmd - backwards - - // edition commands - else if (buf->value == L'x') result = EDITION_CMD; // cuts a cell - else if (buf->value == L'u') result = MOVEMENT_CMD; // undo - else if (buf->value == ctl('r')) result = MOVEMENT_CMD; // redo - else if (buf->value == L'@') result = EDITION_CMD; // EvalAll - else if (buf->value == L'{') result = EDITION_CMD; - else if (buf->value == L'}') result = EDITION_CMD; - else if (buf->value == L'|') result = EDITION_CMD; - else if (buf->value == L'p') result = EDITION_CMD; // paste yanked cells below or left - else if (buf->value == L't') result = EDITION_CMD; // paste yanked cells above or right - else if (buf->value == L'-') result = EDITION_CMD; - else if (buf->value == L'+') result = EDITION_CMD; - - else if (isdigit(buf->value) && get_conf_int("numeric") ) - result = MOVEMENT_CMD; // repeat last command - - else if (buf->value == L'.') result = MOVEMENT_CMD; // repeat last command - else if (buf->value == L'y' && is_range_selected() != -1) - result = EDITION_CMD; // yank range - - } else if (curmode == NORMAL_MODE) { - - if (buf->value == L'g' && bs == 2 && ( - buf->pnext->value == L'f' || - buf->pnext->value == L'M' || - buf->pnext->value == L'g' || - buf->pnext->value == L'G' || - buf->pnext->value == L'0' || - buf->pnext->value == L'l' || - buf->pnext->value == L'$')) - result = MOVEMENT_CMD; - - else if (buf->value == L'g' && bs > 3 && buf->pnext->value == L't' && timeout >= COMPLETECMDTIMEOUT) - result = MOVEMENT_CMD; // goto cell - // TODO add validation: buf->pnext->pnext->value must be a letter - - else if (buf->value == L'P' && bs == 2 && ( - buf->pnext->value == L'v' || - buf->pnext->value == L'f' || - buf->pnext->value == L'c' ) ) result = EDITION_CMD; // paste yanked cells below or left - - else if (buf->value == L'T' && bs == 2 && ( - buf->pnext->value == L'v' || - buf->pnext->value == L'f' || - buf->pnext->value == L'c' ) ) result = EDITION_CMD; // paste yanked cells above or right - - else if (buf->value == L'a' && bs == 2 && // autojus - buf->pnext->value == L'a') result = EDITION_CMD; - - else if (buf->value == L'Z' && bs == 2 && timeout >= COMPLETECMDTIMEOUT && // Zap (or hide) col or row - ( buf->pnext->value == L'c' || - buf->pnext->value == L'r')) result = EDITION_CMD; - - else if (buf->value == L'S' && bs == 2 && timeout >= COMPLETECMDTIMEOUT && // Zap (or hide) col or row - ( buf->pnext->value == L'c' || - buf->pnext->value == L'r')) result = EDITION_CMD; - - else if (buf->value == L'y' && bs == 2 && // yank cell - ( buf->pnext->value == L'y' || - buf->pnext->value == L'r' || - buf->pnext->value == L'c') ) result = EDITION_CMD; - - else if (buf->value == L'm' && bs == 2 && // mark - ((buf->pnext->value - (L'a' - 1)) < 1 || - buf->pnext->value > 26)) result = MOVEMENT_CMD; - - else if (buf->value == L'c' && bs == 2 && // mark - ((buf->pnext->value - (L'a' - 1)) < 1 || buf->pnext->value > 26)) result = EDITION_CMD; - - else if (buf->value == L'z' && bs == 2 && // scrolling - ( buf->pnext->value == L'h' || - buf->pnext->value == L'l' || - buf->pnext->value == L'z' || - buf->pnext->value == L'm' || - buf->pnext->value == L'.' || - buf->pnext->value == L't' || - buf->pnext->value == L'b' || - buf->pnext->value == L'H' || - buf->pnext->value == L'L') - ) result = MOVEMENT_CMD; - - else if (buf->value == L'V' && bs == 3 && // Vir - buf->pnext->value == L'i' && - buf->pnext->pnext->value == L'r') - result = MOVEMENT_CMD; - - else if (buf->value == L'd' && bs == 2 && // cuts a cell - buf->pnext->value == L'd') result = EDITION_CMD; - - else if (buf->value == L'\'' && bs == 2 && // tick - ((buf->pnext->value - (L'a' - 1)) < 1 || - buf->pnext->value > 26)) result = MOVEMENT_CMD; - - else if (buf->value == L's' && bs == 2 && // shift cell down or up - ( buf->pnext->value == L'j' || - buf->pnext->value == L'k' || - buf->pnext->value == L'h' || - buf->pnext->value == L'l')) result = EDITION_CMD; - - else if (buf->value == L'i' && bs == 2 && // Insert row or column - ( buf->pnext->value == L'r' || - buf->pnext->value == L'c' )) result = EDITION_CMD; - - else if (buf->value == L'o' && bs == 2 && // Open row or column - ( buf->pnext->value == L'r' || - buf->pnext->value == L'c' )) result = EDITION_CMD; - - else if (buf->value == L'd' && bs == 2 && // Delete row or column - ( buf->pnext->value == L'r' || - buf->pnext->value == L'c' )) result = EDITION_CMD; - - else if (buf->value == L'r' && bs == 2 && // range lock / unlock / valueize - ( buf->pnext->value == L'l' || - buf->pnext->value == L'u' || - buf->pnext->value == L'v' )) result = EDITION_CMD; - - else if (buf->value == L'R' && bs == 3 && // Create range with two marks - // FIXME add better validation - ((buf->pnext->value - (L'a' - 1)) < 1 || - buf->pnext->value > 26) && - ((buf->pnext->pnext->value - (L'a' - 1)) < 1 || - buf->pnext->pnext->value > 26)) result = EDITION_CMD; - - else if (buf->value == L'f' && bs == 2 && // Format col - ( buf->pnext->value == L'>' || - buf->pnext->value == L'<' || - buf->pnext->value == L'h' || - buf->pnext->value == OKEY_LEFT || - buf->pnext->value == L'l' || - buf->pnext->value == OKEY_RIGHT || - buf->pnext->value == L'j' || - buf->pnext->value == OKEY_DOWN || - buf->pnext->value == L'k' || - buf->pnext->value == OKEY_UP || - buf->pnext->value == L'-' || - buf->pnext->value == L'+' || - buf->pnext->value == L'r' || // Freeze row / col / area - buf->pnext->value == L'c' || - buf->pnext->value == L'a' - ) - ) result = EDITION_CMD; - - } else if (curmode == VISUAL_MODE && bs == 1) { - if (buf->value == L'j' || - buf->value == OKEY_DOWN || - buf->value == L'k' || - buf->value == OKEY_UP || - buf->value == L'h' || - buf->value == OKEY_LEFT || - buf->value == L'l' || - buf->value == OKEY_RIGHT || - buf->value == L'$' || - buf->value == L'0' || - buf->value == L'#' || - buf->value == L'^' || - buf->value == L'y' || - buf->value == L'p' || - buf->value == L'P' || - buf->value == L'x' || - buf->value == L'w' || - buf->value == L'b' || - buf->value == L'H' || - buf->value == L'M' || - buf->value == L'L' || - buf->value == L'G' || - buf->value == ctl('f') || - buf->value == ctl('j') || - buf->value == ctl('d') || - buf->value == ctl('b') || - buf->value == ctl('a') || - buf->value == ctl('o') || - buf->value == ctl('k') || - buf->value == L':' - ) - result = MOVEMENT_CMD; - else if (buf->value == L'{' || - buf->value == L'}' || - buf->value == L'f' || - buf->value == L'|') - result = EDITION_CMD; - - } else if (curmode == VISUAL_MODE && bs == 2) { - if ((buf->value == L'\'') || - (buf->value == L'd' && - buf->pnext->value == L'd') || - (buf->value == L's' && ( - buf->pnext->value == L'h' || - buf->pnext->value == L'j' || - buf->pnext->value == L'k' || - buf->pnext->value == L'l' )) - ) { - result = MOVEMENT_CMD; - } else if ((buf->value == L'Z' && ( - buf->pnext->value == L'r' || - buf->pnext->value == L'c' )) || - (buf->value == L'S' && ( - buf->pnext->value == L'r' || - buf->pnext->value == L'c' )) ) { - result = EDITION_CMD; - } else if (buf->value == L'r' && ( - buf->pnext->value == L'l' || - buf->pnext->value == L'u' || - buf->pnext->value == L'v' )) { - result = EDITION_CMD; - } else if (buf->value == L'm' && // mark - ((buf->pnext->value - (L'a' - 1)) < 1 || - buf->pnext->value > 26)) { - result = MOVEMENT_CMD; - } - } - return result; -} diff -Nru sc-im-0.8.2+ds/src/cmds_command.c sc-im-0.8.3+ds/src/cmds_command.c --- sc-im-0.8.2+ds/src/cmds_command.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_command.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1169 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_command.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include -#include // for isprint() - -#ifndef NO_WORDEXP -#include -#endif - -#include "sc.h" // for rescol -#include "conf.h" -#include "cmds_command.h" -#include "cmds_edit.h" -#include "cmds.h" -#include "utils/string.h" -#include "utils/dictionary.h" -#include "tui.h" -#include "file.h" -#include "main.h" -#include "interp.h" -#include "hide_show.h" -#include "exec.h" -#include "help.h" -#include "marks.h" -#include "filter.h" -#include "maps.h" -#include "xls.h" -#include "xlsx.h" -#include "cmds_visual.h" -#include "plot.h" - -#ifdef UNDO -#include "undo.h" -#endif - -extern char * rev; -extern struct dictionary * user_conf_d; - -wchar_t inputline[BUFFERSIZE]; -extern wchar_t interp_line[BUFFERSIZE]; -int inputline_pos; /**< Position in window. Some chars has 2 chars width */ -// see https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms -int real_inputline_pos; /**< Real position in inputline */ - -static wchar_t * valid_commands[] = { -L"!", -L"addfilter", -L"autojus", -L"ccopy", -L"cellcolor", -L"cmap", -L"cnoremap", -L"color", -L"cpaste", -L"cunmap", -L"datefmt", -L"define_color", -L"delfilter", -L"delfilters", -L"e csv", -L"e! csv", -L"e mkd", -L"e! mkd", -L"e tab", -L"e! tab", -L"e tex", -L"e! tex", -L"e txt", -L"e! txt", -L"e xlsx", -L"e! xlsx", -L"fcopy", -L"file", -L"fill", -L"filteroff", -L"filteron", -L"format", -L"formatcol", -L"formatrow", -L"freezecol", -L"freezerow", -L"fsum", -L"h", -L"help", -L"hiddencols", -L"hiddenrows", -L"hidecol", -L"hiderow", -L"imap", -L"inoremap", -L"int", -L"iunmap", -L"load!", -L"load", -L"lock", -L"nmap", -L"nnoremap", -L"nunmap", -L"pad", -L"plot", -L"plotedit", -L"q!", -L"q", -L"quit!", -L"quit", -L"redefine_color", -L"refresh", -L"set", -L"showcol", -L"showcols", -L"showfilters", -L"showmaps", -L"showrow", -L"showrows", -L"sort", -L"strtonum", -L"subtotal", -L"trigger", -L"unformat", -L"unfreezecol", -L"unfreezerow", -L"unlock", -L"untrigger", -L"valueize", -L"version", -L"vmap", -L"vnoremap", -L"vunmap", -L"w", -L"wq", -L"x", -(wchar_t *) 0 -}; - -/** - * \brief TODO Document do_commandmode() - * - * \param[in] sb - * - * \return none - */ - -void do_commandmode(struct block * sb) { - - // If a visual selected range exists - int p = is_range_selected(); - struct srange * sr = NULL; - if (p != -1) sr = get_range_by_pos(p); - - - /* - * Normal KEY handlers for this MODE - */ - if (sb->value == OKEY_BS || sb->value == OKEY_BS2) { // BS - if ( ! wcslen(inputline) || ! real_inputline_pos ) return; - int l = wcwidth(inputline[real_inputline_pos - 1]); - real_inputline_pos--; - del_wchar(inputline, real_inputline_pos); - inputline_pos -= l; - ui_show_header(); - -#ifdef HISTORY_FILE - if (commandline_history->pos == 0) - del_wchar(get_line_from_history(commandline_history, commandline_history->pos), real_inputline_pos); // Clean history -#endif - ui_show_header(); - return; - - } else if (sb->value == OKEY_LEFT) { // LEFT - if (inputline_pos) { - real_inputline_pos--; - int l = wcwidth(inputline[real_inputline_pos]); - inputline_pos -= l; - } - ui_show_header(); - return; - - } else if (sb->value == OKEY_RIGHT) { // RIGHT - int max = wcswidth(inputline, wcslen(inputline)); - if (inputline_pos < max) { - int l = wcwidth(inputline[real_inputline_pos++]); - inputline_pos += l; - } - ui_show_header(); - return; - - } else if (sb->value == OKEY_DEL) { // DEL - if (inputline_pos > wcswidth(inputline, wcslen(inputline))) return; - del_wchar(inputline, real_inputline_pos); - -#ifdef HISTORY_FILE - if (commandline_history->pos == 0) - del_wchar(get_line_from_history(commandline_history, commandline_history->pos), real_inputline_pos); // Clean history -#endif - ui_show_header(); - return; - -#ifdef HISTORY_FILE - } else if (sb->value == OKEY_UP || sb->value == ctl('p') || // UP - sb->value == OKEY_DOWN || sb->value == ctl('n')) { // DOWN - - int delta = 0, k = 0, i, cmp; - if (sb->value == OKEY_UP || sb->value == ctl('p')) { // up - for (i=commandline_history->pos; -i+1 < commandline_history->len; i--, k--) - if (wcslen(get_line_from_history(commandline_history, 0))) { - if (! (cmp = wcsncmp(inputline, get_line_from_history(commandline_history, i-1), wcslen(get_line_from_history(commandline_history, 0))))) { - k--; - break; - } else if (commandline_history->len == 2-i && cmp) { - k=0; - break; - } - } else if (!wcslen(get_line_from_history(commandline_history, 0))) { - k--; - break; - } - } else if (sb->value == OKEY_DOWN || sb->value == ctl('n')) { // down - for (i=commandline_history->pos; i != 0; i++, k++) - if (wcslen(get_line_from_history(commandline_history, 0))) { - if (! (cmp = wcsncmp(inputline, get_line_from_history(commandline_history, i+1), wcslen(get_line_from_history(commandline_history, 0))))) { - k++; - break; - } else if (commandline_history->pos == 0 && cmp) { - k=0; - break; - } - } else if (!wcslen(get_line_from_history(commandline_history, 0))) { - k++; - break; - } - } - delta += k; - commandline_history->pos += delta; - wcscpy(inputline, get_line_from_history(commandline_history, commandline_history->pos)); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; -#endif - - } else if (sb->value == ctl('v') ) { // VISUAL SUBMODE - visual_submode = ':'; - chg_mode('v'); - start_visualmode(currow, curcol, currow, curcol); - return; - - } else if (sb->value == ctl('r') && get_bufsize(sb) == 2 && // C-r // FIXME ??? - (sb->pnext->value - (L'a' - 1) < 1 || sb->pnext->value > 26)) { - wchar_t cline [BUFFERSIZE]; - int i, r = get_mark(sb->pnext->value)->row; - if (r != -1) { - swprintf(cline, BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->col), r); - } else { - swprintf(cline, BUFFERSIZE, L"%s%d:", coltoa(get_mark(sb->pnext->value)->rng->tlcol), get_mark(sb->pnext->value)->rng->tlrow); - swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->rng->brcol), get_mark(sb->pnext->value)->rng->brrow); - } - for(i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]); - -#ifdef HISTORY_FILE - if (commandline_history->pos == 0) { // Only if editing the new command - wchar_t * sl = get_line_from_history(commandline_history, 0); - wcscat(sl, cline); // Insert into history - } -#endif - ui_show_header(); - return; - - } else if (sb->value == ctl('f')) { // C-f - wchar_t cline [BUFFERSIZE]; - int i; - struct ent * p1 = *ATBL(tbl, currow, curcol); - if (! p1 || ! p1->format) { - sc_error("cell has no format"); - return; - } - swprintf(cline, BUFFERSIZE, L"%s", p1->format); - for (i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]); - -#ifdef HISTORY_FILE - if (commandline_history->pos == 0) { // Only if editing the new command - wchar_t * sl = get_line_from_history(commandline_history, 0); - wcscat(sl, cline); // Insert into history - } -#endif - ui_show_header(); - return; - - } else if ( sb->value == ctl('w') || sb->value == ctl('b') || - sb->value == OKEY_HOME || sb->value == OKEY_END) { - switch (sb->value) { - case ctl('w'): - real_inputline_pos = for_word(1, 0, 1) + 1; // E - break; - case ctl('b'): - real_inputline_pos = back_word(1); // B - break; - case OKEY_HOME: - real_inputline_pos = 0; // 0 - break; - case OKEY_END: - real_inputline_pos = wcslen(inputline); // $ - break; - } - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == '\t') { // TAB completion - int i, clen = (sizeof(valid_commands) / sizeof(char *)) - 1; - - if (! get_comp()) copy_to_curcmd(inputline); // keep original cmd - - for (i = 0; i < clen; i++) { - if ( ! wcscmp(inputline, valid_commands[i]) ) { - wcscpy(inputline, get_curcmd()); - continue; - } - if ( ! wcsncmp(inputline, valid_commands[i], wcslen(inputline)) - ) { - wcscpy(inputline, valid_commands[i]); - real_inputline_pos = wcslen(inputline); - inputline_pos = wcswidth(inputline, real_inputline_pos); - set_comp(1); - break; - } - } - - // Restore inputline content - if (i == clen) { - wcscpy(inputline, get_curcmd()); - real_inputline_pos = wcslen(inputline); - inputline_pos = wcswidth(inputline, real_inputline_pos); - set_comp(0); - } - - ui_show_header(); - return; - - } else if (sc_isprint(sb->value)) { // Write new char - ins_in_line(sb->value); - ui_show_header(); - -#ifdef HISTORY_FILE - if (commandline_history->pos == 0) { // Only if editing the new command - wchar_t * sl = get_line_from_history(commandline_history, 0); - add_wchar(sl, sb->value, real_inputline_pos-1); // Insert into history - } -#endif - return; - - - /* - * CONFIRM A COMMAND PRESSING ENTER - */ - } else if (find_val(sb, OKEY_ENTER)) { - - if ( ! wcscmp(inputline, L"refresh")) { - sig_winchg(); - - } else if ( ! wcscmp(inputline, L"help") || ! wcscmp(inputline, L"h") ) { - help(); - - } else if ( ! wcscmp(inputline, L"q!") || ! wcscmp(inputline, L"quit!") ) { - shall_quit = 2; - - } else if ( ! wcscmp(inputline, L"q") || ! wcscmp(inputline, L"quit") ) { - shall_quit = 1; - - } else if ( ! wcsncmp(inputline, L"autojus", 7) ) { - wchar_t cline [BUFFERSIZE]; - wcscpy(cline, inputline); - int c = curcol, cf = curcol; - if (p != -1) { - c = sr->tlcol; - cf = sr->brcol; - } - if ( p != -1 || ! wcscmp(inputline, L"autojus")) { - swprintf(cline, BUFFERSIZE, L"autojus %s:", coltoa(c)); - swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s", coltoa(cf)); - } - send_to_interp(cline); - - } else if ( ! wcsncmp(inputline, L"define_color", 12) ) { - send_to_interp(inputline); - - } else if ( ! wcsncmp(inputline, L"redefine_color", 14) ) { - send_to_interp(inputline); - - } else if ( ! wcsncmp(inputline, L"load", 4) ) { - char name [BUFFERSIZE]; - int name_ok = 0; - int force_rewrite = 0; - #ifndef NO_WORDEXP - size_t len; - wordexp_t p; - #endif - - wcstombs(name, inputline, BUFFERSIZE); - if ( ! wcsncmp(inputline, L"load! ", 6) ) { - force_rewrite = 1; - del_range_chars(name, 4, 4); - } - - del_range_chars(name, 0, 4); - if ( ! strlen(name) ) { - sc_error("Path to file to load is missing !"); - } else if ( modflg && ! force_rewrite ) { - sc_error("Changes were made since last save. Use '!' to force the load"); - } else { - #ifdef NO_WORDEXP - name_ok = 1; - #else - wordexp(name, &p, 0); - if ( p.we_wordc < 1 ) { - sc_error("Failed expanding filepath"); - - } else if ( (len = strlen(p.we_wordv[0])) >= sizeof(name) ) { - sc_error("File path too long"); - wordfree(&p); - } else { - memcpy(name, p.we_wordv[0], len+1); - name_ok = 1; - wordfree(&p); - } - #endif - } - - if ( name_ok ) { - if ( ! file_exists(name)) { - sc_error("File %s does not exists!", name); - } else { - delete_structures(); - create_structures(); - readfile(name, 0); - - if (! get_conf_int("nocurses")) { - ui_show_header(); - } - } - } - } else if ( ! wcsncmp(inputline, L"hiderow ", 8) || - ! wcsncmp(inputline, L"showrow ", 8) || - ! wcsncmp(inputline, L"showcol ", 8) || - ! wcsncmp(inputline, L"hidecol ", 8) - ) { - send_to_interp(inputline); - - } else if ( ! wcsncmp(inputline, L"showrows", 8) ) { - if (p != -1) { // only continue if there is a selected range - int r, arg; - sr = get_range_by_pos(p); - r = sr->tlrow; - arg = sr->brrow - sr->tlrow + 1; - show_row(r, arg); - } - - } else if ( ! wcsncmp(inputline, L"showcols", 8) ) { - if (p != -1) { // only continue if there is a selected range - int r, arg; - sr = get_range_by_pos(p); - r = sr->tlcol; - arg = sr->brcol - sr->tlcol + 1; - show_col(r, arg); - } - - // range lock / unlock - } else if ( ! wcsncmp(inputline, L"lock", 4) || ! wcsncmp(inputline, L"unlock", 6) || - ! wcsncmp(inputline, L"valueize", 8) ) { - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - } - if ( ! wcsncmp(inputline, L"lock", 4) ) lock_cells(lookat(r, c), lookat(rf, cf)); - else if ( ! wcsncmp(inputline, L"unlock", 6) ) unlock_cells(lookat(r, c), lookat(rf, cf)); - else if ( ! wcsncmp(inputline, L"valueize", 8) ) valueize_area(r, c, rf, cf); - - } else if ( ! wcsncmp(inputline, L"datefmt", 7)) { - wcscpy(interp_line, inputline); - - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { // in case there is a range selected - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - } - wchar_t cline [BUFFERSIZE]; - wcscpy(cline, interp_line); - int found = wstr_in_wstr(interp_line, L"\""); - if (found != -1) { - del_range_wchars(cline, 0, found-1); - swprintf(interp_line, BUFFERSIZE, L"datefmt %s%d:", coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d %ls", coltoa(cf), rf, cline); - send_to_interp(interp_line); - } - - } else if ( ! wcsncmp(inputline, L"sort ", 5) ) { - wcscpy(interp_line, inputline); - if (p != -1) { // in case there is a range selected - wchar_t cline [BUFFERSIZE]; - wcscpy(cline, interp_line); - int found = wstr_in_wstr(interp_line, L"\""); - if (found != -1) { - del_range_wchars(cline, 0, found-1); - swprintf(interp_line, BUFFERSIZE, L"sort %s%d:", coltoa(sr->tlcol), sr->tlrow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d %ls", coltoa(sr->brcol), sr->brrow, cline); - } - } - sc_info("Sorting.."); - send_to_interp(interp_line); - sc_info("Done."); - - } else if ( ! wcsncmp(inputline, L"subtotal ", 9) ) { - int r = currow, c = curcol, rf = currow, cf = curcol, pos, cancel = 0; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - } - if (any_locked_cells(r, c, rf, cf)) { - sc_error("Locked cells encountered. Nothing changed"); - } else { - wchar_t line [BUFFERSIZE]; - wcscpy(line, inputline); - del_range_wchars(line, 0, 8); - if ( - (pos = wstr_in_wstr(line, L"@sum")) != -1 || - (pos = wstr_in_wstr(line, L"@avg")) != -1 || - (pos = wstr_in_wstr(line, L"@max")) != -1 || - (pos = wstr_in_wstr(line, L"@min")) != -1 ) { - add_wchar(line, L'\"', pos); - add_wchar(line, L'\"', pos+5); - } else if ( - (pos = wstr_in_wstr(line, L"@prod")) != -1) { - add_wchar(line, L'\"', pos); - add_wchar(line, L'\"', pos+6); - } else if ( - (pos = wstr_in_wstr(line, L"@count")) != -1) { - add_wchar(line, L'\"', pos); - add_wchar(line, L'\"', pos+7); - } else if ( - (pos = wstr_in_wstr(line, L"@stddev")) != -1) { - add_wchar(line, L'\"', pos); - add_wchar(line, L'\"', pos+8); - } else { - sc_error("Please specify a function to apply the subtotals"); - cancel = 1; - } - if (!cancel) { - swprintf(interp_line, BUFFERSIZE, L"subtotal %s%d:", coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(cf), rf); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); - send_to_interp(interp_line); - unselect_ranges(); - } - } - - } else if ( ! wcsncmp(inputline, L"freezecol", 9) ) { - if (p != -1) { - swprintf(interp_line, BUFFERSIZE, L"freeze %s:", coltoa(sr->tlcol)); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(sr->brcol)); - } else if (! wcscmp(inputline, L"freezecol")) { - swprintf(interp_line, BUFFERSIZE, L"freeze %s", coltoa(curcol)); - } else - swprintf(interp_line, BUFFERSIZE, L"freeze %ls", &inputline[9]); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"freezerow", 9) ) { - if (p != -1) { - swprintf(interp_line, BUFFERSIZE, L"freeze %d:%d", sr->tlrow, sr->brrow); - } else if (! wcscmp(inputline, L"freezerow")) { - swprintf(interp_line, BUFFERSIZE, L"freeze %d", currow); - } else - swprintf(interp_line, BUFFERSIZE, L"freeze %ls", &inputline[9]); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"unfreezecol", 11) ) { - if (p != -1) { - swprintf(interp_line, BUFFERSIZE, L"unfreeze %s:", coltoa(sr->tlcol)); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(sr->brcol)); - } else if (! wcscmp(inputline, L"unfreezecol")) { - swprintf(interp_line, BUFFERSIZE, L"unfreeze %s", coltoa(curcol)); - } else - swprintf(interp_line, BUFFERSIZE, L"unfreeze %ls", &inputline[11]); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"unfreezerow", 11) ) { - if (p != -1) { - swprintf(interp_line, BUFFERSIZE, L"unfreeze %d:%d", sr->tlrow, sr->brrow); - } else if (! wcscmp(inputline, L"unfreezerow")) { - swprintf(interp_line, BUFFERSIZE, L"unfreeze %d", currow); - } else - swprintf(interp_line, BUFFERSIZE, L"unfreeze %ls", &inputline[11]); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"addfilter", 9) ) { - wchar_t cline [BUFFERSIZE]; - char line [BUFFERSIZE]; - wcscpy(cline, inputline); - int found; - if ((found = wstr_in_wstr(cline, L"\"")) != -1) { - del_range_wchars(cline, wcslen(cline), wcslen(cline)); - del_range_wchars(cline, 0, found); - wcstombs(line, cline, BUFFERSIZE); - add_filter(line); - line[strlen(line)-1]='\0'; // remove last " - sc_info("Added filter: %s", line); - } - - } else if ( ! wcsncmp(inputline, L"delfilter ", 10) ) { - wchar_t cline [BUFFERSIZE]; - char line [BUFFERSIZE]; - wcscpy(cline, inputline); - del_range_wchars(cline, 0, 9); - wcstombs(line, cline, BUFFERSIZE); - int id = atoi(line); - if (del_filter(id) == 0) sc_info("Removed filter: %d", id); - - } else if ( ! wcsncmp(inputline, L"delfilters", 10) ) { - if (free_filters() == 0) sc_info("Removed filters"); - - } else if ( ! wcsncmp(inputline, L"filteron", 8) ) { - wcscpy(interp_line, inputline); - if ( ! wcscmp(inputline, L"filteron") && p == -1) { // If there is no selected range and no range in inputline passed - sc_error("Please specify a range or select one"); - } else if (p != -1) { - wchar_t cline [BUFFERSIZE]; - wcscpy(cline, interp_line); - swprintf(interp_line, BUFFERSIZE, L"filteron %s%d:", coltoa(sr->tlcol), sr->tlrow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(sr->brcol), sr->brrow); - send_to_interp(interp_line); - } else { // no range selected. range passed in inputline - send_to_interp(interp_line); - } - - } else if ( ! wcsncmp(inputline, L"filteroff", 9) ) { - disable_filters(); - - } else if ( ! wcsncmp(inputline, L"hiddenrows", 10)) { - show_hiddenrows(); - - } else if ( ! wcsncmp(inputline, L"hiddencols", 10)) { - show_hiddencols(); - - } else if ( ! wcsncmp(inputline, L"showfilters", 11)) { - show_filters(); - - } else if ( ! wcsncmp(inputline, L"int ", 4) ) { // send cmd to interpreter - wcscpy(interp_line, inputline); - del_range_wchars(interp_line, 0, 3); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"fill ", 5) ) { - interp_line[0]=L'\0'; - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - swprintf(interp_line, BUFFERSIZE, L"fill %s%d:", coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(cf), rf); - } - - if (any_locked_cells(r, c, rf, cf)) { - swprintf(interp_line, BUFFERSIZE, L""); - sc_error("Locked cells encountered. Nothing changed"); - } else { - if (p != -1) - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", &inputline[5]); - else - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", inputline); - send_to_interp(interp_line); - } - - } else if ( ! wcsncmp(inputline, L"formatrow ", 10) ) { - int r = currow, rf = currow, i; - if (p != -1) { - r = sr->tlrow; - rf = sr->brrow; - } -#ifdef UNDO - int changed = 0, fmt_ori; - create_undo_action(); -#endif - for (i=r; i<=rf;i++) { -#ifdef UNDO - fmt_ori = row_format[i]; - add_undo_row_format(i, 'R', row_format[i]); -#endif - swprintf(interp_line, BUFFERSIZE, L"format %d %ls", i, &inputline[10]); - send_to_interp(interp_line); -#ifdef UNDO - if (fmt_ori != row_format[i]) changed = 1; - add_undo_row_format(i, 'A', row_format[i]); -#endif - } -#ifdef UNDO - if (! changed) dismiss_undo_item(NULL); - else end_undo_action(); -#endif - - } else if ( ! wcsncmp(inputline, L"formatcol ", 10) ) { - int c = curcol, cf = curcol, i; - if (p != -1) { - c = sr->tlcol; - cf = sr->brcol; - } -#ifdef UNDO - int changed = 0; - int fwidth_ori; - int precision_ori; - int realfmt_ori; - create_undo_action(); -#endif - for (i=c; i<=cf;i++) { -#ifdef UNDO - fwidth_ori = fwidth[i]; - precision_ori = precision[i]; - realfmt_ori = realfmt[i]; - add_undo_col_format(i, 'R', fwidth[i], precision[i], realfmt[i]); -#endif - swprintf(interp_line, BUFFERSIZE, L"format %s", coltoa(i)); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %ls", &inputline[10]); - send_to_interp(interp_line); -#ifdef UNDO - if (fwidth[i] != fwidth_ori || precision[i] != precision_ori || realfmt[i] != realfmt_ori) changed = 1; - add_undo_col_format(i, 'A', fwidth[i], precision[i], realfmt[i]); -#endif - } -#ifdef UNDO - if (! changed) dismiss_undo_item(NULL); - else end_undo_action(); -#endif - - } else if ( ! wcsncmp(inputline, L"format ", 7) ) { - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - swprintf(interp_line, BUFFERSIZE, L"fmt %s%d:", coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); - } else - swprintf(interp_line, BUFFERSIZE, L"fmt %s%d", coltoa(c), r); - - if (any_locked_cells(r, c, rf, cf)) { - sc_error("Locked cells encountered. Nothing changed"); - } else { - int l = wcslen(interp_line); - swprintf(interp_line + l, BUFFERSIZE, L"%ls", inputline); - del_range_wchars(interp_line, l, l + 5); - #ifdef UNDO - create_undo_action(); - copy_to_undostruct(r, c, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); - #endif - send_to_interp(interp_line); - #ifdef UNDO - copy_to_undostruct(r, c, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); - #endif - } - - } else if ( ! wcsncmp(inputline, L"ccopy", 5) ) { - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - } - swprintf(interp_line, BUFFERSIZE, L"ccopy %s%d:", coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"strtonum", 8) ) { - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - } - swprintf(interp_line, BUFFERSIZE, L"strtonum %s%d:", coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"cpaste", 6) ) { - swprintf(interp_line, BUFFERSIZE, L"cpaste"); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"cellcolor ", 10) ) { - #ifdef USECOLORS - interp_line[0]=L'\0'; - wchar_t line [BUFFERSIZE]; - wcscpy(line, inputline); - del_range_wchars(line, 0, 9); - swprintf(interp_line, BUFFERSIZE, L"cellcolor "); - if (p != -1) { - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow); - } - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); - send_to_interp(interp_line); - #else - sc_error("Color support not compiled in"); - chg_mode('.'); - inputline[0] = L'\0'; - #endif - - } else if ( ! wcsncmp(inputline, L"unformat", 8) ) { - #ifdef USECOLORS - interp_line[0]=L'\0'; - wchar_t line [BUFFERSIZE]; - wcscpy(line, inputline); - del_range_wchars(line, 0, 7); - swprintf(interp_line, BUFFERSIZE, L"unformat"); - if (p != -1) { - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow); - } - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); - send_to_interp(interp_line); - #else - sc_error("Color support not compiled in"); - chg_mode('.'); - inputline[0] = L'\0'; - #endif - - } else if ( ! wcsncmp(inputline, L"color ", 6) ) { - #ifdef USECOLORS - char line [BUFFERSIZE]; - wcstombs(line, inputline, BUFFERSIZE); - del_range_chars(line, 0, 5); - chg_color(line); - #else - sc_error("Color support not compiled in"); - chg_mode('.'); - inputline[0] = '\0'; - #endif - - } else if ( ! wcsncmp(inputline, L"trigger ", 8) ) { - interp_line[0]=L'\0'; - wchar_t line [BUFFERSIZE]; - wcscpy(line, inputline); - del_range_wchars(line, 0, 7); - swprintf(interp_line, BUFFERSIZE, L"trigger "); - if (p != -1) { - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow); - } - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"untrigger ", 10) ) { - wcscpy(interp_line, inputline); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"set ", 4) ) { - wchar_t line [BUFFERSIZE]; - wcscpy(line, inputline); - del_range_wchars(line, 0, 3); - - wchar_t * l; - char oper[BUFFERSIZE]; - if ((l = wcschr(line, L' ')) != NULL) l[0] = L'\0'; - if ((l = wcschr(line, L'=')) != NULL) l[0] = L'\0'; - - wcscpy(interp_line, inputline); - send_to_interp(interp_line); - - wcstombs(oper, line, BUFFERSIZE); - if (get_conf_value(oper)) { - sc_info("Config value changed: %s", oper); - } else if (strlen(oper) > 2 && ! wcsncmp(inputline, L"set no", 6)) { - sc_info("Config value changed: %s", &oper[2]); - } - - } else if ( ! wcsncmp(inputline, L"pad ", 4) ) { - int c = curcol, cf = curcol; - if (p != -1) { // in case there is a range selected - c = sr->tlcol; - cf = sr->brcol; - } - wcscpy(interp_line, inputline); // pad 5 - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s:", coltoa(c)); // pad 5 A: - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(cf)); // B - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"plot ", 5) ) { - int r = currow, c = curcol, rf = currow, cf = curcol; - if (p != -1) { - c = sr->tlcol; - r = sr->tlrow; - rf = sr->brrow; - cf = sr->brcol; - } - wchar_t aux[wcslen(inputline)+1]; - wcscpy(aux, inputline); - del_range_wchars(aux, 0, 4); - swprintf(interp_line, BUFFERSIZE, L"plot \"%ls\" %s%d:", aux, coltoa(c), r); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf); - send_to_interp(interp_line); - - } else if ( ! wcsncmp(inputline, L"plotedit ", 9) ) { - wchar_t aux[wcslen(inputline)+1]; - wcscpy(aux, inputline); - del_range_wchars(aux, 0, 8); - plotedit(aux); - - } else if ( ! wcscmp(inputline, L"set") ) { - char valores[get_dict_buffer_size(user_conf_d) + 1]; - get_conf_values(valores); - ui_show_text(valores); - - } else if ( ! wcscmp(inputline, L"version") ) { - ui_show_text(rev); - - } else if ( ! wcscmp(inputline, L"showmaps") ) { - extern int len_maps; - char valores[MAXMAPITEM * len_maps]; - get_mappings(valores); - ui_show_text(valores); - - } else if ( ! wcsncmp(inputline, L"nmap", 4) || - ! wcsncmp(inputline, L"imap", 4) || - ! wcsncmp(inputline, L"vmap", 4) || - ! wcsncmp(inputline, L"cmap", 4) || - ! wcsncmp(inputline, L"inoremap", 8) || - ! wcsncmp(inputline, L"nnoremap", 8) || - ! wcsncmp(inputline, L"vnoremap", 8) || - ! wcsncmp(inputline, L"cnoremap", 8) || - ! wcsncmp(inputline, L"iunmap", 6) || - ! wcsncmp(inputline, L"vunmap", 6) || - ! wcsncmp(inputline, L"cunmap", 6) || - ! wcsncmp(inputline, L"nunmap", 6) ) { - send_to_interp(inputline); - - } else if ( ! wcsncmp(inputline, L"!", 1) ) { - char line [BUFFERSIZE]; - wcstombs(line, inputline, BUFFERSIZE); - int found = str_in_str(line, " "); - if (found == -1) found++; - del_range_chars(line, 0, found); - exec_cmd(line); - - } else if ( ! wcscmp(inputline, L"wq") ) { - wcscpy(inputline, L"x"); - if (savefile() == 0) shall_quit = 1; - - } else if ( inputline[0] == L'w' ) { - savefile(); - - } else if ( ! wcsncmp(inputline, L"file ", 5) ) { - - char name [BUFFERSIZE]; - int name_ok = 0; - #ifndef NO_WORDEXP - size_t len; - wordexp_t p; - #endif - - wcstombs(name, inputline, BUFFERSIZE); - del_range_chars(name, 0, 4); - - #ifdef NO_WORDEXP - name_ok = 1; - #else - wordexp(name, &p, 0); - if ( p.we_wordc < 1 ) { - sc_error("Failed to expand filename"); - } else if ( (len = strlen(p.we_wordv[0])) >= sizeof(name) ) { - sc_error("File path too long"); - wordfree(&p); - } else { - memcpy(name, p.we_wordv[0], len+1); - name_ok = 1; - wordfree(&p); - } - #endif - - if (name_ok) { - #ifdef AUTOBACKUP - // check if backup of curfile exists. - // if it exists, remove it. - if (strlen(curfile) && backup_exists(curfile)) remove_backup(curfile); - #endif - strncpy(curfile, name, PATHLEN - 1); - sc_info("File name set to \"%s\"", curfile); - } - - } else if ( ! wcscmp(inputline, L"file") ) { - - if( ! *curfile ) { - sc_info("Current file has no name"); - } else { - sc_info("Current file: \"%s\"", curfile); - } - - } else if ( inputline[0] == L'x' ) { - if (savefile() == 0) shall_quit = 1; - - } else if ( ! wcscmp(inputline, L"fcopy") ) { - fcopy(""); - - } else if ( ! wcsncmp(inputline, L"fcopy ", 6)) { - - wchar_t line [BUFFERSIZE]; - wcscpy(line, inputline); - del_range_wchars(line, 0, 5); - char action[BUFFERSIZE]; - wcstombs(action, line, BUFFERSIZE); - fcopy(action); - - } else if ( ! wcscmp(inputline, L"fsum") ) { - fsum(); - - } else if ( - ! wcsncmp(inputline, L"e csv" , 5) || - ! wcsncmp(inputline, L"e! csv" , 6) || - ! wcsncmp(inputline, L"e tex" , 5) || - ! wcsncmp(inputline, L"e! tex" , 6) || - ! wcsncmp(inputline, L"e tab" , 5) || - ! wcsncmp(inputline, L"e! tab" , 6) || - ! wcsncmp(inputline, L"e mkd" , 4) || - ! wcsncmp(inputline, L"e! mkd" , 5) || - ! wcsncmp(inputline, L"e txt" , 5) || - ! wcsncmp(inputline, L"e! txt" , 6) ) { - do_export( p == -1 ? 0 : sr->tlrow, p == -1 ? 0 : sr->tlcol, - p == -1 ? maxrow : sr->brrow, p == -1 ? maxcol : sr->brcol); - - } else if ( - ! wcsncmp(inputline, L"e xlsx" , 6) || - ! wcsncmp(inputline, L"e! xlsx" , 7)) { - #ifndef XLSX_EXPORT - sc_error("XLSX export support not compiled in"); - #else - char linea[BUFFERSIZE]; - char filename[PATHLEN] = ""; - int force_rewrite = 0; - if (inputline[1] == L'!') force_rewrite = 1; - wcstombs(linea, inputline, BUFFERSIZE); // Use new variable to keep command history untouched - del_range_chars(linea, 0, 1 + force_rewrite); // Remove 'e' or 'e!' from inputline - - // Get path and file name to write. - // Use parameter if any. - if (strlen(linea) > 5) { // ex. 'xlsx ' - del_range_chars(linea, 0, 4); // remove 'xlsx' - strcpy(filename, linea); - // Use curfile name and '.xlsx' extension - // Remove current '.sc' extension if necessary - } else if (curfile[0]) { - strcpy(filename, curfile); - char * ext = strrchr(filename, '.'); - if (ext != NULL) del_range_chars(filename, strlen(filename) - strlen(ext), strlen(filename)-1); - sprintf(filename + strlen(filename), ".xlsx"); - } else { - sc_error("No filename specified !"); - } - - if (strlen(filename) > 0 && ! force_rewrite && file_exists(filename)) { - sc_error("File %s already exists. Use \"!\" to force rewrite.", filename); - - #ifdef AUTOBACKUP - // check if backup of filename exists. - // if it exists and '!' is set, remove it. - // if it exists and curfile = fname, remove it. - // else return. - } else if (strlen(filename) && backup_exists(filename) - && !force_rewrite && !(strlen(curfile) && !strcmp(curfile, filename))) { - sc_error("Backup file of %s exists. Use \"!\" to force the write process.", filename); - #endif - } else if (strlen(filename)) { - #ifdef AUTOBACKUP - if (backup_exists(filename)) remove_backup(filename); - #endif - if (export_xlsx( - filename, p == -1 ? 0 : sr->tlrow, p == -1 ? 0 : sr->tlcol, - p == -1 ? maxrow : sr->brrow, p == -1 ? maxcol : sr->brcol) == 0) - sc_info("File \"%s\" written", filename); - } - #endif - - } else { - sc_error("COMMAND NOT FOUND !"); - } - -#ifdef HISTORY_FILE - /* - * if exists in history an item with same text to the command typed - * (counting from the second position) it is moved to the beginning of list. - * (first element in list means last command executed) - */ - del_item_from_history(commandline_history, 0); - int moved = move_item_from_history_by_str(commandline_history, inputline, -1); - if (! moved) add(commandline_history, inputline); - commandline_history->pos = 0; -#endif - - chg_mode('.'); - inputline[0]=L'\0'; - inputline_pos = 0; //ADDED 08/10/2018 - set_comp(0); // unmark tab completion - ui_update(TRUE); - } - return; -} - -/** - * \brief TODO Document ins_in_line() - * - * \param[in] d - * - * \return none - */ - -void ins_in_line(wint_t d) { - add_wchar(inputline, (wchar_t) d, real_inputline_pos++); - inputline_pos += wcwidth((wchar_t) d); - return; -} diff -Nru sc-im-0.8.2+ds/src/cmds_command.h sc-im-0.8.3+ds/src/cmds_command.h --- sc-im-0.8.2+ds/src/cmds_command.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_command.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_command.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for cmds_command.c - */ - -#ifdef HISTORY_FILE -#include "history.h" -#endif -#include "buffer.h" - -extern int shall_quit; -extern struct dictionary * user_conf_d; -extern struct history * commandline_history; - -void do_commandmode(struct block * sb); -void ins_in_line(wint_t d); diff -Nru sc-im-0.8.2+ds/src/cmds_edit.c sc-im-0.8.3+ds/src/cmds_edit.c --- sc-im-0.8.2+ds/src/cmds_edit.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_edit.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,694 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_edit.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include -#include "cmds.h" -#include "tui.h" -#include "buffer.h" -#include "sc.h" // for rescol -#include "cmds_edit.h" -#include "utils/string.h" -#include "interp.h" -#include "marks.h" -#include "conf.h" -#include "history.h" - -// this macro is used to determinate a word over a WORD -#define istext(a) (iswalnum(a) || ((a) == L'_')) - -#ifdef INS_HISTORY_FILE -extern char ori_insert_edit_submode; -#endif - -static wint_t wi; /**< char read from stdin */ - -/** - * \brief TODO Document do_editmode() - * - * \param[in] sb - * - * \return none - */ - -void do_editmode(struct block * sb) { - int pos; - int initial_position; - - if (sb->value == L'h' || sb->value == OKEY_LEFT) { // LEFT - if (real_inputline_pos) { - real_inputline_pos--; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } - ui_show_header(); - return; - - } else if (sb->value == L'l' || sb->value == OKEY_RIGHT) { // RIGHT - if (real_inputline_pos < wcslen(inputline)-1) { - real_inputline_pos++; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } - ui_show_header(); - return; - - } else if (sb->value == L' ' && ( wcslen(inputline) < (COLS - 14) ) ) { // SPACE - add_wchar(inputline, L' ', real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'^') { // ^ - pos = first_nonblank_char(); - if (pos == -1) return; - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'g') { // ^ - if (ui_getch_b(&wi) == -1 || wi != L'_') return; - pos = last_nonblank_char(); - if (pos == -1) return; - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'0' || sb->value == OKEY_HOME) { // 0 - inputline_pos = 0; - real_inputline_pos = 0; - ui_show_header(); - return; - - } else if (sb->value == L'$' || sb->value == OKEY_END) { // $ - inputline_pos = wcswidth(inputline, wcslen(inputline)) - 1; - real_inputline_pos = wcslen(inputline) - 1; - ui_show_header(); - return; - - } else if (sb->value == L'I') { // I - inputline_pos = 0; - real_inputline_pos = 0; -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = insert_edit_submode; - add(insert_history, L""); -#endif - chg_mode(insert_edit_submode); - ui_show_header(); - return; - - } else if (sb->value == L'i' || sb->value == L'=') { // i o = -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = insert_edit_submode; - add(insert_history, L""); -#endif - chg_mode(insert_edit_submode); - ui_show_header(); - return; - - } else if (sb->value == L'x') { // x - del_back_char(); - ui_show_header(); - return; - - } else if (sb->value == L'X') { // X - del_for_char(); - ui_show_header(); - return; - - } else if (sb->value == L'r') { // r - //curs_set(1); - if (ui_getch_b(&wi) != -1) inputline[real_inputline_pos] = wi; - //curs_set(2); - ui_show_header(); - return; - - } else if (find_val(sb, OKEY_ENTER)) { // ENTER - char ope[BUFFERSIZE] = ""; - wchar_t content[BUFFERSIZE] = L""; - wcscpy(content, inputline); - - switch (insert_edit_submode) { - case '=': - strcpy(ope, "let"); - break; - case '<': - strcpy(ope, "leftstring"); - break; - case '>': - strcpy(ope, "rightstring"); - break; - case '\\': - strcpy(ope, "label"); - break; - } - - if (content[0] == L'"') { - del_wchar(content, 0); - } else if (insert_edit_submode != '=' && content[0] != L'"') { - add_wchar(content, L'\"', 0); - add_wchar(content, L'\"', wcslen(content)); - } - - enter_cell_content(currow, curcol, ope, content); - - inputline[0] = L'\0'; - inputline_pos = 0; - real_inputline_pos = 0; - chg_mode('.'); - ui_clr_header(1); - - char * opt = get_conf_value("newline_action"); - switch (opt[0]) { - case 'j': - currow = forw_row(1)->row; - break; - case 'l': - curcol = forw_col(1)->col; - break; - } - ui_update(TRUE); - return; - - } else if (sb->value == L'a') { // a - real_inputline_pos++; - inputline_pos = wcswidth(inputline, real_inputline_pos); -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = insert_edit_submode; - add(insert_history, L""); -#endif - chg_mode(insert_edit_submode); - ui_show_header(); - return; - - } else if (sb->value == L'A') { // A - real_inputline_pos = wcslen(inputline); - inputline_pos = wcswidth(inputline, real_inputline_pos); -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = insert_edit_submode; - add(insert_history, L""); -#endif - chg_mode(insert_edit_submode); - ui_show_header(); - return; - - } else if (sb->value == L'D') { // D - inputline[real_inputline_pos] = L'\0'; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L's') { // s - del_back_char(); -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = insert_edit_submode; - add(insert_history, L""); -#endif - chg_mode(insert_edit_submode); - ui_show_header(); - return; - - } else if (sb->value == L'f') { // f - if (ui_getch_b(&wi) == -1) return; - pos = look_for((wchar_t) wi); // this returns real_inputline_pos ! - if (pos != -1) { - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - } - return; - - } else if (sb->value == L't') { // t - if (ui_getch_b(&wi) == -1) return; - int initial_position = inputline_pos; - if (inputline_pos < wcswidth(inputline, wcslen(inputline))) inputline_pos++ ; - pos = look_for((wchar_t) wi); // this returns real_inputline_pos ! - if (pos != -1) { - real_inputline_pos = pos - 1; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } else { - inputline_pos = initial_position; - } - ui_show_header(); - return; - - } else if (sb->value == L'F') { // F - if (ui_getch_b(&wi) == -1) return; - pos = look_back((wchar_t) wi); // this returns real_inputline_pos ! - if (pos != -1) { - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - } - return; - - } else if (sb->value == L'T') { // T - if (ui_getch_b(&wi) == -1) return; - int initial_position = inputline_pos; - if (inputline_pos) inputline_pos--; - pos = look_back((wchar_t) wi); // this returns real_inputline_pos ! - if (pos != -1) { - real_inputline_pos = pos + 1; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } else { - inputline_pos = initial_position; - } - ui_show_header(); - return; - - } else if (sb->value == L'w') { // w - real_inputline_pos = for_word(0, 0, 0); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'W') { // W - real_inputline_pos = for_word(0, 0, 1); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'e') { // e - real_inputline_pos = for_word(1, 0, 0); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'E') { // E - real_inputline_pos = for_word(1, 0, 1); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'b') { // b - real_inputline_pos = back_word(0); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'B') { // B - real_inputline_pos = back_word(1); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == L'R') { // R - //curs_set(1); - if (ui_getch_b(&wi) == -1) return; - wint_t c = wi; - while (c != OKEY_ENTER && c != -1) { - if (iswprint(c)) { - inputline[real_inputline_pos] = c; - ++real_inputline_pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - } - if (ui_getch_b(&wi) == -1) return; - c = wi; - } - //curs_set(2); - - - } else if (sb->value == L'd' || sb->value == L'c') { // d or c - wint_t c, d; - if (ui_getch_b(&wi) != -1) { - c = wi; - switch (c) { - case L'$': - pos = wcswidth(inputline, wcslen(inputline)) - 1; - del_range_wchars(inputline, real_inputline_pos, pos); - if (real_inputline_pos == wcslen(inputline) && real_inputline_pos) real_inputline_pos--; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'f': - if (ui_getch_b(&wi) == -1) return; - d = wi; - pos = look_for((wchar_t) d); // this returns real_inputline_pos ! - if (pos != -1) del_range_wchars(inputline, real_inputline_pos, pos); - break; - - case L't': - if (ui_getch_b(&wi) == -1) return; - initial_position = inputline_pos; - if (inputline_pos < wcswidth(inputline, wcslen(inputline))) inputline_pos++ ; - pos = look_for((wchar_t) wi); - if (pos != -1) { - del_range_wchars(inputline, real_inputline_pos, pos - 1); - inputline_pos = wcswidth(inputline, real_inputline_pos); - } else { - inputline_pos = initial_position; - } - break; - - case L'0': // 0 - del_range_wchars(inputline, 0, real_inputline_pos-1); - real_inputline_pos = 0; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'^': - pos = first_nonblank_char(); - if (pos == -1) return; - del_range_wchars(inputline, pos, real_inputline_pos-1); - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'g': - if (ui_getch_b(&wi) == -1 || wi != L'_') return; - pos = last_nonblank_char(); - if (pos == -1) return; - del_range_wchars(inputline, real_inputline_pos, pos); - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'e': // de or ce - del_range_wchars(inputline, real_inputline_pos, for_word(1, 0, 0)); - break; - - case L'E': // dE or cE - del_range_wchars(inputline, real_inputline_pos, for_word(1, 0, 1)); - break; - - case L'w': // dw or cw - del_range_wchars(inputline, real_inputline_pos, for_word(0, 1, 0) - 1); - inputline_pos = wcswidth(inputline, real_inputline_pos); - if (real_inputline_pos == wcslen(inputline) && real_inputline_pos) real_inputline_pos--; - break; - - case L'W': // dW or cW - del_range_wchars(inputline, real_inputline_pos, for_word(0, 1, 1) - 1); - inputline_pos = wcswidth(inputline, real_inputline_pos); - if (real_inputline_pos == wcslen(inputline) && real_inputline_pos) real_inputline_pos--; - break; - - case L'b': // db or cb - d = back_word(0); - del_range_wchars(inputline, d, real_inputline_pos-1); - real_inputline_pos = d; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'B': // dB or cB - d = back_word(1); - del_range_wchars(inputline, d, real_inputline_pos-1); - real_inputline_pos = d; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'F': - if (ui_getch_b(&wi) == -1) return; - pos = look_back((wchar_t) wi); - if (pos != -1) del_range_wchars(inputline, pos, real_inputline_pos-1); - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - break; - - case L'T': - if (ui_getch_b(&wi) == -1) return; - initial_position = inputline_pos; - if (inputline_pos) inputline_pos--; - pos = look_back((wchar_t) wi); - - if (pos != -1) { - del_range_wchars(inputline, pos+1, real_inputline_pos-1); - real_inputline_pos = pos; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } else { - inputline_pos = initial_position; - } - break; - - case L'l': // dl or cl - case OKEY_RIGHT: - del_back_char(); - break; - - case L'h': // dh or ch - case OKEY_LEFT: - del_for_char(); - break; - - case L'a': - if (ui_getch_b(&wi) == -1) return; - d = wi; - if ( d == L'W' ) { // daW or caW - c = ( real_inputline_pos && inputline[real_inputline_pos-1] == L' ' ) ? real_inputline_pos : back_word(1); - del_range_wchars(inputline, c, for_word(0, 1, 1) - 1); - real_inputline_pos = (wcslen(inputline) > real_inputline_pos) ? c : wcslen(inputline)-2; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } else if ( d == L'w' ) { // daw or caw - d = ( real_inputline_pos && ! istext( inputline[real_inputline_pos-1]) ) ? real_inputline_pos : back_word(0); - del_range_wchars(inputline, d, for_word(0, 1, 0) - 1); - real_inputline_pos = (wcslen(inputline) > real_inputline_pos) ? d : wcslen(inputline)-2; - inputline_pos = wcswidth(inputline, real_inputline_pos); - } - break; - } - if (sb->value == L'c') { -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = insert_edit_submode; - add(insert_history, L""); -#endif - chg_mode(insert_edit_submode); - } - } - - } - ui_show_header(); - return; -} - -/** - * \brief Looks (forward) for a char in inputline - * - * \param[in] cb - * - * \return position; -1 otherwise - */ - -int look_for(wchar_t cb) { - int c, cpos = inputline_pos; - while (++cpos < wcslen(inputline)) - if ((c = inputline[cpos]) && c == cb) return cpos; - //if (cpos > 0 && cpos == wcslen(inputline)) return real_inputline_pos; - return -1; -} - -/** - * \brief Looks (backwards) for a char in inputline - * - * \param[in] cb - * - * \return position; -1 otherwise - */ - -int look_back(wchar_t cb) { - int c, cpos = inputline_pos; - while (--cpos >= 0) - if ((c = inputline[cpos]) && c == cb) return cpos; - return -1; -} - -/** - * \brief Looks for a first non blank char in inputline - * - * \return position if found; -1 otherwise - */ -int first_nonblank_char() { - int cpos = -1; - while (++cpos < wcslen(inputline)) - if (inputline[cpos] && inputline[cpos] != L' ') return cpos; - return -1; -} - - -/** - * \brief Looks for the last non blank char in inputline - * - * \return position if found; -1 otherwise - */ -int last_nonblank_char() { - int cpos = wcslen(inputline); - while (--cpos > 0) - if (inputline[cpos] && inputline[cpos] != L' ') return cpos; - return -1; -} - -/** - * \brief Move backward one word - * - * \param[in] big_word - * - * \return position - */ - -int back_word(int big_word) { - int c, cpos = real_inputline_pos; - if (inputline[cpos-1] == L' ' ) cpos--; - - while (cpos) - if ((c = inputline[--cpos]) && c == L' ' ) return cpos+1; - else if ( istext( inputline [cpos] ) && ! istext( inputline[cpos - 1] ) && ! big_word ) return cpos; - else if ( ! istext( inputline [cpos] ) && istext( inputline[cpos - 1] ) && ! big_word ) return cpos; - return cpos; -} - -/** - * \brief Move to the end of a word - * - * \details Used for moving forward to the end of a WORD. big_word - * looks for ' ', else looks for istext. - * - * \param[in] end_of_word - * \param[in] delete - * \param[in] big_word - * - * \return position; 0 otherwise - */ - -int for_word(int end_of_word, int delete, int big_word) { - int cpos = real_inputline_pos; - - if (! end_of_word) { // w or W - while ( ++cpos < wcslen(inputline) ) - if ( ! istext( inputline[cpos - 1]) && inputline[cpos] != L' ' && ! big_word ) return cpos; - else if ( inputline[cpos] == L' ' ) return ++cpos; - else if ( ! istext( inputline [cpos] ) && istext( inputline[cpos - 1] ) && ! big_word ) return cpos; - } else { // e or E - if ( inputline[cpos+1] == L' ' ) cpos += 2; - else if ( ! istext( inputline [cpos+1] ) && istext( inputline[cpos] ) && ! big_word ) cpos++; - while ( ++cpos < wcslen(inputline) ) - if ( ( inputline[cpos] == L' ' ) || ( ! istext( inputline [cpos] ) - && istext( inputline[cpos - 1] ) && ! big_word ) ) return --cpos; - } - - if (cpos > 0 && cpos >= wcslen(inputline)) return wcslen(inputline) - 1 + delete; - return 0; -} - -/** - * \brief TODO Document del_back_char() - * - * \return none - */ - -void del_back_char() { // x DEL - int max = wcswidth(inputline, wcslen(inputline)); - if (inputline_pos > max) return; - int l = wcwidth(inputline[real_inputline_pos]); - del_wchar(inputline, real_inputline_pos); - if (real_inputline_pos == wcslen(inputline) && wcslen(inputline)) { - inputline_pos -= l; - real_inputline_pos--; - } else if (! wcslen(inputline)) { - inputline_pos = 0; - } - return; -} - -/** - * \brief TODO Document del_for_char() - * - * \return none - */ - -void del_for_char() { // X BS - if ( ! wcslen(inputline) || ! real_inputline_pos ) return; - int l = wcwidth(inputline[real_inputline_pos - 1]); - del_wchar(inputline, real_inputline_pos-1); - real_inputline_pos--; - inputline_pos -= l; - return; -} - -/** - * \brief TODO Document start_edit_mode() - * - * \returns: 1 on success; 0 on error - */ - -int start_edit_mode(struct block * buf, char type) { - chg_mode(buf->value); - - line[0]='\0'; - inputline[0]=L'\0'; - - struct ent * p1 = lookat(currow, curcol); - - if (type == 'v') { // && p1->flags & is_valid) { // numeric value - if (( ! (p1->expr) ) ) { // || (p1->flags & is_strexpr)) { - (void) swprintf(inputline, BUFFERSIZE, L"%.15g", p1->v); - } else { // expression - linelim = 0; - editexp(currow, curcol); - linelim = -1; - (void) swprintf(inputline, BUFFERSIZE, L"%s", line); - } - insert_edit_submode='='; - - } else if (type == 's') { // string value - if (! ((p1)->label || (p1)->flags & is_strexpr)) { - return 0; - } - if (p1->flags & is_label) { - insert_edit_submode='\\'; - } else if (p1->flags & is_leftflush) { - insert_edit_submode='<'; - } else { - insert_edit_submode='>'; - } - linelim = 0; - edits(currow, curcol, 0); - linelim = -1; - if ((p1)->flags & is_strexpr) swprintf(inputline + wcslen(inputline), BUFFERSIZE, L"\""); - (void) swprintf(inputline + wcslen(inputline), BUFFERSIZE, L"%s", line); - } - inputline_pos = wcswidth(inputline, wcslen(inputline)) - 1; - real_inputline_pos = wcslen(inputline) - 1; - //ui_show_header(); - return 1; -} diff -Nru sc-im-0.8.2+ds/src/cmds_edit.h sc-im-0.8.3+ds/src/cmds_edit.h --- sc-im-0.8.2+ds/src/cmds_edit.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_edit.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_edit.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for cmds_edit.c - */ - -#include "input.h" - -void do_editmode(struct block * sb); -int start_edit_mode(struct block * buf, char type); - -int for_word(int end_of_word, int delete, int big_word); -int look_for(wchar_t cb); -int look_back(wchar_t cb); -int back_word(int big_word); - -void del_back_char(); -void del_for_char(); - -int first_nonblank_char(); -int last_nonblank_char(); - -wint_t get_key(); diff -Nru sc-im-0.8.2+ds/src/cmds.h sc-im-0.8.3+ds/src/cmds.h --- sc-im-0.8.2+ds/src/cmds.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds.h - * \author Andrés Martinelli - * \date 2021-05-02 - * \brief Header file for cmds.c - */ - -#include "macros.h" -#include - -extern char insert_edit_submode; // insert or edit submode -extern wchar_t inputline[BUFFERSIZE]; -extern int inputline_pos; -extern int real_inputline_pos; -extern struct block * lastcmd_buffer; - -int is_single_command (struct block * buf, long timeout); -void enter_cell_content(int r, int c, char * submode, wchar_t * content); -void send_to_interp(wchar_t * oper); // Send command to interpreter -void send_to_interpp(char * oper); -void chg_mode(char strcmd); // Change mode function -int modcheck(); // Verify if open file has been modified -int savefile(); // Save open file -struct ent; -void copyent(struct ent * n, struct ent * p, int dr, int dc, int r1, int c1, int r2, int c2, int special); -void flush_saved(); -void insert_row(int after); -void insert_col(int after); -void deleterow(int row, int mult); -void int_deleterow(int row, int multi); -void deletecol(); -void int_deletecol(int col, int mult); -void formatcol(int c); -void del_selected_cells(); -struct ent * lookat(int row, int col); // return pointer to 'ent' of cell. Create it if it doesn't exist -void cleanent(struct ent * p); // Initialize 'ent' to zero. Won't free memory -void clearent(struct ent * v); // free 'ent' memory. -int locked_cell(int r, int c); -int any_locked_cells(int r1, int c1, int r2, int c2); -void scroll_left (int n); -void scroll_right (int n); -void scroll_down(int n); -void scroll_up(int n); -struct ent * left_limit(); -struct ent * right_limit(int row); -struct ent * goto_top(); -struct ent * goto_bottom(); -struct ent * tick(char c); // 'tick' ( ' ) command -struct ent * forw_row(int arg); -struct ent * back_row(int arg); -struct ent * forw_col(int arg); -struct ent * back_col(int arg); -struct ent * go_home(); -struct ent * go_end(); -struct ent * go_forward(); -struct ent * go_backward(); -struct ent * vert_top(); -struct ent * vert_middle(); -struct ent * vert_bottom(); -struct ent * go_bol(); -struct ent * go_eol(); -struct ent * horiz_middle(); -struct ent * goto_last_col(); -void select_inner_range(int * vir_tlrow, int * vir_tlcol, int * vir_brrow, int * vir_brcol); -void ljustify(int sr, int sc, int er, int ec); -void rjustify(int sr, int sc, int er, int ec); -void center(int sr, int sc, int er, int ec); -void doformat(int c1, int c2, int w, int p, int r); -void dorowformat(int r, unsigned char size); -struct enode; -int etype(struct enode *e); -void erase_area(int sr, int sc, int er, int ec, int ignorelock, int mark_ent_as_deleted); -void auto_justify(int ci, int cf, int min); -void valueize_area(int sr, int sc, int er, int ec); -void sync_refs(); -void syncref(struct enode * e); -int fcopy(char * action); -int fsum(); -int pad(int n, int r1, int c1, int r2, int c2); -void fix_row_hidden(int deltar, int ri, int rf); -void fix_col_hidden(int deltac, int ci, int cf); -void fix_row_frozen(int deltar, int ri, int rf); -void fix_col_frozen(int deltac, int ci, int cf); - -void mark_ent_as_deleted(struct ent * p, int del); -int calc_mobile_rows(int *); -int calc_mobile_cols(int *); -void pad_and_align (char * str_value, char * numeric_value, int col_width, int align, int padding, wchar_t * str_out, int rowfmt); diff -Nru sc-im-0.8.2+ds/src/cmds_insert.c sc-im-0.8.3+ds/src/cmds_insert.c --- sc-im-0.8.2+ds/src/cmds_insert.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_insert.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,293 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_insert.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include - -#include "cmds_insert.h" -#include "cmds.h" -#include "tui.h" -#include "buffer.h" -#include "sc.h" // for rescol -#include "utils/string.h" -#include "marks.h" -#include "cmds_visual.h" -#include "conf.h" - -#ifdef INS_HISTORY_FILE -char ori_insert_edit_submode; -#endif - -extern void ins_in_line(wint_t d); - -/** - * \brief TODO Document do_insertmode() - * - * \param[in] sb - * - * returns: none - */ - -void do_insertmode(struct block * sb) { - - if (sb->value == ctl('v') ) { // VISUAL SUBMODE - visual_submode = insert_edit_submode; - chg_mode('v'); - start_visualmode(currow, curcol, currow, curcol); - return; - - } else if (sb->value == OKEY_LEFT) { // LEFT - if (inputline_pos) { - real_inputline_pos--; - int l = wcwidth(inputline[real_inputline_pos]); - inputline_pos -= l; - } - ui_show_header(); - return; - - } else if (sb->value == OKEY_RIGHT) { // RIGHT - int max = wcswidth(inputline, wcslen(inputline)); - if (inputline_pos < max) { - int l = wcwidth(inputline[real_inputline_pos++]); - inputline_pos += l; - } - ui_show_header(); - return; - -#ifdef INS_HISTORY_FILE - } else if (sb->value == OKEY_UP || sb->value == ctl('p') || // UP - sb->value == OKEY_DOWN || sb->value == ctl('n')) { // DOWN - - int delta = 0, i, cmp; - if (sb->value == OKEY_UP || sb->value == ctl('p')) { // up - for (i=insert_history->pos; -i+1 < insert_history->len; i--, delta--) - if (wcslen(get_line_from_history(insert_history, 0))) { - if (! (cmp = wcsncmp(inputline, &get_line_from_history(insert_history, i-1)[1], wcslen(get_line_from_history(insert_history, 0))))) { - delta--; - break; - } else if (insert_history->len == 2-i && cmp) { - delta=0; - break; - } - } else if (!wcslen(get_line_from_history(insert_history, 0))) { - delta--; - break; - } - } else if (sb->value == OKEY_DOWN || sb->value == ctl('n')) { // down - for (i=insert_history->pos; i != 0; i++, delta++) - if (wcslen(get_line_from_history(insert_history, 0))) { - if (! (cmp = wcsncmp(inputline, &get_line_from_history(insert_history, i+1)[1], wcslen(get_line_from_history(insert_history, 0))))) { - delta++; - break; - } else if (insert_history->pos == 0 && cmp) { - delta=0; - break; - } - } else if (!wcslen(get_line_from_history(insert_history, 0))) { - delta++; - break; - } - } - insert_history->pos += delta; - - wchar_t word [COLS]; - wcscpy(word, get_line_from_history(insert_history, insert_history->pos)); - if (insert_history->pos == 0) - insert_edit_submode = ori_insert_edit_submode; - else { - insert_edit_submode = word[0]; - del_wchar(word, 0); - } - wcscpy(inputline, word); - inputline_pos = wcswidth(inputline, real_inputline_pos); - - chg_mode(insert_edit_submode); - ui_show_header(); - return; -#endif - - } else if (sb->value == OKEY_BS || sb->value == OKEY_BS2) { // BS - if ( ! wcslen(inputline) || ! real_inputline_pos ) return; - - int l = wcwidth(inputline[real_inputline_pos - 1]); - real_inputline_pos--; - del_wchar(inputline, real_inputline_pos); - inputline_pos -= l; - ui_show_header(); -#ifdef INS_HISTORY_FILE - if (insert_history->pos == 0) - del_wchar(get_line_from_history(insert_history, insert_history->pos), real_inputline_pos); // Clean history -#endif - - } else if (sb->value == OKEY_DEL) { // DEL - int max = wcswidth(inputline, wcslen(inputline)); - if (inputline_pos > max) return; - del_wchar(inputline, real_inputline_pos); -#ifdef INS_HISTORY_FILE - if (insert_history->pos == 0) - del_wchar(get_line_from_history(insert_history, insert_history->pos), real_inputline_pos); // Clean history -#endif - ui_show_header(); - - } else if (sb->value == OKEY_TAB) { // TAB - if (inputline_pos && wcslen(inputline) >= inputline_pos) { - real_inputline_pos--; - int l = wcwidth(inputline[real_inputline_pos]); - inputline_pos -= l; - } - chg_mode(insert_edit_submode == '=' ? 'e' : 'E'); - ui_show_header(); - - } else if (find_val(sb, OKEY_ENTER)) { // ENTER - char ope[BUFFERSIZE] = ""; - wchar_t content[BUFFERSIZE] = L""; - wcscpy(content, inputline); - - switch (insert_edit_submode) { - case '=': - strcpy(ope, "let"); - break; - case '<': - strcpy(ope, "leftstring"); - break; - case '>': - strcpy(ope, "rightstring"); - break; - case '\\': - strcpy(ope, "label"); - break; - } - - if (content[0] == L'"') { - del_wchar(content, 0); - } else if (insert_edit_submode != '=' && content[0] != L'"') { - add_wchar(content, L'\"', 0); - add_wchar(content, L'\"', wcslen(content)); - } - - enter_cell_content(currow, curcol, ope, content); - -#ifdef INS_HISTORY_FILE - /* - * if exists in history an item with same text to the command typed - * (counting from the second position) it is moved to the beginning of list. - * (first element in list means last command executed) - */ - del_item_from_history(insert_history, 0); - wchar_t copy[BUFFERSIZE]; - - swprintf(copy, BUFFERSIZE, L"%c%ls", insert_edit_submode, inputline); - int moved = move_item_from_history_by_str(insert_history, copy, -1); - if (! moved) add(insert_history, copy); - insert_history->pos = 0; -#endif - - inputline[0] = L'\0'; - inputline_pos = 0; - real_inputline_pos = 0; - chg_mode('.'); - //ui_clr_header(1); - - char * opt = get_conf_value("newline_action"); - switch (opt[0]) { - case 'j': - currow = forw_row(1)->row; - break; - case 'l': - curcol = forw_col(1)->col; - break; - } - ui_update(TRUE); - return; - - - } else if (sb->value == OKEY_HOME) { // HOME - real_inputline_pos = 0; - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - } else if (sb->value == OKEY_END) { // END - real_inputline_pos = wcslen(inputline); - inputline_pos = wcswidth(inputline, real_inputline_pos); - ui_show_header(); - return; - - // Write new char !! - //} else if ( wcslen(inputline) < (COLS - 16) && sc_isprint(sb->value)) { - } else if ( sc_isprint(sb->value)) { - //DEBUG sc_info("2: %d %lc", sb->value, sb->value); - ins_in_line(sb->value); - ui_show_header(); -#ifdef INS_HISTORY_FILE - if (insert_history->pos == 0) { // Only if editing the new command - wchar_t * sl = get_line_from_history(insert_history, 0); - add_wchar(sl, sb->value, real_inputline_pos-1); // Insert into history - } -#endif - - } else if (sb->value == ctl('r') && get_bufsize(sb) == 2 && // C-r // FIXME ??? - (sb->pnext->value - (L'a' - 1) < 1 || sb->pnext->value > 26)) { - wchar_t cline [BUFFERSIZE]; - int i, r = get_mark(sb->pnext->value)->row; - if (r != -1) { - swprintf(cline, BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->col), r); - } else { - swprintf(cline, BUFFERSIZE, L"%s%d:", coltoa(get_mark(sb->pnext->value)->rng->tlcol), get_mark(sb->pnext->value)->rng->tlrow); - swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->rng->brcol), get_mark(sb->pnext->value)->rng->brrow); - } - for(i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]); - -#ifdef INS_HISTORY_FILE - if (commandline_history->pos == 0) { // Only if editing the new command - wchar_t * sl = get_line_from_history(commandline_history, 0); - wcscat(sl, cline); // Insert into history - } -#endif - ui_show_header(); - return; - } - return; -} diff -Nru sc-im-0.8.2+ds/src/cmds_insert.h sc-im-0.8.3+ds/src/cmds_insert.h --- sc-im-0.8.2+ds/src/cmds_insert.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_insert.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_insert.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for cmds_insert.c - */ - -#include "input.h" - -#ifdef INS_HISTORY_FILE -#include "history.h" -extern struct history * insert_history; -#endif - -void do_insertmode(struct block * sb); diff -Nru sc-im-0.8.2+ds/src/cmds_normal.c sc-im-0.8.3+ds/src/cmds_normal.c --- sc-im-0.8.2+ds/src/cmds_normal.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_normal.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1180 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_normal.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include - -#include "yank.h" -#include "marks.h" -#include "cmds.h" -#include "conf.h" -#include "tui.h" -#include "cmds_edit.h" -#include "history.h" -#include "hide_show.h" -#include "shift.h" -#include "main.h" // for sig_winchg -#include "interp.h" -#include "freeze.h" -#include "utils/extra.h" -#ifdef UNDO -#include "undo.h" -#endif - - -#include "dep_graph.h" -extern graphADT graph; -extern char valores; -extern int cmd_multiplier; -extern void start_visualmode(int tlrow, int tlcol, int brrow, int brcol); -extern void ins_in_line(wint_t d); -extern void openfile_under_cursor(int r, int c); - -extern wchar_t interp_line[BUFFERSIZE]; - -#ifdef HISTORY_FILE -extern struct history * commandline_history; -#endif - -#ifdef INS_HISTORY_FILE -extern struct history * insert_history; -extern char ori_insert_edit_submode; -#endif - -/** - * \brief TODO Document do_normalmode() - * - * \param[in] buf - * - * \return none - */ - -void do_normalmode(struct block * buf) { - int bs = get_bufsize(buf); - struct ent * e; - - switch (buf->value) { - // FOR TEST PURPOSES - case L'A': - //; - //wchar_t t = ui_query_opt(L"show a message. q / a / d to quit", L"qad"); - break; - - case L'W': - break; - - case L'Q': - break; - - // MOVEMENT COMMANDS - case L'j': - case OKEY_DOWN: - lastcol = curcol; - lastrow = currow; - currow = forw_row(1)->row; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'k': - case OKEY_UP: - lastcol = curcol; - lastrow = currow; - currow = back_row(1)->row; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'h': - case OKEY_LEFT: - lastrow = currow; - lastcol = curcol; - curcol = back_col(1)->col; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'l': - case OKEY_RIGHT: - lastrow = currow; - lastcol = curcol; - curcol = forw_col(1)->col; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'0': - if (get_conf_int("numeric_zero") == 1 && get_conf_int("numeric") == 1) goto numeric; - case OKEY_HOME: - lastrow = currow; - lastcol = curcol; - curcol = left_limit()->col; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'$': - case OKEY_END: - lastrow = currow; - lastcol = curcol; - curcol = right_limit(currow)->col; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'^': - lastcol = curcol; - lastrow = currow; - currow = goto_top()->row; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'#': - lastcol = curcol; - lastrow = currow; - currow = goto_bottom()->row; - if (currow == lastrow && curcol == lastcol) currow = go_end()->row; - unselect_ranges(); - ui_update(TRUE); - break; - - // Tick - case L'\'': - if (bs != 2) break; - unselect_ranges(); - e = tick(buf->pnext->value); - if (row_hidden[e->row]) { - sc_error("Cell row is hidden"); - break; - } - if (col_hidden[e->col]) { - sc_error("Cell column is hidden"); - break; - } - lastrow = currow; - lastcol = curcol; - currow = e->row; - curcol = e->col; - ui_update(TRUE); - break; - - // CTRL j - case ctl('j'): - { - int p, c = curcol, cf = curcol; - if ( (p = is_range_selected()) != -1) { - struct srange * sr = get_range_by_pos(p); - c = sr->tlcol; - cf = sr->brcol; - } - auto_justify(c, cf, DEFWIDTH); // auto justify columns - ui_update(TRUE); - break; - } - - // CTRL d - case ctl('d'): // set date format using current locate D_FMT format - { - #ifdef USELOCALE - #include - #include - char * loc = NULL; - char * f = NULL; - loc = setlocale(LC_TIME, ""); - if (loc != NULL) { - f = nl_langinfo(D_FMT); - } else { - sc_error("No locale set. Nothing changed"); - } - int p, r = currow, c = curcol, rf = currow, cf = curcol; - if ( (p = is_range_selected()) != -1) { - struct srange * sr = get_range_by_pos(p); - r = sr->tlrow; - c = sr->tlcol; - rf = sr->brrow; - cf = sr->brcol; - } - if (any_locked_cells(r, c, rf, cf)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } - dateformat(lookat(r, c), lookat(rf, cf), f); - ui_update(TRUE); - break; - #else - sc_info("Build made without USELOCALE enabled"); - #endif - } - - // CTRL f - case ctl('f'): - case OKEY_PGDOWN: - { - int n = calc_mobile_rows(NULL); - if (get_conf_int("half_page_scroll")) n = n / 2; - lastcol = curcol; - lastrow = currow; - currow = forw_row(n)->row; - unselect_ranges(); - scroll_down(n); - ui_update(TRUE); - break; - } - - // CTRL b - case ctl('b'): - case OKEY_PGUP: - { - int n = calc_mobile_rows(NULL); - if (get_conf_int("half_page_scroll")) n = n / 2; - lastcol = curcol; - lastrow = currow; - currow = back_row(n)->row; - unselect_ranges(); - scroll_up(n); - ui_update(TRUE); - break; - } - - case L'w': - e = go_forward(); - lastrow = currow; - lastcol = curcol; - currow = e->row; - curcol = e->col; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'b': - e = go_backward(); - lastrow = currow; - lastcol = curcol; - currow = e->row; - curcol = e->col; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'H': - lastrow = currow; - int currow_h = vert_top()->row; - currow = currow_h; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'M': - lastrow = currow; - currow = vert_middle()->row; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'L': - lastrow = currow; - currow = vert_bottom()->row; - unselect_ranges(); - ui_update(TRUE); - break; - - case L'G': // goto end - e = go_end(); - lastrow = currow; - lastcol = curcol; - currow = e->row; - curcol = e->col; - unselect_ranges(); - ui_update(TRUE); - break; - - // GOTO goto - case ctl('a'): - e = go_home(); - lastrow = currow; - lastcol = curcol; - curcol = e->col; - currow = e->row; - unselect_ranges(); - offscr_sc_rows = 0; - offscr_sc_cols = 0; - ui_update(TRUE); - break; - - case L'g': - if (buf->pnext->value == L'0') { // g0 - lastcol = curcol; - lastrow = currow; - curcol = go_bol()->col; - - } else if (buf->pnext->value == L'$') { // g$ - lastcol = curcol; - lastrow = currow; - curcol = go_eol()->col; - - } else if (buf->pnext->value == L'f') { // gf - unselect_ranges(); - ui_update(TRUE); - ui_stop_screen(); - openfile_under_cursor(currow, curcol); - ui_start_screen(); - start_default_ucolors(); - set_colors_param_dict(); - - } else if (buf->pnext->value == L'g') { // gg - e = go_home(); - lastcol = curcol; - lastrow = currow; - curcol = e->col; - currow = e->row; - offscr_sc_rows = 0; - offscr_sc_cols = 0; - - } else if (buf->pnext->value == L'G') { // gG - e = go_end(); - lastcol = curcol; - lastrow = currow; - currow = e->row; - curcol = e->col; - - } else if (buf->pnext->value == L'M') { // gM - lastcol = curcol; - lastrow = currow; - curcol = horiz_middle()->col; - - // goto last cell position - } else if (buf->pnext->value == L'l') { // gl - int newlr = currow; - int newlc = curcol; - curcol = lastcol; - currow = lastrow; - lastrow = newlr; - lastcol = newlc; - } else if (buf->pnext->value == L't') { // gtA4 (goto cell A4) - (void) swprintf(interp_line, BUFFERSIZE, L"goto %s", parse_cell_name(2, buf)); - send_to_interp(interp_line); - } - unselect_ranges(); - ui_update(TRUE); - break; - - // repeat last goto command - backwards - case L'N': - go_previous(); - ui_update(TRUE); - break; - - // repeat last goto command - case L'n': - go_last(); - ui_update(TRUE); - break; - - // END OF MOVEMENT COMMANDS - - case L'/': - { - char cadena[] = ":int goto "; - int i; - for (i=0; i': - if (locked_cell(currow, curcol)) return; - insert_edit_submode = buf->value; - chg_mode(insert_edit_submode); -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = buf->value; - add(insert_history, L""); -#endif - inputline_pos = 0; - real_inputline_pos = 0; - ui_show_header(); - break; - - // EDITION COMMANDS - // edit cell (v) - case L'e': - if (locked_cell(currow, curcol)) return; - inputline_pos = 0; - real_inputline_pos = 0; - if (start_edit_mode(buf, 'v')) ui_show_header(); - break; - - // edit cell (s) - case L'E': - if (locked_cell(currow, curcol)) return; - inputline_pos = 0; - real_inputline_pos = 0; - if (start_edit_mode(buf, 's')) ui_show_header(); - else { - sc_info("No string value to edit"); - chg_mode('.'); - ui_print_mode(); - ui_show_celldetails(); - } - break; - - // del current cell or range - case L'x': - del_selected_cells(); - ui_update(TRUE); - break; - - // format col or freeze range - case L'f': - if (bs != 2) return; - - // freeze row / column or area - if (buf->pnext->value == 'r' || buf->pnext->value == 'c' || buf->pnext->value == 'a') { - int p = is_range_selected(), r = currow, c = curcol, rf = currow, cf = curcol; - - if (p != -1) { // mark range - struct srange * sr = get_range_by_pos(p); - r = sr->tlrow; - c = sr->tlcol; - rf = sr->brrow; - cf = sr->brcol; - } - - if (buf->pnext->value == 'r') { - handle_freeze(lookat(r, c), lookat(rf, cf), 1, 'r'); - sc_info("Row%s frozen", r != rf ? "s" : ""); - } else if (buf->pnext->value == 'c') { - handle_freeze(lookat(r, c), lookat(rf, cf), 1, 'c'); - sc_info("Column%s frozen", c != cf ? "s" : ""); - } else if (buf->pnext->value == 'a') { - handle_freeze(lookat(r, c), lookat(rf, cf), 1, 'r'); - handle_freeze(lookat(r, c), lookat(rf, cf), 1, 'c'); - sc_info("Area frozen"); - } - ui_update(FALSE); - break; - - // decrease row height - } else if (buf->pnext->value == 'k' || buf->pnext->value == OKEY_UP) { - -#ifdef UNDO - create_undo_action(); - int fmt_ori = row_format[currow]; - add_undo_row_format(currow, 'R', row_format[currow]); -#endif - swprintf(interp_line, BUFFERSIZE, L"format %d %d", currow, row_format[currow]-1); - send_to_interp(interp_line); -#ifdef UNDO - if (row_format[currow] != fmt_ori) { - add_undo_row_format(currow, 'A', row_format[currow]); - end_undo_action(); - } else dismiss_undo_item(NULL); -#endif - ui_update(TRUE); - break; - - // increase row height - } else if (buf->pnext->value == 'j' || buf->pnext->value == OKEY_DOWN) { - -#ifdef UNDO - create_undo_action(); - int fmt_ori = row_format[currow]; - add_undo_row_format(currow, 'R', row_format[currow]); -#endif - swprintf(interp_line, BUFFERSIZE, L"format %d %d", currow, row_format[currow]+1); - send_to_interp(interp_line); -#ifdef UNDO - if (row_format[currow] != fmt_ori) { - add_undo_row_format(currow, 'A', row_format[currow]); - end_undo_action(); - } else dismiss_undo_item(NULL); -#endif - ui_update(TRUE); - break; - - // change in format - } else { -#ifdef UNDO - create_undo_action(); - add_undo_col_format(curcol, 'R', fwidth[curcol], precision[curcol], realfmt[curcol]); -#endif - formatcol(buf->pnext->value); -#ifdef UNDO - add_undo_col_format(curcol, 'A', fwidth[curcol], precision[curcol], realfmt[curcol]); - end_undo_action(); -#endif - } - break; - - // mark cell or range - case L'm': - if (bs != 2) break; - int p = is_range_selected(); - if (p != -1) { // mark range - struct srange * sr = get_range_by_pos(p); - set_range_mark(buf->pnext->value, sr); - } else // mark cell - set_cell_mark(buf->pnext->value, currow, curcol); - modflg++; - break; - - // copy - case L'c': - { - if (bs != 2) break; - struct mark * m = get_mark(buf->pnext->value); - if ( m == NULL) return; - - - // if m represents a range - if ( m->row == -1 && m->col == -1) { - srange * r = m->rng; - yank_area(r->tlrow, r->tlcol, r->brrow, r->brcol, 'a', cmd_multiplier); - if (paste_yanked_ents(0, 'c') == -1) { - sc_error("Locked cells encountered. Nothing changed"); - break; - } - - // if m represents just one cell - } else { - struct mark * m = get_mark(buf->pnext->value); - struct ent * p = lookat(m->row, m->col); - struct ent * n; - int c1; - -#ifdef UNDO - create_undo_action(); -#endif - for (c1 = curcol; cmd_multiplier-- && cmd_multiplier > -1 && c1 < maxcols; c1++) { - if ((n = * ATBL(tbl, currow, c1))) { - if (n->flags & is_locked) - continue; - if (! p) { - clearent(n); - continue; - } - } else { - if (! p) break; - n = lookat(currow, c1); - } -#ifdef UNDO - // added for #244 - 22/03/2018 - ents_that_depends_on_range(n->row, n->col, n->row, n->col); - copy_to_undostruct(currow, c1, currow, c1, UNDO_DEL, HANDLE_DEPS, NULL); -#endif - copyent(n, p, currow - get_mark(buf->pnext->value)->row, c1 - get_mark(buf->pnext->value)->col, 0, 0, maxrow, maxcol, 0); - - n->row += currow - get_mark(buf->pnext->value)->row; - n->col += c1 - get_mark(buf->pnext->value)->col; - - n->flags |= is_changed; - if (n->expr) EvalJustOneVertex(n, 1); - -#ifdef UNDO - copy_to_undostruct(currow, c1, currow, c1, UNDO_ADD, HANDLE_DEPS, NULL); -#endif - } -#ifdef UNDO - extern struct ent_ptr * deps; - if (deps != NULL) free(deps); - deps = NULL; - end_undo_action(); -#endif - } - - ui_update(TRUE); - break; - } - - // range lock / unlock / valueize - case L'r': - { - int p, r = currow, c = curcol, rf = currow, cf = curcol; - if ( (p = is_range_selected()) != -1) { - struct srange * sr = get_range_by_pos(p); - r = sr->tlrow; - c = sr->tlcol; - rf = sr->brrow; - cf = sr->brcol; - } - if (buf->pnext->value == L'l') { - lock_cells(lookat(r, c), lookat(rf, cf)); - } else if (buf->pnext->value == L'u') { // watch out if you do C-r and u too quickly ! - unlock_cells(lookat(r, c), lookat(rf, cf)); - } else if (buf->pnext->value == L'v') { - valueize_area(r, c, rf, cf); - } - ui_update(TRUE); - break; - } - - // create range with two marks - case L'R': - if (bs == 3) { - create_range(buf->pnext->value, buf->pnext->pnext->value, NULL, NULL); - ui_update(TRUE); - } - break; - - // Zr Zc - Zap col or row - Show col or row - Sr Sc - case L'Z': - case L'S': - { - int rs, r = currow, c = curcol, arg = cmd_multiplier; - struct srange * sr; - if ( (rs = is_range_selected()) != -1) { - sr = get_range_by_pos(rs); - cmd_multiplier = 1; - r = sr->tlrow; - c = sr->tlcol; - arg = buf->pnext->value == L'r' ? sr->brrow - sr->tlrow + 1 : sr->brcol - sr->tlcol + 1; - } - if (buf->value == L'Z' && buf->pnext->value == L'r') { - hide_row(r, arg); - } else if (buf->value == L'Z' && buf->pnext->value == L'c') { - hide_col(c, arg); - } else if (buf->value == L'S' && buf->pnext->value == L'r') { - show_row(r, arg); - } else if (buf->value == L'S' && buf->pnext->value == L'c') { - show_col(c, arg); - } - cmd_multiplier = 0; - ui_update(TRUE); - break; - } - - // shift range or cell - case L's': - { - int p, r = currow, c = curcol, rf = currow, cf = curcol; - if ( (p = is_range_selected()) != -1) { - struct srange * sr = get_range_by_pos(p); - r = sr->tlrow; - c = sr->tlcol; - rf = sr->brrow; - cf = sr->brcol; - } - shift(r, c, rf, cf, buf->pnext->value); - unselect_ranges(); - ui_update(TRUE); - break; - } - - // delete row or column, or selected cell or range - case L'd': - { - if (bs != 2) return; - int ic = cmd_multiplier; // orig - - // deleterow - if (buf->pnext->value == L'r') { - deleterow(currow, ic); - if (cmd_multiplier > 1) cmd_multiplier = 0; - - // deletecol - } else if (buf->pnext->value == L'c') { - deletecol(curcol, ic); - if (cmd_multiplier > 1) cmd_multiplier = 0; - - } else if (buf->pnext->value == L'd') { - del_selected_cells(); - } - - ui_update(TRUE); - break; - } - - // insert row or column - case L'i': - { - if (bs != 2) return; -#ifdef UNDO - create_undo_action(); -#endif - - if (buf->pnext->value == L'r') { -#ifdef UNDO - save_undo_range_shift(1, 0, currow, 0, currow, maxcol); -#endif - fix_marks(1, 0, currow, maxrow, 0, maxcol); - insert_row(0); -#ifdef UNDO - add_undo_row_format(currow, 'A', row_format[currow]); -#endif - - } else if (buf->pnext->value == L'c') { -#ifdef UNDO - save_undo_range_shift(0, 1, 0, curcol, maxrow, curcol); -#endif - fix_marks(0, 1, 0, maxrow, curcol, maxcol); - insert_col(0); -#ifdef UNDO - add_undo_col_format(curcol, 'A', fwidth[curcol], precision[curcol], realfmt[curcol]); -#endif - } -#ifdef UNDO - end_undo_action(); -#endif - ui_update(TRUE); - break; - } - - // open row or column - case L'o': - { - if (bs != 2) return; -#ifdef UNDO - create_undo_action(); -#endif - if (buf->pnext->value == L'r') { -#ifdef UNDO - save_undo_range_shift(1, 0, currow+1, 0, currow+1, maxcol); -#endif - fix_marks(1, 0, currow+1, maxrow, 0, maxcol); - insert_row(1); -#ifdef UNDO - add_undo_row_format(currow, 'A', row_format[currow]); -#endif - - } else if (buf->pnext->value == L'c') { -#ifdef UNDO - save_undo_range_shift(0, 1, 0, curcol+1, maxrow, curcol+1); -#endif - fix_marks(0, 1, 0, maxrow, curcol+1, maxcol); - insert_col(1); -#ifdef UNDO - add_undo_col_format(curcol, 'A', fwidth[curcol], precision[curcol], realfmt[curcol]); -#endif - } -#ifdef UNDO - end_undo_action(); -#endif - ui_update(TRUE); - break; - } - - case L'y': - // yank row - if ( bs == 2 && buf->pnext->value == L'r') { - yank_area(currow, 0, currow + cmd_multiplier - 1, maxcol, 'r', cmd_multiplier); - if (cmd_multiplier > 1) cmd_multiplier = 0; - - // yank col - } else if ( bs == 2 && buf->pnext->value == L'c') { - yank_area(0, curcol, maxrow, curcol + cmd_multiplier - 1, 'c', cmd_multiplier); - if (cmd_multiplier > 1) cmd_multiplier = 0; - - // yank cell - } else if ( bs == 2 && buf->pnext->value == L'y' && is_range_selected() == -1) { - yank_area(currow, curcol, currow, curcol, 'e', cmd_multiplier); - - // yank range - } else if ( bs == 1 && is_range_selected() != -1) { - srange * r = get_selected_range(); - yank_area(r->tlrow, r->tlcol, r->brrow, r->brcol, 'a', cmd_multiplier); - } - break; - - // paste cell below or left - case L'p': - if (paste_yanked_ents(0, 'a') == -1) { - sc_error("Locked cells encountered. Nothing changed"); - break; - } - ui_update(TRUE); - break; - - case L'P': - case L'T': - if (bs != 2) break; - if (buf->pnext->value == L'v' || buf->pnext->value == L'f' || buf->pnext->value == L'c') { - int res = buf->value == L'P' ? paste_yanked_ents(0, buf->pnext->value) : paste_yanked_ents(1, buf->pnext->value); // paste cell above or right - if (res == -1) { - sc_error("Locked cells encountered. Nothing changed"); - break; - } - ui_update(TRUE); - } - break; - - // paste cell above or right - case L't': - if (paste_yanked_ents(1, 'a') == -1) { - sc_error("Locked cells encountered. Nothing changed"); - break; - } - ui_update(TRUE); - break; - - // select inner range - Vir - case L'V': - if (buf->value == L'V' && bs == 3 && - buf->pnext->value == L'i' && buf->pnext->pnext->value == L'r') { - int tlrow = currow; - int brrow = currow; - int tlcol = curcol; - int brcol = curcol; - int * tlr = &tlrow; - int * brr = &brrow; - int * tlc = &tlcol; - int * brc = &brcol; - select_inner_range(tlr, tlc, brr, brc); - start_visualmode(*tlr, *tlc, *brr, *brc); - } - break; - - // autojus - case L'a': - if ( bs != 2 ) break; - - if (buf->pnext->value == L'a') { - int p, r = currow, c = curcol, rf = currow, cf = curcol; - if ( (p = is_range_selected()) != -1) { - struct srange * sr = get_range_by_pos(p); - r = sr->tlrow; - c = sr->tlcol; - rf = sr->brrow; - cf = sr->brcol; - } - if (any_locked_cells(r, c, rf, cf)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } - wchar_t cline [BUFFERSIZE]; - swprintf(cline, BUFFERSIZE, L"autojus %s:", coltoa(c)); - swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s", coltoa(cf)); - send_to_interp(cline); - ui_update(TRUE); - } - break; - - // scroll - case L'z': - if ( bs != 2 ) break; - int scroll = 0; - - switch (buf->pnext->value) { - case L'l': - scroll_right(1); - break; - - case L'h': - scroll_left(1); - break; - - case L'H': - scroll = calc_mobile_cols(NULL); - if (get_conf_int("half_page_scroll")) scroll /= 2; - scroll_left(scroll); - break; - - case L'L': - scroll = calc_mobile_cols(NULL); - if (get_conf_int("half_page_scroll")) scroll /= 2; - scroll_right(scroll); - break; - - case L'm': - ; - int i = 0, c = 0, ancho = rescol; - offscr_sc_cols = 0; - for (i = 0; i < curcol; i++) { - for (c = i; c < curcol; c++) { - if (!col_hidden[c]) ancho += fwidth[c]; - if (ancho >= (COLS - rescol)/ 2) { - ancho = rescol; - break; - } - } - if (c == curcol) break; - } - offscr_sc_cols = i; - break; - - case L't': - case L'b': - case L'z': - case L'.': - { - int i = 0, r = offscr_sc_rows-1; - - if (buf->pnext->value == L't') { - while (i < LINES - RESROW - 1 && r < currow) { - r++; - if (row_frozen[r]) continue; - i++; - } - scroll_down(--i); - - } else if (buf->pnext->value == L'b') { - int hidden = 0; - while (i < LINES - RESROW - 1) { - r++; - if (row_hidden[r]) { hidden++; continue; } - else if (r < offscr_sc_rows && ! (row_frozen[r])) continue; - else if (row_frozen[r]) continue; - i++; - } - scroll_up(r-currow-hidden); - - } else if (buf->pnext->value == L'z' || buf->pnext->value == L'.') { - while (i < LINES - RESROW - 1 && r <= currow) { - r++; - if (row_frozen[r]) continue; - i++; - } - int top = --i; - i = 0, r = offscr_sc_rows-1; - while (i < LINES - RESROW - 1) { - r++; - if (r < offscr_sc_rows && ! (row_frozen[r])) continue; - i++; - } - int bottom = r-currow; - int scroll = (-top + bottom)/2; - if (scroll < 0) - scroll_down(-scroll); - else if (scroll > 0) - scroll_up(scroll); - } - break; - } - } - ui_update(TRUE); - break; - - // scroll up a line - case ctl('y'): - scroll_up(1); - ui_update(TRUE); - break; - - // scroll down a line - case ctl('e'): - scroll_down(1); - ui_update(TRUE); - break; - - // undo - case L'u': - #ifdef UNDO - do_undo(); - ui_update(TRUE); - #else - sc_error("Build was done without UNDO support"); - #endif - break; - - // redo - case ctl('r'): - #ifdef UNDO - do_redo(); - ui_update(TRUE); - #else - sc_error("Build was done without UNDO support"); - #endif - break; - - case L'{': // left align - case L'}': // right align - case L'|': // center align - { - int p, r = currow, c = curcol, rf = currow, cf = curcol; - struct srange * sr; - if ( (p = is_range_selected()) != -1) { - sr = get_range_by_pos(p); - r = sr->tlrow; - c = sr->tlcol; - rf = sr->brrow; - cf = sr->brcol; - } - if (any_locked_cells(r, c, rf, cf)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } -#ifdef UNDO - create_undo_action(); -#endif - if (buf->value == L'{') swprintf(interp_line, BUFFERSIZE, L"leftjustify %s", v_name(r, c)); - else if (buf->value == L'}') swprintf(interp_line, BUFFERSIZE, L"rightjustify %s", v_name(r, c)); - else if (buf->value == L'|') swprintf(interp_line, BUFFERSIZE, L"center %s", v_name(r, c)); - if (p != -1) swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L":%s", v_name(rf, cf)); -#ifdef UNDO - copy_to_undostruct(r, c, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); -#endif - send_to_interp(interp_line); -#ifdef UNDO - copy_to_undostruct(r, c, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); -#endif - cmd_multiplier = 0; - ui_update(TRUE); - break; - } - - case ctl('l'): - sig_winchg(); - break; - - case L'@': - EvalAll(); - ui_update(TRUE); - break; - - // increase or decrease numeric value of cell or range - case L'-': - case L'+': - { - int r, c, tlrow = currow, tlcol = curcol, brrow = currow, brcol = curcol; - if ( is_range_selected() != -1 ) { - struct srange * sr = get_selected_range(); - tlrow = sr->tlrow; - tlcol = sr->tlcol; - brrow = sr->brrow; - brcol = sr->brcol; - } - if (any_locked_cells(tlrow, tlcol, brrow, brcol)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } - if (get_conf_int("numeric") == 1) goto numeric; - struct ent * p; -#ifdef UNDO - create_undo_action(); - copy_to_undostruct(tlrow, tlcol, brrow, brcol, UNDO_DEL, IGNORE_DEPS, NULL); -#endif - int arg = cmd_multiplier; - int mf = modflg; // keep original modflg - for (r = tlrow; r <= brrow; r++) { - for (c = tlcol; c <= brcol; c++) { - p = *ATBL(tbl, r, c); - if ( ! p ) { - continue; - } else if (p->expr && !(p->flags & is_strexpr)) { - //sc_error("Can't increment / decrement a formula"); - continue; - } else if (p->flags & is_valid) { - p->v += buf->value == L'+' ? (double) arg : - 1 * (double) arg; - if (mf == modflg) modflg++; // increase just one time - } - } - } -#ifdef UNDO - copy_to_undostruct(tlrow, tlcol, brrow, brcol, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); -#endif - if (get_conf_int("autocalc")) EvalRange(tlrow, tlcol, brrow, brcol); - cmd_multiplier = 0; - ui_update(TRUE); - } - break; - - // input of numbers - default: - numeric: - if ( (isdigit(buf->value) || buf->value == L'-' || buf->value == L'+' || - ( buf->value == L'.' && get_conf_int("numeric_decimal") )) && - get_conf_int("numeric") ) { - if (locked_cell(currow, curcol)) return; - insert_edit_submode='='; - chg_mode(insert_edit_submode); -#ifdef INS_HISTORY_FILE - ori_insert_edit_submode = buf->value; - add(insert_history, L""); -#endif - inputline_pos = 0; - real_inputline_pos = 0; - ins_in_line(buf->value); - ui_show_header(); - } - } - return; -} diff -Nru sc-im-0.8.2+ds/src/cmds_normal.h sc-im-0.8.3+ds/src/cmds_normal.h --- sc-im-0.8.2+ds/src/cmds_normal.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_normal.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_normal.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for cmds_normal.c - */ - -#include "input.h" -extern int shall_quit; - -void do_normalmode (struct block * buf); - -extern struct history * commandline_history; diff -Nru sc-im-0.8.2+ds/src/cmds_visual.c sc-im-0.8.3+ds/src/cmds_visual.c --- sc-im-0.8.2+ds/src/cmds_visual.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_visual.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,580 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_visuals.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include - -#include "utils/string.h" -#include "tui.h" -#include "buffer.h" -#include "marks.h" -#include "macros.h" -#include "cmds.h" -#include "conf.h" -#include "hide_show.h" -#include "shift.h" -#include "freeze.h" -#include "yank.h" -#include "history.h" -#include "interp.h" -#ifdef UNDO -#include "undo.h" -#endif - -extern int offscr_sc_rows, offscr_sc_cols; -extern unsigned int curmode; -extern int cmd_multiplier; -extern struct history * commandline_history; - -char visual_submode = '0'; -srange * r; // SELECTED RANGE! -int moving = FALSE; - -/** - * \brief TODO Document start_visualmode() - * - * \param[in] tlrow - * \param[in] tlcol - * \param[in] brrow - * \param[in] brcol - * - * \return none - */ - -void start_visualmode(int tlrow, int tlcol, int brrow, int brcol) { - unselect_ranges(); - - struct srange * sr = get_range_by_marks('\t', '\t'); // visual mode selected range - if (sr != NULL) del_ranges_by_mark('\t'); - - r = (srange *) malloc (sizeof(srange)); - r->tlrow = tlrow; - r->tlcol = tlcol; - r->brrow = brrow; - r->brcol = brcol; - r->orig_row = currow; // original row before starting selection - r->orig_col = curcol; // original col before starting selection - r->startup_row = currow; // original row position before entering visual mode - r->startup_col = curcol; // original col position before entering visual mode - r->marks[0] = '\t'; - r->marks[1] = '\t'; - r->selected = 1; - r->pnext = NULL; - - // add visual selected range at start of list - if (ranges == NULL) ranges = r; - else { - r->pnext = ranges; - ranges = r; - } - - if (visual_submode == '0') { // Started visual mode with 'v' command - ui_update(TRUE); - moving = FALSE; - } else { // Started visual mode with 'C-v' command - ui_update(TRUE); - moving = TRUE; - } - return; -} - -/** - * \brief TODO Document exit_visualmode() - * - * \return none - */ - -void exit_visualmode() { - moving = FALSE; - visual_submode = '0'; - r->selected = 0; - currow = r->startup_row; - curcol = r->startup_col; - del_ranges_by_mark('\t'); - return; -} - -/** - * \brief TODO Document do_visualmode() - * - * \param[in] buf - * - * \return none - */ - -void do_visualmode(struct block * buf) { - // we are moving (previous to a 'C-o' keypress) - if (moving == TRUE) { - switch (buf->value) { - case L'j': - case OKEY_DOWN: - currow = forw_row(1)->row; - break; - - case L'k': - case OKEY_UP: - currow = back_row(1)->row; - break; - - case L'h': - case OKEY_LEFT: - curcol = back_col(1)->col; - break; - - case L'l': - case OKEY_RIGHT: - curcol = forw_col(1)->col; - break; - - case ctl('o'): - moving = FALSE; - r->orig_row = currow; - r->orig_col = curcol; - break; - - case OKEY_ENTER: - sc_info("Press to begin selection or key to exit VISUAL MODE"); - return; - - } - r->tlrow = currow; - r->tlcol = curcol; - r->brrow = currow; - r->brcol = curcol; - - ui_update(FALSE); - return; - } - - // started visual mode with 'C-v' - // ENTER or 'C-k' : Confirm selection - // 'C-k' only works if started visualmode with 'C-v' - if ((buf->value == OKEY_ENTER || buf->value == ctl('k')) && visual_submode != '0') { - wchar_t cline [BUFFERSIZE]; - swprintf(cline, BUFFERSIZE, L"%ls%d", coltoa(r->tlcol), r->tlrow); - if (r->tlrow != r->brrow || r->tlcol != r->brcol) - swprintf(cline + wcslen(cline), BUFFERSIZE, L":%ls%d", coltoa(r->brcol), r->brrow); - swprintf(inputline + wcslen(inputline), BUFFERSIZE, L"%ls", cline); - - real_inputline_pos += wcslen(cline); - inputline_pos = wcswidth(inputline, real_inputline_pos); - - char c = visual_submode; - exit_visualmode(); - chg_mode(c); - - ui_show_header(); - return; - - // moving to TRUE - //} else if (buf->value == ctl('m')) { - // moving = TRUE; - - // MOVEMENT COMMANDS - // UP - ctl(b) - } else if (buf->value == OKEY_UP || buf->value == L'k' || buf->value == ctl('b') ) { - int n, i; - if (buf->value == ctl('b')) { - n = LINES - RESROW - 1; - if (get_conf_value("half_page_scroll")) n = n / 2; - } else n = 1; - - for (i=0; i < n; i++) - if (r->orig_row < r->brrow && r->tlrow < r->brrow) { - while (row_hidden[-- r->brrow]); - currow = r->brrow; - } else if (r->tlrow <= r->brrow && r->tlrow-1 >= 0) { - int newrow = r->tlrow; - while (newrow > 0 && row_hidden[-- newrow]); - if (!row_hidden[newrow]) { - currow = r->tlrow = newrow; - } - } - - // DOWN - ctl('f') - } else if (buf->value == OKEY_DOWN || buf->value == L'j' || buf->value == ctl('f')) { - int n, i; - if (buf->value == ctl('f')) { - n = LINES - RESROW - 1; - if (get_conf_value("half_page_scroll")) n = n / 2; - } else n = 1; - - for (i=0; i < n; i++) - if (r->orig_row <= r->tlrow && r->tlrow <= r->brrow) { - while (r->brrow+1 < maxrows && row_hidden[++ r->brrow]); - currow = r->brrow; - } else if (r->tlrow < r->brrow) { - while (row_hidden[++ r->tlrow]); - currow = r->tlrow; - } - - // LEFT - } else if (buf->value == OKEY_LEFT || buf->value == L'h') { - if (r->orig_col < r->brcol && r->tlcol < r->brcol) { - while (col_hidden[-- r->brcol]); - curcol = r->brcol; - } else if (r->tlcol <= r->brcol && r->tlcol-1 >= 0) { - while (col_hidden[-- r->tlcol]); - curcol = r->tlcol; - } - - // RIGHT - } else if (buf->value == OKEY_RIGHT || buf->value == L'l') { - if (r->orig_col <= r->tlcol && r->tlcol <= r->brcol && r->brcol+2 < maxcols) { - while (col_hidden[++ r->brcol]); - curcol = r->brcol; - } else if (r->tlcol <= r->brcol) { - while (col_hidden[++ r->tlcol]); - curcol = r->tlcol; - } - - // 0 - } else if (buf->value == L'0') { - r->brcol = r->tlcol; - r->tlcol = left_limit()->col; - curcol = r->tlcol; - - // $ - } else if (buf->value == L'$') { - int s = right_limit(currow)->col; - r->tlcol = r->brcol; - r->brcol = r->brcol > s ? r->brcol : s; - curcol = r->brcol; - - // ^ - } else if (buf->value == L'^') { - r->brrow = r->tlrow; - r->tlrow = goto_top()->row; - currow = r->tlrow; - - // # - } else if (buf->value == L'#') { - int s = goto_bottom()->row; - if (s == r->brrow) s = go_end()->row; - //r->tlrow = r->brrow; - r->brrow = r->brrow > s ? r->brrow : s; - //r->brrow = s; - currow = r->brrow; - - // ctl(a) - } else if (buf->value == ctl('a')) { - if (r->tlrow == 0 && r->tlcol == 0) return; - struct ent * e = go_home(); - r->tlrow = e->row; - r->tlcol = e->col; - r->brrow = r->orig_row; - r->brcol = r->orig_col; - currow = r->tlrow; - curcol = r->tlcol; - - // G - } else if (buf->value == L'G') { - struct ent * e = go_end(); - r->tlrow = r->orig_row; - r->tlcol = r->orig_col; - r->brrow = e->row; - r->brcol = e->col; - currow = r->tlrow; - curcol = r->tlcol; - - // ' - } else if (buf->value == L'\'') { - // if we receive a mark of a range, just return. - if (get_mark(buf->pnext->value)->row == -1) return; - - struct ent * e = tick(buf->pnext->value); - if (row_hidden[e->row]) { - sc_error("Cell row is hidden"); - return; - } else if (col_hidden[e->col]) { - sc_error("Cell column is hidden"); - return; - } - r->tlrow = r->tlrow < e->row ? r->tlrow : e->row; - r->tlcol = r->tlcol < e->col ? r->tlcol : e->col; - r->brrow = r->brrow > e->row ? r->brrow : e->row; - r->brcol = r->brcol > e->col ? r->brcol : e->col; - - // w - } else if (buf->value == L'w') { - struct ent * e = go_forward(); - if (e->col > r->orig_col) { - r->brcol = e->col; - r->tlcol = r->orig_col; - } else { - r->tlcol = e->col; - r->brcol = r->orig_col; - } - r->brrow = e->row; - r->tlrow = r->orig_row; - curcol = e->col; - currow = e->row; - - // b - } else if (buf->value == L'b') { - struct ent * e = go_backward(); - if (e->col <= r->orig_col) { - r->tlcol = e->col; - r->brcol = r->orig_col; - } else { - r->brcol = e->col; - r->tlcol = r->orig_col; - } - r->tlrow = e->row; - r->brrow = r->orig_row; - curcol = e->col; - currow = e->row; - - // H - } else if (buf->value == L'H') { - r->brrow = r->tlrow; - r->tlrow = vert_top()->row; - currow = r->tlrow; - - // M - } else if (buf->value == L'M') { - r->tlrow = r->orig_row; - int rm = vert_middle()->row; - if (r->orig_row < rm) r->brrow = rm; - else r->tlrow = rm; - currow = r->tlrow; - - // L - } else if (buf->value == L'L') { - r->tlrow = r->orig_row; - r->brrow = vert_bottom()->row; - currow = r->brrow; - - // mark a range - } else if (buf->value == L'm' && get_bufsize(buf) == 2) { - del_ranges_by_mark(buf->pnext->value); - srange * rn = create_range('\0', '\0', lookat(r->tlrow, r->tlcol), lookat(r->brrow, r->brcol)); - set_range_mark(buf->pnext->value, rn); - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // auto_justify - } else if (buf->value == ctl('j')) { - auto_justify(r->tlcol, r->brcol, DEFWIDTH); // auto justify columns - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // datefmt with locale D_FMT format - } else if (buf->value == ctl('d')) { - #ifdef USELOCALE - #include - #include - char * loc = NULL; - char * f = NULL; - loc = setlocale(LC_TIME, ""); - if (loc != NULL) { - f = nl_langinfo(D_FMT); - } else { - sc_error("No locale set. Nothing changed"); - } - if (any_locked_cells(r->tlrow, r->tlcol, r->brrow, r->brcol)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } - dateformat(lookat(r->tlrow, r->tlcol), lookat(r->brrow, r->brcol), f); - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - #else - sc_info("Build made without USELOCALE enabled"); - #endif - - // EDITION COMMANDS - // yank - } else if (buf->value == 'y') { - yank_area(r->tlrow, r->tlcol, r->brrow, r->brcol, 'a', 1); - - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // 'p' normal paste - // 'P' Works like 'p' except that all cell references are adjusted. - } else if (buf->value == 'P' || buf->value == 'p') { - struct ent * yl = get_yanklist(); - int type_paste = (buf->value == 'P') ? 'c' : 'a' ; - int row, col; - if( yl != NULL) { - int colsize = -(yl->col); //calculate colsize for correct repeating if paste area is bigger than yank area - int rowsize = -(yl->row); //calculate rowsize - while (yl->next != NULL) { yl = yl->next; } //get the last one to calculated size of yank_area - colsize += (yl->col +1); //calculate size - rowsize += (yl->row +1); //calculate size -#ifdef DEBUG - char str[20]; - sprintf(str, "RowSize:%d ColSize:%d Type Paste:%d", rowsize, colsize, type_paste); -#endif - for (row = r->tlrow; row <= r->brrow; row += rowsize) { - for (col = r->tlcol; col <= r->brcol; col += colsize) { - currow = row; - curcol = col; - paste_yanked_ents(0,type_paste); - } - } - exit_visualmode(); - chg_mode('.'); - ui_show_header(); -#ifdef DEBUG - sc_info(str); -#endif -#ifndef DEBUG - sc_info("Nice Pasting :-)"); -#endif - } - else{ - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - sc_info("Nothing to Paste"); - } - - // left / right / center align - } else if (buf->value == L'{' || buf->value == L'}' || buf->value == L'|') { - if (any_locked_cells(r->tlrow, r->tlcol, r->brrow, r->brcol)) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } - extern wchar_t interp_line[BUFFERSIZE]; - if (buf->value == L'{') swprintf(interp_line, BUFFERSIZE, L"leftjustify %s", v_name(r->tlrow, r->tlcol)); - else if (buf->value == L'}') swprintf(interp_line, BUFFERSIZE, L"rightjustify %s", v_name(r->tlrow, r->tlcol)); - else if (buf->value == L'|') swprintf(interp_line, BUFFERSIZE, L"center %s", v_name(r->tlrow, r->tlcol)); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L":%s", v_name(r->brrow, r->brcol)); -#ifdef UNDO - create_undo_action(); - copy_to_undostruct(r->tlrow, r->tlcol, r->brrow, r->brcol, UNDO_DEL, IGNORE_DEPS, NULL); -#endif - send_to_interp(interp_line); -#ifdef UNDO - copy_to_undostruct(r->tlrow, r->tlcol, r->brrow, r->brcol, UNDO_ADD, IGNORE_DEPS, NULL); - end_undo_action(); -#endif - cmd_multiplier = 0; - - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // freeze a range - } else if (buf->value == L'f') { - handle_freeze(lookat(r->tlrow, r->tlcol), lookat(r->brrow, r->brcol), 1, 'r'); - handle_freeze(lookat(r->tlrow, r->tlcol), lookat(r->brrow, r->brcol), 1, 'c'); - cmd_multiplier = 0; - - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - sc_info("Area frozen"); - - // range lock / unlock // valueize - } else if ( buf->value == L'r' && (buf->pnext->value == L'l' || buf->pnext->value == L'u' || - buf->pnext->value == L'v' )) { - if (buf->pnext->value == L'l') { - lock_cells(lookat(r->tlrow, r->tlcol), lookat(r->brrow, r->brcol)); - } else if (buf->pnext->value == L'u') { - unlock_cells(lookat(r->tlrow, r->tlcol), lookat(r->brrow, r->brcol)); - } else if (buf->pnext->value == L'v') { - valueize_area(r->tlrow, r->tlcol, r->brrow, r->brcol); - } - cmd_multiplier = 0; - - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // Zr Zc - Zap col or row - } else if ( (buf->value == L'Z' || buf->value == L'S') && (buf->pnext->value == L'c' || buf->pnext->value == L'r')) { - int arg = buf->pnext->value == L'r' ? r->brrow - r->tlrow + 1 : r->brcol - r->tlcol + 1; - if (buf->value == L'Z' && buf->pnext->value == L'r') { - hide_row(r->tlrow, arg); - } else if (buf->value == L'Z' && buf->pnext->value == L'c') { - hide_col(r->tlcol, arg); - } else if (buf->value == L'S' && buf->pnext->value == L'r') { - show_row(r->tlrow, arg); - } else if (buf->value == L'S' && buf->pnext->value == L'c') { - show_col(r->tlcol, arg); - } - cmd_multiplier = 0; - - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // delete selected range - } else if (buf->value == L'x' || (buf->value == L'd' && buf->pnext->value == L'd') ) { - del_selected_cells(); - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - // shift range - } else if (buf->value == L's') { - shift(r->tlrow, r->tlcol, r->brrow, r->brcol, buf->pnext->value); - exit_visualmode(); - chg_mode('.'); - ui_show_header(); - - } else if (buf->value == L':') { - chg_mode(':'); - ui_show_header(); -#ifdef HISTORY_FILE - add(commandline_history, L""); -#endif - ui_handle_cursor(); - inputline_pos = 0; - real_inputline_pos = 0; - return; - } - - if (visual_submode == '0') - ui_update(TRUE); - else { - ui_update(FALSE); - } -} diff -Nru sc-im-0.8.2+ds/src/cmds_visual.h sc-im-0.8.3+ds/src/cmds_visual.h --- sc-im-0.8.2+ds/src/cmds_visual.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/cmds_visual.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file cmds_visual.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for cmds_visual.c - */ - -void start_visualmode(int tlrow, int tlcol, int brrow, int brcol); -void exit_visualmode(); -void do_visualmode(struct block * sb); -extern char visual_submode; diff -Nru sc-im-0.8.2+ds/src/color.c sc-im-0.8.3+ds/src/color.c --- sc-im-0.8.2+ds/src/color.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/color.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -57,7 +57,7 @@ #include "tui.h" #include "undo.h" #include "conf.h" -#include "cmds.h" +#include "cmds/cmds.h" struct ucolor ucolors[N_INIT_PAIRS] = {}; @@ -68,6 +68,8 @@ } static struct custom_color * custom_colors = NULL; +extern struct session * session; + /** * @brief Generate DEFAULT 'initcolor' colors * @@ -142,6 +144,7 @@ ucolors[ CELL_CONTENT ].bold = 1; ucolors[ INPUT ].fg = WHITE; ucolors[ INPUT ].bg = DEFAULT_COLOR; + ucolors[ NORMAL ].bold = 1; ucolors[ NORMAL ].fg = WHITE; ucolors[ NORMAL ].bg = DEFAULT_COLOR; ucolors[ CELL_ERROR ].fg = RED; @@ -151,6 +154,13 @@ ucolors[ CELL_NEGATIVE ].bg = DEFAULT_COLOR; ucolors[ HELP_HIGHLIGHT ].fg = BLACK; // cell selection in spreadsheet ucolors[ HELP_HIGHLIGHT ].bg = YELLOW; + ucolors[ CURRENT_SHEET ].fg = CYAN; + ucolors[ CURRENT_SHEET ].bg = DEFAULT_COLOR; + ucolors[ CURRENT_SHEET ].bold = 1; + ucolors[ SHEET ].fg = MAGENTA; + ucolors[ SHEET ].bg = DEFAULT_COLOR; + ucolors[ FILENM ].fg = GREEN; + ucolors[ FILENM ].bg = DEFAULT_COLOR; ui_start_colors(); // call specific ui startup routine } @@ -238,6 +248,12 @@ put(d_colors_param, "CELL_NEGATIVE", str); sprintf(str, "%d", DEFAULT); put(d_colors_param, "DEFAULT", str); + sprintf(str, "%d", CURRENT_SHEET); + put(d_colors_param, "CURRENT_SHEET", str); + sprintf(str, "%d", SHEET); + put(d_colors_param, "SHEET", str); + sprintf(str, "%d", FILENM); + put(d_colors_param, "FILENM", str); } /** @@ -363,8 +379,9 @@ * returns: none */ -void color_cell(int r, int c, int rf, int cf, char * str) { - if (any_locked_cells(r, c, rf, cf)) { +void color_cell(struct sheet * sh, int r, int c, int rf, int cf, char * str) { + struct roman * roman = session->cur_doc; + if (any_locked_cells(sh, r, c, rf, cf)) { sc_error("Locked cells encountered. Nothing changed"); return; } @@ -398,17 +415,17 @@ for (j=c; j<=cf; j++) { // if we are not loading the file - if (! loading) { - modflg++; + if (! roman->loading) { + roman->modflg++; #ifdef UNDO create_undo_action(); - copy_to_undostruct(i, j, i, j, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, i, j, i, j, UNDO_DEL, IGNORE_DEPS, NULL); #endif } // action - n = lookat(i, j); + n = lookat(sh, i, j); if (n->ucolor == NULL) { n->ucolor = (struct ucolor *) malloc(sizeof(struct ucolor)); n->ucolor->fg = NONE_COLOR; @@ -452,9 +469,9 @@ if ((cl = get(d, "blink")) != NULL && cl[0] != '\0') n->ucolor->blink = get_int(d, "blink"); if ((cl = get(d, "underline")) != NULL && cl[0] != '\0') n->ucolor->underline = get_int(d, "underline"); - if (! loading) { + if (! roman->loading) { #ifdef UNDO - copy_to_undostruct(i, j, i, j, UNDO_ADD, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, i, j, i, j, UNDO_ADD, IGNORE_DEPS, NULL); end_undo_action(); #endif } @@ -462,7 +479,7 @@ } destroy_dictionary(d); - if (! loading) ui_update(TRUE); + if (! roman->loading) ui_update(TRUE); return; } @@ -478,18 +495,19 @@ * returns: none */ -void unformat(int r, int c, int rf, int cf) { - if (any_locked_cells(r, c, rf, cf)) { +void unformat(struct sheet * sh, int r, int c, int rf, int cf) { + struct roman * roman = session->cur_doc; + if (any_locked_cells(sh, r, c, rf, cf)) { sc_error("Locked cells encountered. Nothing changed"); return; } // if we are not loading the file - if (! loading) { - modflg++; + if (! roman->loading) { + roman->modflg++; #ifdef UNDO create_undo_action(); - copy_to_undostruct(r, rf, c, cf, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, r, c, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL); #endif } @@ -500,16 +518,16 @@ for (j=c; j<=cf; j++) { // action - if ( (n = *ATBL(tbl, i, j)) && n->ucolor != NULL) { + if ( (n = *ATBL(sh, sh->tbl, i, j)) && n->ucolor != NULL) { free(n->ucolor); n->ucolor = NULL; } } } - if (! loading) { + if (! roman->loading) { #ifdef UNDO - copy_to_undostruct(r, rf, c, cf, UNDO_ADD, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, r, c, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL); end_undo_action(); #endif ui_update(TRUE); @@ -560,6 +578,7 @@ */ int redefine_color(char * color, int r, int g, int b) { + struct roman * roman = session->cur_doc; #if defined(NCURSES) && defined(USECOLORS) extern void sig_winchg(); if ( @@ -577,11 +596,11 @@ if (init_color(atoi(s), RGB(r, g, b)) == 0) { #endif sig_winchg(); - if (! loading) sc_info("Color %s redefined to %d %d %d.", color, r, g, b); + if (! roman->loading) sc_info("Color %s redefined to %d %d %d.", color, r, g, b); return 0; } } - if (! loading) sc_error("Could not redefine color"); + if (! roman->loading) sc_error("Could not redefine color"); #endif return -1; } @@ -598,6 +617,7 @@ * returns: 0 on success, -1 on error */ int define_color(char * color, int r, int g, int b) { + struct roman * roman = session->cur_doc; #if defined(NCURSES) && defined(USECOLORS) if (get_conf_int("nocurses")) { @@ -643,7 +663,7 @@ init_color(7 + cc->number, RGB(r, g, b)); #endif - if (! loading) sc_info("Defined custom color #%d with name '%s' and RGB values %d %d %d", cc->number, cc->name, cc->r, cc->g, cc->b); + if (! roman->loading) sc_info("Defined custom color #%d with name '%s' and RGB values %d %d %d", cc->number, cc->name, cc->r, cc->g, cc->b); return 0; #endif sc_error("Could not define color %s", color); diff -Nru sc-im-0.8.2+ds/src/color.h sc-im-0.8.3+ds/src/color.h --- sc-im-0.8.2+ds/src/color.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/color.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -42,12 +42,42 @@ * \brief Header file for color.c */ +#include "sc.h" #include "macros.h" #include #define RGB(r, g, b) r*999/255, g*999/255, b*999/255 -#define N_INIT_PAIRS 25 +#define N_INIT_PAIRS 28 + +#define HEADINGS 0 +#define WELCOME 1 +#define CELL_SELECTION 2 +#define CELL_SELECTION_SC 3 +#define NUMB 4 +#define STRG 5 +#define DATEF 6 +#define EXPRESSION 7 +#define INFO_MSG 8 +#define ERROR_MSG 9 +#define MODE 10 +#define CELL_ID 11 +#define CELL_FORMAT 12 +#define CELL_CONTENT 13 +#define INPUT 14 +#define NORMAL 15 +#define CELL_ERROR 16 +#define CELL_NEGATIVE 17 +#define DEFAULT 18 +#define DEBUG_MSG 19 +#define VALUE_MSG 20 +#define GRID_EVEN 21 +#define GRID_ODD 22 +#define HEADINGS_ODD 23 +#define HELP_HIGHLIGHT 24 +#define SHEET 25 +#define CURRENT_SHEET 26 +#define FILENM 27 struct ucolor { int fg; @@ -83,8 +113,8 @@ struct dictionary * get_d_colors_param(); void start_default_ucolors(); -void color_cell(int r, int c, int rf, int cf, char * detail); -void unformat(int r, int c, int rf, int cf); +void color_cell(struct sheet * sh, int r, int c, int rf, int cf, char * str); +void unformat(struct sheet * sh, int r, int c, int rf, int cf); void set_colors_param_dict(); void free_colors_param_dict(); void chg_color(char * str); diff -Nru sc-im-0.8.2+ds/src/conf.c sc-im-0.8.3+ds/src/conf.c --- sc-im-0.8.2+ds/src/conf.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/conf.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -50,6 +50,7 @@ #include #include #include "conf.h" +#include "sc.h" #include "utils/dictionary.h" @@ -63,16 +64,17 @@ "exec_lua=1\n" "xlsx_readformulas=0\n" "import_delimited_as_text=0\n" + "ignore_hidden=0\n" "quit_afterload=0\n" "quiet=0\n" "numeric_zero=1\n" "numeric_decimal=1\n" - "filename_with_mode=0\n" "overlap=0\n" "truncate=0\n" "autowrap=0\n" "debug=0\n" "ignorecase=0\n" + "show_cursor=0\n" "trigger=1\n" "version=0\n" "help=0\n" @@ -195,3 +197,84 @@ int get_conf_int(const char * key) { return get_int(user_conf_d, key); } + + +/* \brief change_config_parameter + * parameter[in] char * cmd + * return int: + * 0 if config parameter changed + * 1 if config parameter was valid but previous and new values are the same + * -1 on error + */ +#include +#include +#include "macros.h" +#include "cmds/cmds.h" +#include "utils/string.h" +#include "tui.h" +int change_config_parameter(wchar_t * inputline) { + extern wchar_t interp_line[BUFFERSIZE]; + + // remove "set " + wchar_t line [BUFFERSIZE]; + wcscpy(line, inputline); + del_range_wchars(line, 0, 3); + + // parse value + wchar_t * l; + if ((l = wcschr(line, L' ')) != NULL) l[0] = L'\0'; + if ((l = wcschr(line, L'=')) != NULL) l[0] = L'\0'; + + // check a proper config parameter exists + char oper[BUFFERSIZE]; + wcstombs(oper, line, BUFFERSIZE); + // sent garbage after "set ".. + if (! strlen(oper)) { + sc_error("Invalid command: \'%ls\'", inputline); + return -1; + } + char * value_bef = malloc(sizeof(char)*90); + value_bef[0] = '\0'; + char * key = malloc(sizeof(char)*90); + key[0] = '\0'; + char * value_aft = malloc(sizeof(char)*90); + value_aft[0] = '\0'; + + strcpy(key, oper); + char * s_aux = get_conf_value(key); + if (s_aux != NULL) strcpy(value_bef, get_conf_value(key)); + if ((! value_bef || ! strlen(value_bef)) && strlen(oper) > 2 && ! wcsncmp(inputline, L"set no", 6)) { + s_aux = get_conf_value(&oper[2]); + if (s_aux != NULL) { + strcpy(value_bef, s_aux); + strcpy(key, &oper[2]); + } + } + + if (! value_bef || ! strlen(value_bef)) { + sc_error("Invalid config variable: \'%s\'", oper); + free(value_aft); + free(value_bef); + free(key); + return -1; + } + + // we try to change config value + wcscpy(interp_line, inputline); + send_to_interp(interp_line); + s_aux = get_conf_value(key); + if (s_aux != NULL) strcpy(value_aft, s_aux); + // check it was changed + if (! strcmp(value_bef, value_aft)) { sc_info("Config variable \'%s\' unchanged. Current value is \'%s\'", key, value_aft); + free(value_aft); + free(value_bef); + free(key); + return 1; + } + // inform so + sc_info("Config variable \'%s\' changed. Value \'%s\' to \'%s\'", key, value_bef, value_aft); + free(value_aft); + free(value_bef); + free(key); + return 0; +} diff -Nru sc-im-0.8.2+ds/src/conf.h sc-im-0.8.3+ds/src/conf.h --- sc-im-0.8.2+ds/src/conf.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/conf.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -42,9 +42,11 @@ * @brief Header file for conf.c */ +#include extern struct dictionary * user_conf_d; void store_default_config_values(); char * get_conf_value(const char * key); int get_conf_int(const char * key); +int change_config_parameter(wchar_t * inputline); char * get_conf_values(char * salida); diff -Nru sc-im-0.8.2+ds/src/debug.sh sc-im-0.8.3+ds/src/debug.sh --- sc-im-0.8.2+ds/src/debug.sh 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/debug.sh 2023-01-16 15:38:03.000000000 +0000 @@ -1,4 +1,4 @@ #!/bin/bash -tmux splitw -h -p 35 "gdbserver :12345 ./sc-im dos.sc" +tmux splitw -h -p 35 "gdbserver :12345 ./sc-im" tmux selectp -t 0 cgdb -x gdb.gdb diff -Nru sc-im-0.8.2+ds/src/dep_graph.c sc-im-0.8.3+ds/src/dep_graph.c --- sc-im-0.8.2+ds/src/dep_graph.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/dep_graph.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,847 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file dep_graph.c - * \author Andrés Martinelli - * \date 2021-04-29 - * \brief All the functions used to track cell dependencies - * - * \details This file contains all functions used for maintaining a - * dependence graph that keeps track of all the cells that depends on - * each other. This is done in a two way relationship. - * - * \details A vertex represents an ent and has in "edges", links to - * other vertex's(ents) which the first vertex depends on. - * - * \details The other relationship is "back_edges". This is a pointer - * to other vertex's and there you will keep linked all the vertex's that - * use the first vertex in their formulas. In other words, you will keep - * track of all the vertex's that depends on the first vertex. - * - * \details NOTE: an orphan vertex represents an ent that has an enode - * thats need to be evaluated, but do not depend in another cell. - */ - -#include -#include -#include -#include - -#include "dep_graph.h" -#include "interp.h" -#include "tui.h" // for show_text -#include "sc.h" -#include "xmalloc.h" // for scxfree -#include "macros.h" -#include "trigger.h" - -extern jmp_buf fpe_save; -extern int cellerror; /**< is there an error in this cell */ - -#define CREATE_NEW(type) (type *) malloc(sizeof(type)) - -#define APPEND_TO_LINKLIST(firstNode, newNode, tempNode) \ - if( firstNode == NULL ) { \ - firstNode = newNode ; \ - } \ - else { \ - tempNode = firstNode; \ - while (tempNode->next != NULL) { \ - tempNode = tempNode->next; \ - } \ - tempNode->next = newNode; \ - } - -graphADT graph; /**< Creates an empty graph, with no vertices. Allocate memory from the heap */ - -// used for saving dependencies of cells: -struct ent_ptr * deps = NULL; -int dep_size = 0; - - -/************************************************************ - * These are the functions used for creating the depgraph - * **********************************************************/ - - -/** - * \brief GraphCreate() - * \return An empty graph - */ -graphADT GraphCreate() { - graphADT emptyGraph = (graphCDT *) malloc(sizeof(graphCDT)); - emptyGraph->vertices = NULL; - return emptyGraph; -} - - -/** - * \brief Undefined function - * - * This adds the vertex sorted in the list and not at the end. Given a row and - * column to insert as a new vertex, this function will create a new vertex - * with those values and add it in order to the list. - * - * \param[in] graph - * \param[in] ent - * - * \return a pointer to the new vertex - */ -vertexT * GraphAddVertex(graphADT graph , struct ent * ent) { - //if (ent == NULL) { - // sc_debug("add vertex- null ent"); - // return NULL; - //} - //sc_debug("will add vertex %d %d ", ent->row, ent->col); - vertexT * newVertex = (vertexT *) malloc(sizeof(vertexT)); - newVertex->visited = 0; - newVertex->eval_visited = 0; - newVertex->ent = ent; - newVertex->edges = NULL; - newVertex->back_edges = NULL; - newVertex->next = NULL; - - vertexT * temp_ant = NULL; - vertexT * tempNode = NULL; - - // first element added to the list - if( graph->vertices == NULL) { - graph->vertices = newVertex; - - // append in first position - } else if (ent->row < graph->vertices->ent->row || (ent->row == graph->vertices->ent->row && ent->col < graph->vertices->ent->col)) { - newVertex->next = graph->vertices; - graph->vertices = newVertex; - - // append in second position or after that - } else { - tempNode = graph->vertices; - temp_ant = tempNode; - while (tempNode != NULL && (ent->row > tempNode->ent->row || (ent->row == tempNode->ent->row && ent->col > tempNode->ent->col) ) ) { - temp_ant = tempNode; - tempNode = temp_ant->next; - } - temp_ant->next = newVertex; - newVertex->next = tempNode; - } - //sc_debug("Added vertex %d %d in the graph", ent->row, ent->col) ; - return newVertex; -} - - -/** - * \brief TODO Write a brief description - * - * \details This looks for a vertex representing a specific ent in - * a sorted list. We search for a vertex in graph and return it if - * found. If not found and create flag, we add add the vertex - * (malloc it) and return it. If not found, it returns NULL. - * - * \param[in] graph - * \param[in] ent - * \param[in] create - * - * \return vertex if found; NULL if not found - */ -vertexT * getVertex(graphADT graph, struct ent * ent, int create) { - if (graph == NULL || ent == NULL || (graph->vertices == NULL && !create)) return NULL; - vertexT * temp = graph->vertices; - //sc_debug("getVertex - looking for %d %d, create:%d", ent->row, ent->col, create); - //while (temp != NULL && temp->ent != NULL) // temp->ent should not be NULL - while (temp != NULL - //in case it was inserted ordered - && (temp->ent->row < ent->row || (temp->ent->row == ent->row && temp->ent->col <= ent->col))) - { - //sc_debug("this vertex exists: %d %d", temp->ent->row, temp->ent->col); - if (temp->ent->row == ent->row && temp->ent->col == ent->col) { - //sc_debug("found vertex: %d %d", temp->ent->row, temp->ent->col); - return temp; - } - temp = temp->next; - } - //sc_debug("not found vertex: %d %d", ent->row, ent->col); - - - /* - * if we get to here, there is not vertex representing ent - * we add it if create is set to true! - */ - return create ? GraphAddVertex(graph, ent) : NULL; -} - - -/** - * \brief Add an edge to a graph - * \details This function adds an edge in out graph from the vertex "from" - * to the vertex "to". - * \return none - */ -void GraphAddEdge(vertexT * from, vertexT * to) { - if (from == NULL || to == NULL) { - sc_info("Error while adding edge: either of the vertices do not exist") ; - return; - } - // do we have to check this here? or shall we handle it outside from the caller? - markAllVerticesNotVisited(0); // needed to check if edge already exists - if (GraphIsReachable(from, to, 0)) { - //sc_info("Error while adding edge: the edge already exists! - %d %d - %d %d", from->ent->row, from->ent->col, to->ent->row, to->ent->col) ; - return; - } - - edgeT * newEdge = CREATE_NEW(edgeT) ; - newEdge->connectsTo = to; - newEdge->next = NULL; - edgeT * tempEdge = NULL; - APPEND_TO_LINKLIST(from->edges, newEdge, tempEdge); - //sc_info("Added the edge from %d %d to %d %d", from->row, from->col, to->row, to->col) ; - - // BACK APPEND - newEdge = CREATE_NEW(edgeT) ; - newEdge->connectsTo = from; - newEdge->next = NULL; - tempEdge = NULL; - APPEND_TO_LINKLIST(to->back_edges, newEdge, tempEdge); - //sc_info("Added BACK reference from %d %d to %d %d", to->row, to->col, from->row, from->col) ; - return; -} - - -/** - * \brief Iterate through all verticies and set visited to false - * - * Iterate through all verticies and set visited to false - * evalvisited - * - * \return none - */ -void markAllVerticesNotVisited (int eval_visited) { - vertexT * temp = graph->vertices; - while (temp != NULL) { - if (eval_visited) temp->eval_visited = 0; - else temp->visited = 0; - temp = temp->next; - } - return; -} - - -/** - * \brief Prints vertexes - * \return none - */ -void print_vertexs() { - char det[BUFFERSIZE] = ""; - if (graph == NULL) { - strcpy(det, "Graph is empty"); - ui_show_text((char *) &det); - return; - } - vertexT * temp = graph->vertices; - edgeT * etemp; - det[0]='\0'; - int msg_size = BUFFERSIZE; - char * msg = (char *) malloc(msg_size); - msg[0]='\0'; - strcpy(msg, "Content of graph:\n"); - - while (temp != NULL) { - sprintf(det + strlen(det), "vertex: %d %d vis:%d eval_vis:%d\n", temp->ent->row, temp->ent->col, temp->visited, temp->eval_visited); - etemp = temp->edges; - - /* check not overflow msg size. if so, just realloc. */ - if (strlen(det) + strlen(msg) > msg_size) { - //sc_debug("realloc"), - msg_size += BUFFERSIZE; - msg = (char *) realloc(msg, msg_size); - } - sprintf(msg + strlen(msg), "%s", det); - det[0]='\0'; - /**/ - while (etemp != NULL) { - sprintf(det + strlen(det), " \\-> depends on the following ents: %d %d\n", etemp->connectsTo->ent->row, etemp->connectsTo->ent->col); - etemp = etemp->next; - - /* check not overflow msg size. if so, just realloc. */ - if (strlen(det) + strlen(msg) > msg_size) { - msg_size += BUFFERSIZE; - msg = (char *) realloc(msg, msg_size); - } - sprintf(msg + strlen(msg), "%s", det); - det[0]='\0'; - /**/ - } - etemp = temp->back_edges; - while (etemp != NULL) { - sprintf(det + strlen(det), "(back_edges) edges that depend on that ent: \\-> %d %d\n", etemp->connectsTo->ent->row, etemp->connectsTo->ent->col); - etemp = etemp->next; - - /* check not overflow msg size. if so, just realloc. */ - if (strlen(det) + strlen(msg) > msg_size) { - msg_size += BUFFERSIZE; - msg = (char *) realloc(msg, msg_size); - } - sprintf(msg + strlen(msg), "%s", det); - det[0]='\0'; - /**/ - } - temp = temp->next; - } - ui_show_text((char *) msg); - free(msg); - return; -} - - -/** - * \brief Destroy a vertex - * - * \details This function frees the memory of vertex's edges. This also - * frees the vertex itself, but only if it has no back_dependences. The - * only parameter is an int pointer. - * - * \param[in] ent - * - * \return none - */ -void destroy_vertex(struct ent * ent) { - if (graph == NULL || ent == NULL) return; - //sc_debug("destroying vertex %d %d", ent->row, ent->col); - - vertexT * v_prev, * v_cur = graph->vertices; - - // if is in the middle of the list - if (v_cur->ent->row != ent->row || v_cur->ent->col != ent->col) { - if (v_cur->ent == NULL) sc_error("ERROR destroying vertex"); - v_prev = v_cur; - v_cur = v_cur->next; - while (v_cur != NULL && (v_cur->ent->row < ent->row || (v_cur->ent->row == ent->row && v_cur->ent->col <= ent->col))) { - if (v_cur->ent->row == ent->row && v_cur->ent->col == ent->col) break; - v_prev = v_cur; - v_cur = v_cur->next; - } - if (v_cur->ent->row != ent->row || v_cur->ent->col != ent->col) { - sc_error("Error while destroying a vertex. Vertex not found! Please rebuild graph"); - return; - } - v_prev->next = v_cur->next; - } - - /*FIXME - // for each edge in back_edges, we look for the reference to the vertex we are deleting, and we erase it! - edgeT * e2 = v_cur->back_edges; - while (e2 != NULL) { - // sc_debug("back_edge: we follow %d %d", e2->connectsTo->ent->row, e2->connectsTo->ent->col); - delete_reference(v_cur, e2->connectsTo, 0); - e2 = e2->next; - }*/ - - // for each edge in edges, we look for the reference to the vertex we are deleting, and we erase it! - edgeT * e = v_cur->edges; - if (v_cur->back_edges == NULL) - while (e != NULL && v_cur->back_edges == NULL) { - // sc_debug("edge: we follow %d %d", e->connectsTo->ent->row, e->connectsTo->ent->col); - delete_reference(v_cur, e->connectsTo, 1); - - // delete vertex only if it end up having no edges, no expression, no value, no label.... - if (e->connectsTo->edges == NULL && e->connectsTo->back_edges == NULL && !e->connectsTo->ent->expr && !(e->connectsTo->ent->flags & is_valid) && ! e->connectsTo->ent->label) - destroy_vertex(e->connectsTo->ent); - // WARNING: an orphan vertex now represents an ent that has an enode thats - // need to be evaluated, but do not depends on another cell. - e = e->next; - } - - destroy_list_edges(v_cur->edges); - v_cur->edges = NULL; - - destroy_list_edges(v_cur->back_edges); - v_cur->back_edges = NULL; - - // if vertex to free was the first one.. - if (graph->vertices && graph->vertices->ent->row == ent->row && graph->vertices->ent->col == ent->col) - graph->vertices = v_cur->next; - - free(v_cur); - return; -} - - -/** - * \brief TODO Write brief function description - * - * \details For each edge in edges, we look for the references to the - * vertex we are deleting and we erase it! - * - * \details v_cur is the reference. - * - * \details If back_reference is set, the delete is done over the - * back_edges list. If not, it is done over edges list. - * - * \param[in] v_cur - * \param[in] tc - * \param[in] back_reference - * - * \return none - */ -void delete_reference(vertexT * v_cur, vertexT * vc, int back_reference) { - if (v_cur == NULL || vc == NULL) return; - //sc_debug("we follow %d %d", vc->ent->row, vc->ent->col); - - // If v_cur is in the first position of back_edge list of vc - if (back_reference && vc->back_edges->connectsTo == v_cur) { - edgeT * e_cur = vc->back_edges; - vc->back_edges = e_cur->next; - free(e_cur); - return; - // If v_cur is in the first position of edge list of vc - } else if (! back_reference && vc->edges->connectsTo == v_cur) { - edgeT * e_cur = vc->edges; - vc->edges = e_cur->next; - free(e_cur); - return; - } - - // If v_cur is not in the first position - edgeT * eb = back_reference ? vc->back_edges : vc->edges; - edgeT * e_prev = eb; - edgeT * e_cur = eb->next; - while (e_cur != NULL && e_cur->connectsTo != v_cur) { - e_prev = e_cur; - e_cur = e_cur->next; - } - if (e_cur != NULL && e_cur->connectsTo == v_cur) { - e_prev->next = e_cur->next; - free(e_cur); - } - return; -} - - -/** - * \brief Free memory of an edge and its linked edges - * \return none - */ -void destroy_list_edges(edgeT * e) { - if (e == NULL) return; - edgeT * e_next, * e_cur = e; - - while (e_cur != NULL) { - e_next = e_cur->next; - e_cur->connectsTo = NULL; - free(e_cur); - e_cur = e_next; - } - return; -} - - -/** - * \brief Free the memory of a graph - * \param[in] graph - * \return none - */ -void destroy_graph(graphADT graph) { - if (graph == NULL) return; - - vertexT * v_next, * v_cur = graph->vertices; - while (v_cur != NULL) { - v_next = v_cur->next; - if (v_cur->edges != NULL) destroy_list_edges(v_cur->edges); - if (v_cur->back_edges != NULL) destroy_list_edges(v_cur->back_edges); - free(v_cur); - v_cur = v_next; - } - free(graph); - return; -} - - -/** - * \brief All_vertexs_of_edges_visited - * \details Used in EvalBottomUp and GraphIsReachable - * \return int - */ -int All_vertexs_of_edges_visited(struct edgeTag * e, int eval_visited) { - struct edgeTag * edges = e; - while (edges != NULL) { - //sc_debug("1 r:%d c:%d visited:%d", edges->connectsTo->ent->row, edges->connectsTo->ent->col, edges->connectsTo->eval_visited); - if (eval_visited && ! edges->connectsTo->eval_visited) return 0; - else if (!eval_visited && ! edges->connectsTo->visited) return 0; - edges = edges->next; - } - return 1; -} - - -/** - * \brief ents_that_depends_on() - * \details get the list of ents that depends on an specific ent - * \param[in] ent - * \return none - */ -void ents_that_depends_on (struct ent * ent) { - if (graph == NULL) return; - vertexT * v = getVertex(graph, ent, 0); - if (v == NULL || v->visited) return; - - struct edgeTag * edges = v->back_edges; - while (edges != NULL) { - // TODO only add ent if it does not exists in deps ?? - deps = (struct ent_ptr *) realloc(deps, sizeof(struct ent_ptr) * (++dep_size)); - deps[0].vf = dep_size; // we always keep size of list in the first position ! - deps[dep_size-1].vp = lookat(edges->connectsTo->ent->row, edges->connectsTo->ent->col); - ents_that_depends_on(edges->connectsTo->ent); - edges->connectsTo->visited = 1; - edges = edges->next; - } - return; -} - -/** - * \brief GraphIsReachable - * \details This method returns if a vertex called dest is reachable - * from the vertex called src (if back_dep is set to false). If back_dep - * is set to true, the relationship is evaluated in the opposite way. - * - * \param[in] src - * \param[out] dest - * \param[in] back_dep - * - * \return 1 true or 0 false - */ -int GraphIsReachable(vertexT * src, vertexT * dest, int back_dep) { - if (src == dest) { - return 1; - } else if (src->visited) { - return 0; - } else { - // visit all edges of vertexT * src - src->visited = 1; - - edgeT * tempe; - if ( !back_dep ) - tempe = src->edges; - else - tempe = src->back_edges; - - while (tempe != NULL) { - if ( ! GraphIsReachable(tempe->connectsTo, dest, back_dep)) { - tempe = tempe->next; - } else { - return 1; - } - } - } - return 0; -} - -/** - * \brief ents_that_depends_on_range() - * - * \details Checks dependency of a range of ents. - * Keep the ents references in "deps" lists. - * - * \param[in] r1 - * \param[in] c1 - * \param[in] r2 - * \param[in] c2 - * - * \return none - */ -void ents_that_depends_on_range (int r1, int c1, int r2, int c2) { - if (graph == NULL) return; - - int r, c; - struct ent * p; - - // at this point deps must be NULL - deps = NULL; - dep_size = 0; - - for (r = r1; r <= r2; r++) { - for (c = c1; c <= c2; c++) { - markAllVerticesNotVisited(0); - p = *ATBL(tbl, r, c); - if (p == NULL) continue; - ents_that_depends_on(p); - } - } - return; -} - - -/** - * \brief ents_that_depends_on_list() - * - * \details Checks dependency of list of ents. - * - * since this is used for pasting yanked ents, on which we may - * have a difference on rows and columns on which the cells are pasted - * we take care of it with deltar and deltac - * - * \param[in] struct ent * (e_ori) - * \param[in] deltar - * \param[in] deltac - * - * \return none - */ -void ents_that_depends_on_list(struct ent * e_ori, int deltar, int deltac) { - struct ent * e = e_ori; - struct ent * p; - if (graph == NULL || e == NULL) return; - - // at this point deps must be NULL - deps = NULL; - dep_size = 0; - - while (e != NULL) { - p = *ATBL(tbl, e->row+deltar, e->col+deltac); - if (p != NULL) { - markAllVerticesNotVisited(0); - ents_that_depends_on(p); - } - e = e->next; - } - return; -} - -/** - * \brief rebuild_graph() - * \details Rebuild entire graph and eval from top left to bottom right. - * \return none - */ -void rebuild_graph() { - destroy_graph(graph); - graph = GraphCreate(); - int first, second, fb, gb; - struct ent * p; - - fb = calc_order == BYROWS ? maxrow : maxcol; - gb = calc_order == BYROWS ? maxcol : maxrow; - - for (first = 0; first <= fb; first++) - for (second = 0; second <= gb; second++) { - p = *ATBL(tbl, calc_order == BYROWS ? first : second, calc_order == BYROWS ? second : first); - if (p && p->expr) { - EvalJustOneVertex(p, 1); - //sc_debug("Expr %d %d", p->row, p->col); - - // just numeric values (no formulas) shouldnt be added to graph - // unless other cell references it - //} else if (p && p->flags & is_valid && getVertex(graph, p, 0) == NULL) { - // GraphAddVertex(graph, p); - // sc_debug("Val %d %d", p->row, p->col); - } - } - return; -} - -/************************************************************ - * Here we have the depgraph evaluation functions - * **********************************************************/ - -/** - * \brief Eval the entire depgraph - * \return none - */ -void EvalAll() { - EvalBottomUp(); - return; -} - - -/** - * \brief EvalBottomUp the entire dep graph - * It operates bottom up. - * \return none - */ -void EvalBottomUp() { - //print_vertexs(); - vertexT * temp = graph->vertices; - struct ent * p; - - markAllVerticesNotVisited(1); - int evalDone = 0; - - while (temp != NULL) { - //sc_debug("analizo %d %d", temp->ent->row, temp->ent->col); - if ( ! temp->eval_visited && (temp->edges == NULL || All_vertexs_of_edges_visited(temp->edges, 1))) { - //sc_debug("visito %d %d", temp->ent->row, temp->ent->col); - - if ((p = *ATBL(tbl, temp->ent->row, temp->ent->col)) && p->expr) { - EvalJustOneVertex(temp->ent, 0); - } - temp->eval_visited = 1; - evalDone = 1; - } - temp = temp->next; - if (temp == NULL) { - //sc_debug("temp is null. evaldone: %d", evalDone); - if (! evalDone) return; - evalDone = 0; - temp = graph->vertices; - } - } - return; -} - - -/** - * \brief EvalRange - * \details Given a range of cells look up for their vertexs in the depgraph and Eval them. - * It also handles the cells that depends on the range and reeval those as well. - * \return none - */ -void EvalRange(int tlrow, int tlcol, int brrow, int brcol) { - if (loading) return; - extern struct ent_ptr * deps; - extern int dep_size; - int i, fa, fb, ga, gb, first, second; - struct ent * e, * f; - - if (calc_order == BYROWS) - fa = tlrow, fb = brrow, ga = tlcol, gb = brcol; - else - fa = tlcol, fb = brcol, ga = tlrow, gb = brrow; - - for (first = fa; first <= fb; first++) { - for (second = ga; second <= gb; second++) { - // eval the cell - e = *ATBL(tbl, calc_order == BYROWS ? first : second, calc_order == BYROWS ? second : first); - - if (!e) continue; - if (e->expr) EvalJustOneVertex(e, 0); - - // eval the dependencies - markAllVerticesNotVisited(0); - deps = NULL; - dep_size = 0; - ents_that_depends_on(e); - - for (i = 0; deps != NULL && i < deps->vf; i++) { - f = *ATBL(tbl, deps[i].vp->row, deps[i].vp->col); - if (f == NULL || ! f->expr) continue; - EvalJustOneVertex(f, 0); - } - if (deps != NULL) free(deps); - deps = NULL; - } - } - - return; -} - - -/** - * \brief EvalAllVertexs - * \details Eval all vertexs of graph in the order that they were added - * >>>>> NO LONGER IN USE - * \return none - */ -void EvalAllVertexs() { - struct ent * p; - - //(void) signal(SIGFPE, eval_fpe); - vertexT * temp = graph->vertices; - //int i = 0; - while (temp != NULL) { - //sc_debug("Evaluating cell %d %d: %d", temp->ent->row, temp->ent->col, ++i); - if ((p = *ATBL(tbl, temp->ent->row, temp->ent->col)) && p->expr) - EvalJustOneVertex(p, 0); - temp = temp->next; - } - //(void) signal(SIGFPE, exit_app); -} - - -/** - * \brief Evaluate just one vertex - * - * \param[in] p - * \param[in] i - * \param[in] j - * \param[in] rebuild_graph - * - * \return none - */ -void EvalJustOneVertex(struct ent * p, int rebuild_graph) { - int i = p->row; - int j = p->col; - - gmyrow=i; gmycol=j; - - if (p->flags & is_strexpr) { - char * v; - if (setjmp(fpe_save)) { - sc_error("Floating point exception %s", v_name(i, j)); - cellerror = CELLERROR; - v = ""; - } else { - cellerror = CELLOK; - v = rebuild_graph ? seval(p, p->expr) : seval(NULL, p->expr); - } - p->cellerror = cellerror; - if ( !v && !p->label) /* Everything's fine */ - return; - if ( !p->label || !v || strcmp(v, p->label) != 0 || cellerror) { - p->flags |= is_changed; - } - if (p->label) - scxfree(p->label); - p->label = v; - } else { - double v; - if (setjmp(fpe_save)) { - sc_error("Floating point exception %s", v_name(i, j)); - cellerror = CELLERROR; - v = (double) 0.0; - } else { - cellerror = CELLOK; - v = rebuild_graph ? eval(p, p->expr) : eval(NULL, p->expr); - - if (cellerror == CELLOK && ! isfinite(v)) - cellerror = CELLERROR; - } - if ((cellerror != p->cellerror) || (v != p->v)) { - p->cellerror = cellerror; - p->v = v; - p->flags |= is_changed | is_valid; - if (( p->trigger ) && ((p->trigger->flag & TRG_WRITE) == TRG_WRITE)) - do_trigger(p, TRG_WRITE); - } - } -} diff -Nru sc-im-0.8.2+ds/src/dep_graph.h sc-im-0.8.3+ds/src/dep_graph.h --- sc-im-0.8.2+ds/src/dep_graph.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/dep_graph.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file dep_graph.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for dep_graph.c - */ - -#include "sc.h" - -typedef struct vertexTag { - struct ent * ent; /**< Add comment here */ - int visited; /**< Add comment here */ - int eval_visited; // just to not to collide with previous. its used in EvalBottomUp. - struct edgeTag * edges; /**< Add comment here */ - struct edgeTag * back_edges; /**< Add comment here */ - struct vertexTag * next; /**< Add comment here */ -} vertexT; - -/* For each edge, we need a link to the vertex it connects to and a link to the next edge w.r.t source vertex */ -typedef struct edgeTag { - vertexT * connectsTo; - struct edgeTag * next; -} edgeT; - -typedef struct graphCDT { - vertexT * vertices; -} graphCDT; - -typedef struct graphCDT * graphADT; - - -graphADT GraphCreate(); -vertexT * GraphAddVertex(graphADT graph , struct ent * ent); -vertexT * getVertex(graphADT graph, struct ent * ent, int create); -void GraphAddEdge(vertexT * from, vertexT * to); -void print_vertexs(); - -void destroy_list_edges(edgeT * e); -void destroy_graph (graphADT graph); -void destroy_vertex(struct ent * ent); -void delete_reference(vertexT * v_cur, vertexT * vc, int back_reference); - -void markAllVerticesNotVisited(int eval_visited); -void ents_that_depends_on (struct ent * ent); -void ents_that_depends_on_range (int r1, int c1, int r2, int c2); -void ents_that_depends_on_list(struct ent * e_ori, int deltar, int deltac); -int GraphIsReachable(vertexT * src, vertexT * dest, int back_dep); -void rebuild_graph(); - -void EvalAll(); -void EvalBottomUp(); -void EvalAllVertexs(); -void EvalRange(int tlrow, int tlcol, int brrow, int brcol); -void EvalJustOneVertex(struct ent * p, int rebuild_graph); diff -Nru sc-im-0.8.2+ds/src/digraphs.c sc-im-0.8.3+ds/src/digraphs.c --- sc-im-0.8.2+ds/src/digraphs.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/digraphs.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -121,4 +121,3 @@ } return x; } - diff -Nru sc-im-0.8.2+ds/src/digraphs.h sc-im-0.8.3+ds/src/digraphs.h --- sc-im-0.8.2+ds/src/digraphs.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/digraphs.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/doc sc-im-0.8.3+ds/src/doc --- sc-im-0.8.2+ds/src/doc 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/doc 2023-01-16 15:38:03.000000000 +0000 @@ -54,18 +54,23 @@ w Go forward to the next valid cell. '{a-zA-Z} Go to the cell or range marked previously with the character. See 'm' for details. - gtab24 Go to cell AB24. (There is no need to press .) + goab24 Go to cell AB24. (There is no need to press .) g0 Go to the leftmost column visible on screen. g$ Go to the rightmost column visible on screen. gM Go to the middle column on the screen. gf Open filename or URL in current cell. - Uses helper script 'scopen'. + Uses helper script 'scopen' by default. + A different executable may be used by changing the + 'default_open_file_under_cursor_cmd' configuration variable + at runtime, using the :set command. H Go to the top row visible on screen. L Go to the lowest row visible on screen. M Go to the middle row on the screen. gg c-a Go to the first cell of sheet. G gG Go to last valid cell of sheet. gl Go to the last (previously occupied) cell position. + gt Move to next sheet in file. + gT Move to previous sheet in file. c-f c-b Scrolls down and up full screen. :set half_page_scroll=1 to scroll by half a page instead. half_page_scroll=0 (default) scrolls by a full page. @@ -358,9 +363,10 @@ A Append at the end of the line. I Append at the beginning of the line. D Delete from the current cursor position to end of line. + C Same as D, but then enter Insert mode. Add a space under the cursor. Confirm changes. - Go back to NORMAL MODE. If you were in INSERT MODE before, + It also confirm changes. If you were in INSERT MODE before, it goes back to that mode, instead of NORMAL MODE. ============================================================================== &COMMAND MODE& @@ -433,6 +439,8 @@ NOTE: If you do an export with the :e command, current file name stays unchaged. See :file command for more details. + See 'ignore_hidden' configuration variable below to avoid exporting + hidden rows. :e tab {file} Export the current spreadsheet to tab-separated file {file}. @@ -536,6 +544,24 @@ :set nonumeric (same as :set numeric=0) :set default_paste_from_clipboard_cmd="xsel" + :newsheet "{name}" + create a new sheet in file and move to it. + + :nextsheet + move to next sheet in file + + :prevsheet + move to previous sheet in file + + :delsheet "{name}" + deletes the sheet named {name}. + + :delsheet + deletes the current sheet. + + :renamesheet "{name}" + rename the current sheet to {name}. + :showmaps Show all key mappings. :nmap {lhs} {rhs} @@ -988,11 +1014,11 @@ :! {cmd} Executes shell command {cmd}. - :autojus {column} - :autojus {column}:{column} + :autofit {column} + :autofit {column}:{column} Auto-resize the column or column range to fit their contents. - :autojus Auto-resize the columns covered by the selected cell or range. + :autofit Auto-resize the columns covered by the selected cell or range. :trigger Trigger action on cell or range. Trigger can be Read or Write or Both. On Read, trigger is executed before evaluating cells @@ -1322,11 +1348,6 @@ Enabled by default, set this variable to enable the execution of @lua scripts. See @lua function below. - 'filename_with_mode' [default 0] - Set it to '1' to display current filename along with the current mode at - the right end of the status line. - Set it to '0', to display the current mode only. - 'overlap' [default off] If cell content exceedes column width it gets cut off to fit the column width. If overlap is set, the content overflows into the next column. @@ -1382,6 +1403,12 @@ Make the screen cursor follow the active cell. Useful for people using sc-im with a braille display. + 'ignore_hidden' [default off] + set this if you want the hidden rows of a spreadsheet to be ignored when exporting them + to another format. + this will also be used in case you also want to copy/paste a range that have hidden rows in + it (for instance, the result of an applied filter). + ============================================================================== &Built-in Range Functions& @@ -1838,23 +1865,14 @@ --txtdelim=";" --txtdelim="|" - If you pass a .xlsx file to sc-im, you can specify which sheet to load - with the --sheet parameter, which can be the name or number of a sheet. - Default value is 1. - - Example: ./sc-im --sheet=dogs file.xlsx - - Some possible values are: - --sheet=3 - --sheet=dogs ============================================================================== &THEMES& There are a couple of themes you can use with sc-im. They are "dracula", "old.sc", "papercolor-dark" and "prince.persia", and they are located in the "/themes" folder. - You can add the corresponding lines of those in your .scimrc or you can - load them at runtime with `:load path_to_theme_file` + You can add the corresponding lines of those to $HOME/.config/sc-im/scimrc + or you can load them at runtime with `:load path_to_theme_file` ============================================================================== &External scripts& @@ -2147,6 +2165,7 @@ COPY_TO_CLIPBOARD_DELIMITED_TAB COPY_TO_CLIPBOARD_DELIMITED_TAB = {NUMBER} NOCOPY_TO_CLIPBOARD_DELIMITED_TAB + DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD = {strarg} NEWLINE_ACTION = {NUMBER} TM_GMTOFF TM_GMTOFF = {num} diff -Nru sc-im-0.8.2+ds/src/Doxyfile sc-im-0.8.3+ds/src/Doxyfile --- sc-im-0.8.2+ds/src/Doxyfile 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/Doxyfile 2023-01-16 15:38:03.000000000 +0000 @@ -38,13 +38,13 @@ # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.6.4 +PROJECT_NUMBER = 0.8.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "SC-IM is a spreadsheet program that is based on SC" +PROJECT_BRIEF = "SC-IM is a spreadsheet program that is based on sc. # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 diff -Nru sc-im-0.8.2+ds/src/exec.c sc-im-0.8.3+ds/src/exec.c --- sc-im-0.8.2+ds/src/exec.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/exec.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -34,12 +34,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *******************************************************************************/ - /** * \file exec.c * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a brief file description. + * \date 28/05/2021 + * \brief file that contains source code for sending a command to the OS */ #include @@ -57,14 +56,12 @@ #include "sc.h" #include "main.h" // exit_app + /** - * \brief TODO Document exec_cmd() - * - * \param[in] line - * - * \return none + * \brief send a command to the OS + * \param[in] char * command + * \return int - 0 on success, -1 on error */ - int exec_cmd (char * line) { #ifdef NCURSES int waitres; diff -Nru sc-im-0.8.2+ds/src/exec.h sc-im-0.8.3+ds/src/exec.h --- sc-im-0.8.2+ds/src/exec.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/exec.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -34,12 +34,10 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *******************************************************************************/ - /** * \file exec.h * \author Andrés Martinelli - * \date 2017-07-18 + * \date 28/05/2021 * \brief Header file for exec.c */ - int exec_cmd (char * line); diff -Nru sc-im-0.8.2+ds/src/file.c sc-im-0.8.3+ds/src/file.c --- sc-im-0.8.2+ds/src/file.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/file.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -42,6 +42,7 @@ * \brief TODO Write a brief file description. */ +#include "sc.h" #include #include #include @@ -61,7 +62,7 @@ #include "conf.h" #include "maps.h" #include "yank.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "file.h" #include "marks.h" #include "lex.h" @@ -69,16 +70,17 @@ #include "interp.h" #include "utils/string.h" #include "utils/dictionary.h" -#include "cmds_edit.h" +#include "cmds/cmds_edit.h" #include "xmalloc.h" #include "y.tab.h" -#include "xlsx.h" -#include "ods.h" -#include "xls.h" +#include "formats/xlsx.h" +#include "formats/ods.h" +#include "formats/xls.h" #include "tui.h" +#include "trigger.h" +#include "sheet.h" +#include "vmtbl.h" -extern struct ent * freeents; -extern int yyparse(void); #ifdef HAVE_PTHREAD #include @@ -86,58 +88,55 @@ extern int pthread_exists; #endif +extern struct ent * freeents; +extern int yyparse(void); +extern int exit_app(int status); +extern struct session * session; + /** - * \brief Erase the database (tbl, etc.) - * + * \brief erasedb() + * \details Erase the database of a sheet (tbl) and set it default values. + * if _free is set we also free the memory of the ents alloc'ed in the tbl * \return none */ -void erasedb() { +void erasedb(struct sheet * sheet, int _free) { int r, c; - for (c = 0; c <= maxcol; c++) { - fwidth[c] = DEFWIDTH; - precision[c] = DEFPREC; - realfmt[c] = DEFREFMT; + for (c = 0; c < sheet->maxcols; c++) { + sheet->fwidth[c] = DEFWIDTH; + sheet->precision[c] = DEFPREC; + sheet->realfmt[c] = DEFREFMT; } - for (r = 0; r <= maxrow; r++) { - row_format[r] = 1; - register struct ent ** pp = ATBL(tbl, r, 0); - for (c = 0; c++ <= maxcol; pp++) + for (r = 0; r < sheet->maxrows; r++) { + sheet->row_format[r] = 1; + struct ent ** pp = ATBL(sheet, sheet->tbl, r, 0); + for (c = 0; c++ < sheet->maxcols; pp++) if (*pp != NULL) { - //(*pp)->next = freeents; /* save [struct ent] for reuse */ - //freeents = *pp; - clearent(*pp); + if (_free) { + free(*pp); + *pp = NULL; + } else { + (*pp)->next = freeents; /* save [struct ent] for reuse */ + freeents = *pp; + } } } - for (c = 0; c < COLFORMATS; c++) { - if (colformat[c] != NULL) - scxfree(colformat[c]); - colformat[c] = NULL; - } - - maxrow = 0; - maxcol = 0; + sheet->maxrow = 0; + sheet->maxcol = 0; clean_range(); - calc_order = BYROWS; - prescale = 1.0; - tbl_style = 0; - optimize = 0; - currow = curcol = 0; - - *curfile = '\0'; + sheet->currow = sheet->curcol = 0; } /** * \brief load rc config file - * * \return none */ -void loadrc(void) { +void load_rc(void) { char rcpath[PATHLEN]; char * home; @@ -151,24 +150,20 @@ /* Default to compile time if XDG_CONFIG_HOME not found */ else if ((home = getenv("HOME"))) { char config_dir[PATHLEN]; - sprintf(config_dir, "%s/%s", home,CONFIG_DIR); + sprintf(config_dir, "%s/%s", home, CONFIG_DIR); mkdir(config_dir,0777); - snprintf(rcpath, PATHLEN, "%s/%s/%s", home,CONFIG_DIR,CONFIG_FILE); + snprintf(rcpath, PATHLEN, "%s/%s/%s", home, CONFIG_DIR, CONFIG_FILE); (void) readfile(rcpath, 0); } - *curfile = '\0'; } + /** * \brief Check if a file exists - * - * \details Check if a file exists. Returns 1 if so. Returns 0 otherwise. - * + * \details Check if a file exists. * \param[in] fname file name - * - * \return 1 if file exises; 0 otherwise + * \return 1 if file exists; 0 otherwise */ - int file_exists(const char * fname) { FILE * file; if ((file = fopen(fname, "r"))) { @@ -178,26 +173,25 @@ return 0; } + /** * \brief Check if file has been modified since last save. - * * \details This function checks if a file suffered mods since it was open. - * * \return 0 if not modified; 1 if modified */ int modcheck() { - if (modflg && ! get_conf_int("nocurses")) { + struct roman * roman = session->cur_doc; + if (roman->modflg && ! get_conf_int("nocurses")) { sc_error("File not saved since last change. Add '!' to force"); return(1); } return 0; } + /** * \brief Return the proper delimiter for delimiter separated files. - * * \details This function checks the type of a file as well as txtdelim conf value - * * \return one of , ; \t | */ char get_delim(char *type) { @@ -219,22 +213,24 @@ return delim; } + /** - * \brief TODO Handle the save file process - * - * This funciton handles the save file process in SC-IM format.. - * + * \brief Handle the save file process + * This function handles the save file process * \return 0 on OK; -1 on error */ int savefile() { + struct roman * doc = session->cur_doc; + char * curfile = doc->name; int force_rewrite = 0; char name[BUFFERSIZE]; + #ifndef NO_WORDEXP size_t len; wordexp_t p; #endif - if (! curfile[0] && wcslen(inputline) < 3) { // casos ":w" ":w!" ":x" ":x!" + if ((curfile == NULL || ! curfile[0]) && wcslen(inputline) < 3) { // casos ":w" ":w!" ":x" ":x!" sc_error("There is no filename"); return -1; } @@ -267,12 +263,12 @@ #ifdef AUTOBACKUP // check if backup of curfile exists. // if it exists, remove it. - if (strlen(curfile) && backup_exists(curfile)) remove_backup(curfile); + if (curfile != NULL && strlen(curfile) && backup_exists(curfile)) remove_backup(curfile); // check if backup of newfilename exists. // if it exists and '!' is set, remove it. // if it exists and no '!' is set, return. - if (!strlen(curfile) && backup_exists(name)) { + if ((curfile == NULL || ! strlen(curfile)) && backup_exists(name)) { if (!force_rewrite) { sc_error("Backup file of %s exists. Use \"!\" to force the write process.", name); return -1; @@ -280,9 +276,11 @@ } #endif + if (doc->name == NULL) doc->name = malloc(sizeof(char)*PATHLEN); + curfile = doc->name; // copy newfilename to curfile if (wcslen(inputline) > 2) { - strcpy(curfile, name); + strcpy(doc->name, name); } // add sc extension if not present @@ -291,22 +289,22 @@ // treat csv } else if (strlen(curfile) > 4 && (! strcasecmp( & curfile[strlen(curfile)-4], ".csv"))) { - export_delim(curfile, get_delim("csv"), 0, 0, maxrow, maxcol, 1); - modflg = 0; + export_delim(curfile, get_delim("csv"), 0, 0, doc->cur_sh->maxrow, doc->cur_sh->maxcol, 1); + doc->modflg = 0; return 0; // treat tab } else if (strlen(curfile) > 4 && (! strcasecmp( & curfile[strlen(curfile)-4], ".tsv") || ! strcasecmp( & curfile[strlen(curfile)-4], ".tab"))){ - export_delim(curfile, '\t', 0, 0, maxrow, maxcol, 1); - modflg = 0; + export_delim(curfile, '\t', 0, 0, doc->cur_sh->maxrow, doc->cur_sh->maxcol, 1); + doc->modflg = 0; return 0; // treat markdown format } else if (strlen(curfile) > 3 && ( ! strcasecmp( & curfile[strlen(curfile)-3], ".md") || ! strcasecmp( & curfile[strlen(curfile)-4], ".mkd"))){ - export_markdown(curfile, 0, 0, maxrow, maxcol); - modflg = 0; + export_markdown(curfile, 0, 0, doc->cur_sh->maxrow, doc->cur_sh->maxcol); + doc->modflg = 0; return 0; // treat xlsx format @@ -316,29 +314,32 @@ sc_error("XLSX export support not compiled in. Please save file in other extension."); return -1; #else - if (export_xlsx(curfile, 0, 0, maxrow, maxcol) == 0) { + if (export_xlsx(curfile) == 0) { sc_info("File \"%s\" written", curfile); - modflg = 0; + doc->modflg = 0; } else sc_error("File could not be saved"); return 0; #endif + // prevent saving files with ".ods" in its name + } else if (strlen(curfile) > 4 && (! strcasecmp( & curfile[strlen(curfile)-4], ".ods"))) { + sc_error("Cannot save \'%s\' file. ODS file saving is not yet supported.", curfile); + return -1; } // save in sc format - if (writefile(curfile, 0, 0, maxrow, maxcol, 1) < 0) { + if (writefile(curfile, 1) < 0) { sc_error("File could not be saved"); return -1; } - modflg = 0; + doc->modflg = 0; return 0; } + /** - * \brief Write a file - * + * \brief Write current Doc(roman) to file in (.sc) sc-im format * \details Write a file. Receives parameter range and file name. - * * \param[in] fname file name * \param[in] r0 * \param[in] c0 @@ -348,8 +349,8 @@ * * \return 0 on success; -1 on error */ -int writefile(char * fname, int r0, int c0, int rn, int cn, int verbose) { - register FILE *f; +int writefile(char * fname, int verbose) { + FILE * f; char save[PATHLEN]; char tfname[PATHLEN]; int pid; @@ -364,21 +365,25 @@ } if (verbose) sc_info("Writing file \"%s\"...", save); - write_fd(f, r0, c0, rn, cn); + + // traverse sheets of the current doc and save the data to file + write_fd(f, session->cur_doc); closefile(f, pid, 0); if (! pid) { - (void) strcpy(curfile, save); - modflg = 0; - if (verbose) sc_info("File \"%s\" written", curfile); + (void) strcpy(session->cur_doc->name, save); + session->cur_doc->modflg = 0; + if (verbose) sc_info("File \"%s\" written", session->cur_doc->name); } return 0; } + /** - * \brief TODO Document write_fd + * \brief write_fd() + * \details traverse sheets of the given Doc and save the data to file * * \param[in] f file pointer * \param[in] r0 @@ -388,253 +393,253 @@ * * \return none */ -void write_fd(register FILE *f, int r0, int c0, int rn, int cn) { - register struct ent **pp; +void write_fd(FILE * f, struct roman * doc) { + struct ent **pp; int r, c; - (void) fprintf(f, "# This data file was generated by the Spreadsheet Calculator Improvised (SC-IM)\n"); + (void) fprintf(f, "# This data file was generated by the Spreadsheet Calculator Improvised (sc-im)\n"); (void) fprintf(f, "# You almost certainly shouldn't edit it.\n\n"); print_options(f); for (c = 0; c < COLFORMATS; c++) if (colformat[c]) (void) fprintf (f, "format %d = \"%s\"\n", c, colformat[c]); - for (c = c0; c <= cn; c++) - if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC || realfmt[c] != DEFREFMT) - (void) fprintf (f, "format %s %d %d %d\n", coltoa(c), fwidth[c], precision[c], realfmt[c]); - - for (r = r0; r <= rn; r++) - if (row_format[r] != 1) - (void) fprintf (f, "format %d %d\n", r, row_format[r]); - - // new implementation of hidecol. group by ranges - for (c = c0; c <= cn; c++) { - int c_aux = c; - if ( col_hidden[c] && c <= maxcol && ( c == 0 || !col_hidden[c-1] )) { - while (c_aux <= maxcol && col_hidden[c_aux]) - c_aux++; - fprintf(f, "hidecol %s", coltoa(c)); - if (c_aux-1 != c) { - fprintf(f, ":%s\n", coltoa(c_aux-1)); - c = c_aux-1; - } else - fprintf(f, "\n"); + //create sheets + struct sheet * sh = doc->first_sh; + while (sh != NULL) { + fprintf (f, "newsheet \"%s\"\n", sh->name); + sh = sh->next; + } + + //traverse sheets + sh = doc->first_sh; + while (sh != NULL) { + fprintf (f, "movetosheet \"%s\"\n", sh->name); + + // save off screen values + fprintf (f, "offscr_sc_cols %d\n", sh->offscr_sc_cols); + fprintf (f, "offscr_sc_rows %d\n", sh->offscr_sc_rows); + fprintf (f, "nb_frozen_rows %d\n", sh->nb_frozen_rows); + fprintf (f, "nb_frozen_cols %d\n", sh->nb_frozen_cols); + fprintf (f, "nb_frozen_screenrows %d\n", sh->nb_frozen_screenrows); + fprintf (f, "nb_frozen_screencols %d\n", sh->nb_frozen_screencols); + + for (c = 0; c <= sh->maxcol; c++) + if (sh->fwidth[c] != DEFWIDTH || sh->precision[c] != DEFPREC || sh->realfmt[c] != DEFREFMT) + (void) fprintf (f, "format %s %d %d %d\n", coltoa(c), sh->fwidth[c], sh->precision[c], sh->realfmt[c]); + + for (r = 0; r <= sh->maxrow; r++) + if (sh->row_format[r] != 1) + (void) fprintf (f, "format %d %d\n", r, sh->row_format[r]); + + // new implementation of hidecol. group by ranges + for (c = 0; c <= sh->maxcol; c++) { + int c_aux = c; + if ( sh->col_hidden[c] && c <= sh->maxcol && ( c == 0 || ! sh->col_hidden[c-1] )) { + while (c_aux <= sh->maxcol && sh->col_hidden[c_aux]) + c_aux++; + fprintf(f, "hidecol %s", coltoa(c)); + if (c_aux-1 != c) { + fprintf(f, ":%s\n", coltoa(c_aux-1)); + c = c_aux-1; + } else + fprintf(f, "\n"); + } } - } - // new implementation of hiderow. group by ranges - for (r = r0; r <= rn; r++) { - int r_aux = r; - if ( row_hidden[r] && r <= maxrow && ( r == 0 || !row_hidden[r-1] )) { - while (r_aux <= maxrow && row_hidden[r_aux]) - r_aux++; - fprintf(f, "hiderow %d", r); - if (r_aux-1 != r) { - fprintf(f, ":%d\n", r_aux-1); - r = r_aux-1; - } else - fprintf(f, "\n"); + // new implementation of hiderow. group by ranges + for (r = 0; r <= sh->maxrow; r++) { + int r_aux = r; + if ( sh->row_hidden[r] && r <= sh->maxrow && ( r == 0 || ! sh->row_hidden[r-1] )) { + while (r_aux <= sh->maxrow && sh->row_hidden[r_aux]) + r_aux++; + fprintf(f, "hiderow %d", r); + if (r_aux-1 != r) { + fprintf(f, ":%d\n", r_aux-1); + r = r_aux-1; + } else + fprintf(f, "\n"); + } } - } - // frozen cols. group by ranges - for (c = c0; c <= cn; c++) { - int c_aux = c; - if (col_frozen[c] && c <= maxcol && (c == 0 || ! col_frozen[c-1])) { - while (c_aux <= maxcol && col_frozen[c_aux]) c_aux++; - fprintf(f, "freeze %s", coltoa(c)); - if (c_aux-1 != c) { - fprintf(f, ":%s\n", coltoa(c_aux-1)); - c = c_aux-1; - } else - fprintf(f, "\n"); + // frozen cols. group by ranges + for (c = 0; c <= sh->maxcol; c++) { + int c_aux = c; + if (sh->col_frozen[c] && c <= sh->maxcol && (c == 0 || ! sh->col_frozen[c-1])) { + while (c_aux <= sh->maxcol && sh->col_frozen[c_aux]) c_aux++; + fprintf(f, "freeze %s", coltoa(c)); + if (c_aux-1 != c) { + fprintf(f, ":%s\n", coltoa(c_aux-1)); + c = c_aux-1; + } else + fprintf(f, "\n"); + } } - } - // frozen rows. group by ranges - for (r = r0; r <= rn; r++) { - int r_aux = r; - if (row_frozen[r] && r <= maxrow && (r == 0 || ! row_frozen[r-1])) { - while (r_aux <= maxrow && row_frozen[r_aux]) r_aux++; - fprintf(f, "freeze %d", r); - if (r_aux-1 != r) { - fprintf(f, ":%d\n", r_aux-1); - r = r_aux-1; - } else - fprintf(f, "\n"); + // frozen rows. group by ranges + for (r = 0; r <= sh->maxrow; r++) { + int r_aux = r; + if (sh->row_frozen[r] && r <= sh->maxrow && (r == 0 || ! sh->row_frozen[r-1])) { + while (r_aux <= sh->maxrow && sh->row_frozen[r_aux]) r_aux++; + fprintf(f, "freeze %d", r); + if (r_aux-1 != r) { + fprintf(f, ":%d\n", r_aux-1); + r = r_aux-1; + } else + fprintf(f, "\n"); + } } - } - write_marks(f); - write_franges(f); + write_cells(f, doc, sh, 0, 0, sh->maxrow, sh->maxcol, 0, 0); - write_cells(f, r0, c0, rn, cn, r0, c0); + struct custom_color * cc; + for (r = 0; r <= sh->maxrow; r++) { + pp = ATBL(sh, sh->tbl, r, 0); + for (c = 0; c <= sh->maxcol; c++, pp++) + if (*pp) { + // Write ucolors + if ((*pp)->ucolor != NULL) { + char strcolorbuf[BUFFERSIZE]; + char * strcolor = strcolorbuf; + strcolor[0] = 0; + strcolor[1] = 0; + + // decompile int value of color to its string description + if ((*pp)->ucolor->fg != NONE_COLOR) { + if ((*pp)->ucolor->fg <= 8) { + linelim=0; + struct enode * e = new((*pp)->ucolor->fg, (struct enode *)0, (struct enode *)0); + decompile(e, 0); + uppercase(line); + del_char(line, 0); + sprintf(strcolor, " fg=%.*s", BUFFERSIZE-5, &line[0]); + free(e); + } else if ((cc = get_custom_color_by_number((*pp)->ucolor->fg - 7)) != NULL) { + sprintf(strcolor, " fg=%.*s", BUFFERSIZE-5, cc->name); + } + } - struct custom_color * cc; - for (r = r0; r <= rn; r++) { - pp = ATBL(tbl, r, c0); - for (c = c0; c <= cn; c++, pp++) - if (*pp) { - // Write ucolors - if ((*pp)->ucolor != NULL) { - char strcolorbuf[BUFFERSIZE]; - char * strcolor = strcolorbuf; - strcolor[0] = 0; - strcolor[1] = 0; - - // decompile int value of color to its string description - if ((*pp)->ucolor->fg != NONE_COLOR) { - if ((*pp)->ucolor->fg <= 8) { - linelim=0; - struct enode * e = new((*pp)->ucolor->fg, (struct enode *)0, (struct enode *)0); - decompile(e, 0); - uppercase(line); - del_char(line, 0); - sprintf(strcolor, " fg=%.*s", BUFFERSIZE-5, &line[0]); - free(e); - } else if ((cc = get_custom_color_by_number((*pp)->ucolor->fg - 7)) != NULL) { - sprintf(strcolor, " fg=%.*s", BUFFERSIZE, cc->name); + if ((*pp)->ucolor->bg != NONE_COLOR) { + if ((*pp)->ucolor->bg <= WHITE) { + linelim=0; + struct enode * e = new((*pp)->ucolor->bg, (struct enode *)0, (struct enode *)0); + decompile(e, 0); + uppercase(line); + del_char(line, 0); + snprintf(strcolor + strlen(strcolor), strlen(line)+5, " bg=%s", &line[0]); + free(e); + } else if ((cc = get_custom_color_by_number((*pp)->ucolor->bg - 7)) != NULL) { + sprintf(strcolor + strlen(strcolor), " bg=%.*s", BUFFERSIZE-5, cc->name); + } } - } - if ((*pp)->ucolor->bg != NONE_COLOR) { - if ((*pp)->ucolor->bg <= WHITE) { - linelim=0; - struct enode * e = new((*pp)->ucolor->bg, (struct enode *)0, (struct enode *)0); - decompile(e, 0); - uppercase(line); - del_char(line, 0); - sprintf(strcolor + strlen(strcolor), " bg=%s", &line[0]); - free(e); - } else if ((cc = get_custom_color_by_number((*pp)->ucolor->bg - 7)) != NULL) { - sprintf(strcolor + strlen(strcolor), " bg=%.*s", BUFFERSIZE, cc->name); + if ((*pp)->ucolor->bold) sprintf(strcolor + strlen(strcolor), " bold=1"); + if ((*pp)->ucolor->italic) sprintf(strcolor + strlen(strcolor), " italic=1"); + if ((*pp)->ucolor->dim) sprintf(strcolor + strlen(strcolor), " dim=1"); + if ((*pp)->ucolor->reverse) sprintf(strcolor + strlen(strcolor), " reverse=1"); + if ((*pp)->ucolor->standout) sprintf(strcolor + strlen(strcolor), " standout=1"); + if ((*pp)->ucolor->underline) sprintf(strcolor + strlen(strcolor), " underline=1"); + if ((*pp)->ucolor->blink) sprintf(strcolor + strlen(strcolor), " blink=1"); + + // Remove the leading space + strcolor++; + + // previous implementation + //(void) fprintf(f, "cellcolor %s%d \"%s\"\n", coltoa((*pp)->col), (*pp)->row, strcolor); + + // new implementation + // by row, store cellcolors grouped by ranges + int c_aux = c; + struct ucolor * u = (*pp)->ucolor; + struct ucolor * a = NULL; + if ( c > 0 && *ATBL(sh, sh->tbl, r, c-1) != NULL) + a = (*ATBL(sh, sh->tbl, r, c-1))->ucolor; + + if ( *strcolor != '\0' && (u != NULL) && (c <= sh->maxcol) && ( c == 0 || ( a == NULL ) || ( a != NULL && ! same_ucolor( a, u ) ))) { + while (c_aux <= sh->maxcol && *ATBL(sh, sh->tbl, r, c_aux) != NULL && same_ucolor( (*ATBL(sh, sh->tbl, r, c_aux))->ucolor, (*pp)->ucolor )) + c_aux++; + fprintf(f, "cellcolor %s%d", coltoa((*pp)->col), (*pp)->row); + if (c_aux-1 != (*pp)->col) + fprintf(f, ":%s%d \"%s\"\n", coltoa(c_aux-1), (*pp)->row, strcolor); + else + fprintf(f, " \"%s\"\n", strcolor); } - } - if ((*pp)->ucolor->bold) sprintf(strcolor + strlen(strcolor), " bold=1"); - if ((*pp)->ucolor->italic) sprintf(strcolor + strlen(strcolor), " italic=1"); - if ((*pp)->ucolor->dim) sprintf(strcolor + strlen(strcolor), " dim=1"); - if ((*pp)->ucolor->reverse) sprintf(strcolor + strlen(strcolor), " reverse=1"); - if ((*pp)->ucolor->standout) sprintf(strcolor + strlen(strcolor), " standout=1"); - if ((*pp)->ucolor->underline) sprintf(strcolor + strlen(strcolor), " underline=1"); - if ((*pp)->ucolor->blink) sprintf(strcolor + strlen(strcolor), " blink=1"); + } - // Remove the leading space - strcolor++; + /* if ((*pp)->nrow >= 0) { + (void) fprintf(f, "addnote %s ", v_name((*pp)->row, (*pp)->col)); + (void) fprintf(f, "%s\n", r_name((*pp)->nrow, (*pp)->ncol, (*pp)->nlastrow, (*pp)->nlastcol)); + } */ + // padding // previous implementation - //(void) fprintf(f, "cellcolor %s%d \"%s\"\n", coltoa((*pp)->col), (*pp)->row, strcolor); + //if ((*pp)->pad) + // (void) fprintf(f, "pad %d %s%d\n", (*pp)->pad, coltoa((*pp)->col), (*pp)->row); + // new implementation + int r_aux = r; + if ( (*pp)->pad && r <= sh->maxrow && ( r == 0 || (*ATBL(sh, sh->tbl, r-1, c) == NULL) || + (*ATBL(sh, sh->tbl, r-1, c) != NULL && ((*ATBL(sh, sh->tbl, r-1, c))->pad != (*pp)->pad)) )) { + while (r_aux <= sh->maxrow && *ATBL(sh, sh->tbl, r_aux, c) != NULL && (*pp)->pad == (*ATBL(sh, sh->tbl, r_aux, c))->pad ) + r_aux++; + fprintf(f, "pad %d %s%d", (*pp)->pad, coltoa((*pp)->col), (*pp)->row); + if (r_aux-1 != (*pp)->row) + fprintf(f, ":%s%d\n", coltoa((*pp)->col), r_aux-1); + else + fprintf(f, "\n"); + } + } + } + // write locked cells + // lock should be stored after any other command + for (r = 0; r <= sh->maxrow; r++) { + pp = ATBL(sh, sh->tbl, r, 0); + for (c = 0; c <= sh->maxcol; c++, pp++) + if (*pp) { + // previous implementation + //if ((*pp)->flags & is_locked) + // (void) fprintf(f, "lock %s%d\n", coltoa((*pp)->col), (*pp)->row); // new implementation - // by row, store cellcolors grouped by ranges int c_aux = c; - struct ucolor * u = (*pp)->ucolor; - struct ucolor * a = NULL; - if ( c > 0 && *ATBL(tbl, r, c-1) != NULL) - a = (*ATBL(tbl, r, c-1))->ucolor; - - if ( *strcolor != '\0' && (u != NULL) && (c <= maxcol) && ( c == 0 || ( a == NULL ) || ( a != NULL && ! same_ucolor( a, u ) ))) { - while (c_aux <= maxcol && *ATBL(tbl, r, c_aux) != NULL && same_ucolor( (*ATBL(tbl, r, c_aux))->ucolor, (*pp)->ucolor )) + if ( (*pp)->flags & is_locked && c <= sh->maxcol && ( c == 0 || ( *ATBL(sh, sh->tbl, r, c-1) != NULL && ! ((*ATBL(sh, sh->tbl, r, c-1))->flags & is_locked) ) )) { + while (c_aux <= sh->maxcol && *ATBL(sh, sh->tbl, r, c_aux) != NULL && (*ATBL(sh, sh->tbl, r, c_aux))->flags & is_locked ) c_aux++; - fprintf(f, "cellcolor %s%d", coltoa((*pp)->col), (*pp)->row); + fprintf(f, "lock %s%d", coltoa((*pp)->col), (*pp)->row); if (c_aux-1 != (*pp)->col) - fprintf(f, ":%s%d \"%s\"\n", coltoa(c_aux-1), (*pp)->row, strcolor); + fprintf(f, ":%s%d\n", coltoa(c_aux-1), (*pp)->row); else - fprintf(f, " \"%s\"\n", strcolor); + fprintf(f, "\n"); } - } + } + /* + * Don't try to combine these into a single fprintf(). v_name() has + * a single buffer that is overwritten on each call, so the first part + * needs to be written to the file before making the second call. + */ + fprintf(f, "goto %s", v_name(sh->currow, sh->curcol)); + //fprintf(f, " %s\n", v_name(strow, stcol)); + fprintf(f, "\n"); - /* if ((*pp)->nrow >= 0) { - (void) fprintf(f, "addnote %s ", v_name((*pp)->row, (*pp)->col)); - (void) fprintf(f, "%s\n", r_name((*pp)->nrow, (*pp)->ncol, (*pp)->nlastrow, (*pp)->nlastcol)); - } */ - - // padding - // previous implementation - //if ((*pp)->pad) - // (void) fprintf(f, "pad %d %s%d\n", (*pp)->pad, coltoa((*pp)->col), (*pp)->row); - // new implementation - int r_aux = r; - if ( (*pp)->pad && r <= maxrow && ( r == 0 || (*ATBL(tbl, r-1, c) == NULL) || - (*ATBL(tbl, r-1, c) != NULL && ((*ATBL(tbl, r-1, c))->pad != (*pp)->pad)) )) { - while (r_aux <= maxrow && *ATBL(tbl, r_aux, c) != NULL && (*pp)->pad == (*ATBL(tbl, r_aux, c))->pad ) - r_aux++; - fprintf(f, "pad %d %s%d", (*pp)->pad, coltoa((*pp)->col), (*pp)->row); - if (r_aux-1 != (*pp)->row) - fprintf(f, ":%s%d\n", coltoa((*pp)->col), r_aux-1); - else - fprintf(f, "\n"); - } - } + sh = sh->next; } + // save movetosheet in sc file + if (doc->cur_sh != NULL) fprintf (f, "movetosheet \"%s\"\n", doc->cur_sh->name); - // write locked cells - // lock should be stored after any other command - for (r = r0; r <= rn; r++) { - pp = ATBL(tbl, r, c0); - for (c = c0; c <= cn; c++, pp++) - if (*pp) { - // previous implementation - //if ((*pp)->flags & is_locked) - // (void) fprintf(f, "lock %s%d\n", coltoa((*pp)->col), (*pp)->row); - // new implementation - int c_aux = c; - if ( (*pp)->flags & is_locked && c <= maxcol && ( c == 0 || ( *ATBL(tbl, r, c-1) != NULL && ! ((*ATBL(tbl, r, c-1))->flags & is_locked) ) )) { - while (c_aux <= maxcol && *ATBL(tbl, r, c_aux) != NULL && (*ATBL(tbl, r, c_aux))->flags & is_locked ) - c_aux++; - fprintf(f, "lock %s%d", coltoa((*pp)->col), (*pp)->row); - if (c_aux-1 != (*pp)->col) - fprintf(f, ":%s%d\n", coltoa(c_aux-1), (*pp)->row); - else - fprintf(f, "\n"); - } - } - } + // write marks of document + write_marks(f); - /* - * Don't try to combine these into a single fprintf(). v_name() has - * a single buffer that is overwritten on each call, so the first part - * needs to be written to the file before making the second call. - */ - fprintf(f, "goto %s", v_name(currow, curcol)); - //fprintf(f, " %s\n", v_name(strow, stcol)); - fprintf(f, "\n"); } -/** - * \brief TODO Document write_franges() - * - * \param[in] f file pointer - * - * \return none - */ -void write_franges(register FILE *f) { - if (! freeze_ranges) return; - if (freeze_ranges->type == 'a') { - fprintf(f, "freeze %s%d", coltoa(freeze_ranges->tl->col), freeze_ranges->tl->row); - fprintf(f, ":%s%d\n", coltoa(freeze_ranges->br->col), freeze_ranges->br->row); - } else if (freeze_ranges->type == 'c' && freeze_ranges->tl->col == freeze_ranges->br->col) { - fprintf(f, "freeze %s\n", coltoa(freeze_ranges->tl->col)); - } else if (freeze_ranges->type == 'c') { - fprintf(f, "freeze %s:", coltoa(freeze_ranges->tl->col)); - fprintf(f, "%s\n", coltoa(freeze_ranges->br->col)); - } else if (freeze_ranges->type == 'r' && freeze_ranges->tl->row == freeze_ranges->br->row) { - fprintf(f, "freeze %d\n", freeze_ranges->tl->row); - } else if (freeze_ranges->type == 'r') { - fprintf(f, "freeze %d:%d\n", freeze_ranges->tl->row, freeze_ranges->br->row); - } -} /** - * \brief TODO Document write_marks() - * + * \brief write_marks() * \param[in] f file pointer - * * \return none */ -void write_marks(register FILE *f) { +void write_marks(FILE * f) { int i; struct mark * m; @@ -642,20 +647,22 @@ m = get_mark((char) i); // m->rng should never be NULL if both m->col and m->row are -1 !! - if ( m->row == -1 && m->col == -1) { // && m->rng != NULL ) { - fprintf(f, "mark %c %s%d ", i, coltoa(m->rng->tlcol), m->rng->tlrow); + if ( m->row == -1 && m->col == -1) { + fprintf(f, "mark %c \"%s\" %s%d ", i, m->sheet->name, coltoa(m->rng->tlcol), m->rng->tlrow); fprintf(f, "%s%d\n", coltoa(m->rng->brcol), m->rng->brrow); - } else if ( m->row != 0 && m->row != 0) { // && m->rng == NULL) { - fprintf(f, "mark %c %s%d\n", i, coltoa(m->col), m->row); + } else if ( m->row != 0 && m->row != 0) { + fprintf(f, "mark %c \"%s\" %s%d\n", i, m->sheet->name, coltoa(m->col), m->row); } } - return; } + /** - * \brief TODO Document write_cells() - * + * \brief write_cells() + * \param[in] struct roman * doc + * \param[in] struct sheet * sh + * \param[in] r0 * \param[in] f file pointer * \param[in] r0 * \param[in] c0 @@ -663,72 +670,87 @@ * \param[in] cn * \param[in] dr * \param[in[ dc - * * \return none */ -void write_cells(register FILE *f, int r0, int c0, int rn, int cn, int dr, int dc) { - register struct ent **pp; +void write_cells(FILE * f, struct roman * doc, struct sheet * sh, int r0, int c0, int rn, int cn, int dr, int dc) { + struct ent ** pp; int r, c; - //int r, c, mf; - char *dpointptr; + char * dpointptr; - //mf = modflg; + int mf = doc->modflg; if (dr != r0 || dc != c0) { //yank_area(r0, c0, rn, cn); rn += dr - r0; cn += dc - c0; - //rs = currow; - //cs = curcol; - currow = dr; - curcol = dc; + //rs = sh->currow; + //cs = sh->curcol; + sh->currow = dr; + sh->curcol = dc; } //if (Vopt) valueize_area(dr, dc, rn, cn); for (r = dr; r <= rn; r++) { - pp = ATBL(tbl, r, dc); + pp = ATBL(sh, sh->tbl, r, dc); for (c = dc; c <= cn; c++, pp++) if (*pp) { if ((*pp)->label || (*pp)->flags & is_strexpr) { - edits(r, c, 1); + edits(sh, r, c, 1); (void) fprintf(f, "%s\n", line); } if ((*pp)->flags & is_valid) { //if ((*pp)->flags & is_valid || (*pp)->expr) { // for #541 - editv(r, c); + editv(sh, r, c); dpointptr = strchr(line, dpoint); if (dpointptr != NULL) *dpointptr = '.'; (void) fprintf(f, "%s\n", line); } if ((*pp)->format) { - editfmt(r, c); + editfmt(sh, r, c); (void) fprintf(f, "%s\n",line); } + if ((*pp)->trigger != NULL) { + struct trigger * t = (*pp)->trigger; + char * mode = NULL; + if ((t->flag & (TRG_READ | TRG_WRITE)) == (TRG_READ | TRG_WRITE)) mode = "RW"; + else if (t->flag & TRG_WRITE) mode = "W"; + else if (t->flag & TRG_READ) mode = "R"; + char * type = NULL; + if (t->flag & TRG_LUA) type = "LUA"; + else type = "C"; + fprintf(f, "trigger %s%d \"mode=%s type=%s file=%s function=%s\"\n", coltoa(c), r, mode, type, t->file, t->function); + } } } - //modflg = mf; + // restore modflg just in case + doc->modflg = mf; } + /** * \brief Try to open a spreadsheet file. * * \param[in] fname file name * \param[in] eraseflg * - * \return SC_READFILE_SUCCESS if we loaded the file, SC_READFILE_ERROR if we failed, + * \return + * SC_READFILE_SUCCESS if we could load the file, + * SC_READFILE_ERROR if we failed, * SC_READFILE_DOESNTEXIST if the file doesn't exist. */ sc_readfile_result readfile(char * fname, int eraseflg) { - if (!strlen(fname)) return 0; - loading = 1; + struct roman * roman = session->cur_doc; + char * curfile = roman->name; + if (! strlen(fname)) return 0; + roman->loading = 1; #ifdef AUTOBACKUP // Check if curfile is set and backup exists.. if (str_in_str(fname, CONFIG_FILE) == -1 && strlen(curfile) && backup_exists(curfile) && strcmp(fname, curfile)) { - if (modflg) { + if (roman->modflg) { // TODO - force load with '!' ?? sc_error("There are changes unsaved. Cannot load file: %s", fname); - loading = 0; + roman->loading = 0; return SC_READFILE_ERROR; } remove_backup(curfile); @@ -743,7 +765,7 @@ switch (t) { case L'q': case L'Q': - loading = 0; + roman->loading = 0; extern int shall_quit; shall_quit = 1; return SC_READFILE_ERROR; @@ -782,10 +804,13 @@ sc_error("XLSX import support not compiled in"); #else open_xlsx(fname, "UTF-8"); - strcpy(curfile, fname); - modflg = 0; + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, fname); + roman->modflg = 0; #endif - loading = 0; + roman->loading = 0; + //TODO we should EvalAll here return SC_READFILE_SUCCESS; // If file is an ODS file, we import it @@ -794,10 +819,12 @@ sc_error("ODS import support not compiled in"); #else open_ods(fname, "UTF-8"); - strcpy(curfile, fname); - modflg = 0; + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, fname); + roman->modflg = 0; #endif - loading = 0; + roman->loading = 0; return SC_READFILE_SUCCESS; // If file is an xls file, we import it @@ -806,21 +833,25 @@ sc_error("XLS import support not compiled in"); #else open_xls(fname, "UTF-8"); - modflg = 0; - strcpy(curfile, fname); + roman->modflg = 0; + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, fname); #endif - loading = 0; + roman->loading = 0; return SC_READFILE_SUCCESS; - // If file is an delimited text file, we import it + // If file is a delimited text file, we import it } else if (len > 4 && ( ! strcasecmp( & fname[len-4], ".csv") || ! strcasecmp( & fname[len-4], ".tsv") || ! strcasecmp( & fname[len-4], ".tab") || ! strcasecmp( & fname[len-4], ".txt") )){ import_csv(fname, get_delim(&fname[len-3])); // csv tsv tab txt delim import - strcpy(curfile, fname); - modflg = 0; - loading = 0; + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, fname); + roman->modflg = 0; + roman->loading = 0; return SC_READFILE_SUCCESS; // If file is a markdown text file, we try to import it @@ -828,14 +859,16 @@ ! strcasecmp( & fname[len-4], ".mkd"))){ import_markdown(fname); - strcpy(curfile, fname); - modflg = 0; - loading = 0; + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, fname); + roman->modflg = 0; + roman->loading = 0; return SC_READFILE_SUCCESS; } else { - sc_info("\"%s\" is not a SC-IM compatible file", fname); - loading = 0; + sc_info("\"%s\" is not a sc-im compatible file", fname); + roman->loading = 0; return SC_READFILE_ERROR; } @@ -847,12 +880,16 @@ (void) strcpy(save, fname); f = fopen(save, "r"); if (f == NULL) { - loading = 0; - strcpy(curfile, save); + roman->loading = 0; + if (strstr(save, "scimrc") == NULL) { + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, save); + } return SC_READFILE_DOESNTEXIST; - } /* */ + } - if (eraseflg) erasedb(); + if (eraseflg) erasedb(roman->cur_sh, 0); //TODO handle file while (! brokenpipe && fgets(line, sizeof(line), f)) { linelim = 0; @@ -860,22 +897,25 @@ } fclose(f); - loading = 0; + roman->loading = 0; linelim = -1; if (eraseflg) { cellassign = 0; } - strcpy(curfile, save); + if (strstr(save, "scimrc") == NULL) { + if (roman->name != NULL) free(roman->name); + roman->name = malloc(sizeof(char)*PATHLEN); + strcpy(roman->name, save); + } EvalAll(); - modflg = 0; + roman->modflg = 0; return SC_READFILE_SUCCESS; } + /** * \brief Expand a ~ in path to the user's home directory - * * \param[in] path - * * \return path */ char * findhome(char * path) { @@ -914,15 +954,13 @@ return (path); } + /** * \brief Open the input or output file - * * \details Open the input or output file, setting up a pipe if needed. - * * \param[in] fname file name * \param[in] rpid * \param[in] rfd - * * \return file pointer */ FILE * openfile(char *fname, int *rpid, int *rfd) { @@ -985,16 +1023,12 @@ return (f); } -// close a file opened by openfile(), if process wait for return /** * \brief Close a file opened by openfile() - * * \details Close a file opened by openfile(). If process, wait for return - * * \param[in] f file pointer * \param[in] pid * \param[in] rfd - * * \return none */ void closefile(FILE *f, int pid, int rfd) { @@ -1028,11 +1062,10 @@ } } + /** * \brief TODO - * * \param[in] f file pointer - * * \return none */ void print_options(FILE *f) { @@ -1041,8 +1074,7 @@ ! rndtoeven && calc_order == BYROWS && prescale == 1.0 && - ! get_conf_int("external_functions") && - tbl_style == 0 + ! get_conf_int("external_functions") ) return; // No reason to do this @@ -1052,28 +1084,24 @@ if (calc_order != BYROWS ) (void) fprintf(f, " bycols"); if (prescale != 1.0) (void) fprintf(f, " prescale"); if ( get_conf_int("external_functions") ) (void) fprintf(f, " external_functions"); - if (tbl_style) (void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" : tbl_style == LATEX ? "latex" : tbl_style == SLATEX ? "slatex" : tbl_style == TEX ? "tex" : tbl_style == FRAME ? "frame" : "0" ); (void) fprintf(f, "\n"); } /** * \brief Import csv to sc - * * \param[in] fname file name * \param[in] d = delim character - * * \return 0 on success; -1 on error */ int import_csv(char * fname, char d) { + struct roman * roman = session->cur_doc; register FILE * f; int r = 0, c = 0, cf = 0; wchar_t line_interp[FBUFLEN] = L""; char * token; - - int quote = 0; // if value has '"'. ex: 12,"1234,450.00",56 - char delim[2] = ""; //strtok receives a char *, not a char - add_char(delim, d, 0); + char * next; + int eol = 0; if ((f = fopen(fname , "r")) == NULL) { sc_error("Can't read file \"%s\"", fname); @@ -1095,17 +1123,12 @@ int i=0; - // handle "," - char lookf[4], repls[2], replb[2]; - sprintf(lookf, "\"%c\"", d); - sprintf(repls, "%c", 6); - sprintf(replb, "%c", d); - // CSV file traversing while ( ! feof(f) && (fgets(line_in, sizeof(line_in), f) != NULL) ) { + eol = 0; + // show file loading progress - i++; // increase number of line; - if (i % 10 == 0 ) sc_info("loading line %d of %d", i, max_lines); + if (++i % 10 == 0 ) sc_info("loading line %d of %d", i, max_lines); // this hack is for importing file that have DOS eol int l = strlen(line_in); @@ -1115,60 +1138,55 @@ break; } - strcpy(line_in, str_replace(line_in, lookf, repls)); // handle "," case + next = line_in; - // Split string using the delimiter - token = xstrtok(line_in, delim); c = 0; - while( token != NULL ) { + while( !eol ) { if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; + + // Split string using the delimiter + token = next; + next += next_unquot_delim(token, d); + if (*next == '\0') + eol = 1; + else { + *next = '\0'; + next++; + } + clean_carrier(token); + + // remove quotes if ( token[0] == '\"' && token[strlen(token)-1] == '\"') { - quote = 1; - } else if ( (token[0] == '\"' || quote) && strlen(token) && (token[strlen(token)-1] != '\"' || strlen(token) == 1) ) { - quote = 1; - char * next = xstrtok(NULL, delim); - - if (next != NULL) { - sprintf(token + strlen(token), "%c%s", d, next); - continue; - } + token[strlen(token)-1] = '\0'; + token++; } - if (quote) { // Remove quotes - del_char(token, 0); - del_char(token, strlen(token)-1); - } - - char * st = str_replace (token, repls, replb); // handle "," case // number import - if (strlen(st) && isnumeric(st) && ! get_conf_int("import_delimited_as_text") + if (strlen(token) && isnumeric(token) && ! get_conf_int("import_delimited_as_text") ) { //wide char - swprintf(line_interp, BUFFERSIZE, L"let %s%d=%s", coltoa(c), r, st); + swprintf(line_interp, BUFFERSIZE, L"let %s%d=%s", coltoa(c), r, token); // text import - } else if (strlen(st)){ + } else if (strlen(token)){ //wide char - swprintf(line_interp, BUFFERSIZE, L"label %s%d=\"%s\"", coltoa(c), r, st); + swprintf(line_interp, BUFFERSIZE, L"label %s%d=\"%s\"", coltoa(c), r, token); } //wide char - if (strlen(st)) send_to_interp(line_interp); + if (strlen(token)) send_to_interp(line_interp); if (++c > cf) cf = c; - quote = 0; - token = xstrtok(NULL, delim); - free(st); } r++; if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; } - maxrow = r-1; - maxcol = cf-1; + roman->cur_sh->maxrow = r-1; + roman->cur_sh->maxcol = cf-1; - auto_justify(0, maxcols, DEFWIDTH); + auto_fit(roman->cur_sh, 0, roman->cur_sh->maxcols, DEFWIDTH); fclose(f); @@ -1176,183 +1194,208 @@ return 0; } + +/** + * \brief find next unquoted delimiter + * \details Helper function to import_csv(). Returns the + * relative position of the next delimiter character that + * is not quoted with double-quotes ("). + * \param[in] start where we are in the line + * \param[in] d the delimiter character + * \return number of characters to move from start to next + * delimiter or EOL + */ +int next_unquot_delim(char *start, char d) { + int quote = 0; + char *p = start; + int count = 0; + + while(1) { + if (*p == '\0') + return count; + if (*p == d && !quote) + return count; + if (*p == '\"') + quote = !quote; + count++; + p++; + } +} + + /** * \brief Import Markdown to sc - * * \param[in] fname file name * \param[in] d - * * \return 0 on success; -1 on error */ - int import_markdown(char * fname) { - register FILE * f; - int r = 0, c = 0, cf = 0; - wchar_t line_interp[FBUFLEN] = L""; - wchar_t line_interp_align[FBUFLEN] = L""; - char * token; - - //int pipe = 0; // if value has '"'. ex: 12,"1234,450.00",56 - int rownr = 0; - char d = '|'; - char delim[2] = ""; //strtok receives a char *, not a char - add_char(delim, d, 0); - // int linenumber = 0; - - if ((f = fopen(fname , "r")) == NULL) { - sc_error("Can't read file \"%s\"", fname); - return -1; - } - - // Check max length of line - int max = max_length(f) + 1; - if (max == 0) { - sc_error("Can't read file \"%s\"", fname); - return -1; - } - char line_in[max]; - char line_in_head[max]; - char align[max]; - rewind(f); - - while ( ! feof(f) && (fgets(line_in, sizeof(line_in), f) != NULL) ) { - - // this hack is for importing file that have DOS eol - int l = strlen(line_in); - while (l--){ - if (line_in[l] == 0x0d) { - line_in[l] = '\0'; - break; - } - } - - /* - if ( line_in[0] == '|' && line_in[strlen(line_in)-1] == '|') { - pipe = 1; - } - */ - //pipe = 0; - del_char(line_in, 0); - del_char(line_in, strlen(line_in)-1); - - if(r==1){ - strcpy(line_in_head, line_in); - - token = xstrtok(line_in_head, delim); - c = 0; + struct roman * roman = session->cur_doc; + register FILE * f; + int r = 0, c = 0, cf = 0; + wchar_t line_interp[FBUFLEN] = L""; + wchar_t line_interp_align[FBUFLEN] = L""; + char * token; - while( token != NULL ) { - if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; - clean_carrier(token); - token = ltrim(token, ' '); - token = rtrim(token, ' '); - - if((token[0] == ':' && token[strlen(token)-1] == '-') || - (token[0] == '-' && token[strlen(token)-1] == '-')){ - align[c] = 'l'; - swprintf(line_interp_align, BUFFERSIZE, L"leftjustify %s", v_name(r-1, c)); + //int pipe = 0; // if value has '"'. ex: 12,"1234,450.00",56 + int rownr = 0; + char d = '|'; + char delim[2] = ""; //strtok receives a char *, not a char + add_char(delim, d, 0); + // int linenumber = 0; - } - else if(token[0] == '-' && token[strlen(token)-1] == ':'){ - align[c] = 'r'; - swprintf(line_interp_align, BUFFERSIZE, L"rightjustify %s", v_name(r-1, c)); - } - else{ - swprintf(line_interp_align, BUFFERSIZE, L"center %s", v_name(r-1, c)); - align[c] = 'c'; - } + if ((f = fopen(fname , "r")) == NULL) { + sc_error("Can't read file \"%s\"", fname); + return -1; + } - send_to_interp(line_interp_align); - token = xstrtok(NULL, delim); - c++; - } + // Check max length of line + int max = max_length(f) + 1; + if (max == 0) { + sc_error("Can't read file \"%s\"", fname); + return -1; } - else{ + char line_in[max]; + char line_in_head[max]; + char align[max]; + rewind(f); - // Split string using the delimiter - token = xstrtok(line_in, delim); + while ( ! feof(f) && (fgets(line_in, sizeof(line_in), f) != NULL) ) { - c = 0; + // this hack is for importing file that have DOS eol + int l = strlen(line_in); + while (l--){ + if (line_in[l] == 0x0d) { + line_in[l] = '\0'; + break; + } + } - while( token != NULL ) { - if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; + /* + if ( line_in[0] == '|' && line_in[strlen(line_in)-1] == '|') { + pipe = 1; + } + */ + //pipe = 0; + del_char(line_in, 0); + del_char(line_in, strlen(line_in)-1); + + if(r==1){ + strcpy(line_in_head, line_in); + + token = xstrtok(line_in_head, delim); + c = 0; + + while( token != NULL ) { + if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; + clean_carrier(token); + token = ltrim(token, ' '); + token = rtrim(token, ' '); + + if((token[0] == ':' && token[strlen(token)-1] == '-') || + (token[0] == '-' && token[strlen(token)-1] == '-')){ + align[c] = 'l'; + swprintf(line_interp_align, BUFFERSIZE, L"leftjustify %s", v_name(r-1, c)); - if(r == 0){ - rownr = r; + } + else if(token[0] == '-' && token[strlen(token)-1] == ':'){ + align[c] = 'r'; + swprintf(line_interp_align, BUFFERSIZE, L"rightjustify %s", v_name(r-1, c)); + } + else{ + swprintf(line_interp_align, BUFFERSIZE, L"center %s", v_name(r-1, c)); + align[c] = 'c'; + } + + send_to_interp(line_interp_align); + token = xstrtok(NULL, delim); + c++; + } } else{ - rownr = r-1; - } - clean_carrier(token); - token = ltrim(token, ' '); - token = rtrim(token, ' '); + // Split string using the delimiter + token = xstrtok(line_in, delim); - char * st = str_replace(token, "\"", "''"); //replace double quotes inside string + c = 0; - // number import - if (isnumeric(st) && strlen(st) && ! atoi(get_conf_value("import_delimited_as_text"))) { - //wide char - swprintf(line_interp, BUFFERSIZE, L"let %s%d=%s", coltoa(c), rownr, st); + while( token != NULL ) { + if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; - // text import - } else if (strlen(st)){ - //wide char - swprintf(line_interp, BUFFERSIZE, L"label %s%d=\"%s\"", coltoa(c), rownr, st); - } - //wide char - if (strlen(st)){ - send_to_interp(line_interp); + if(r == 0){ + rownr = r; + } + else{ + rownr = r-1; + } - if(r>0){ - if(align[c] == 'l'){ - swprintf(line_interp_align, BUFFERSIZE, L"leftjustify %s", v_name(rownr, c)); - } - else if(align[c] == 'r'){ - swprintf(line_interp_align, BUFFERSIZE, L"rightjustify %s", v_name(rownr, c)); - } - else{ - swprintf(line_interp_align, BUFFERSIZE, L"center %s", v_name(rownr, c)); - } - send_to_interp(line_interp_align); - } + clean_carrier(token); + token = ltrim(token, ' '); + token = rtrim(token, ' '); + + char * st = str_replace(token, "\"", "''"); //replace double quotes inside string + + // number import + if (isnumeric(st) && strlen(st) && ! atoi(get_conf_value("import_delimited_as_text"))) { + //wide char + swprintf(line_interp, BUFFERSIZE, L"let %s%d=%s", coltoa(c), rownr, st); + + // text import + } else if (strlen(st)){ + //wide char + swprintf(line_interp, BUFFERSIZE, L"label %s%d=\"%s\"", coltoa(c), rownr, st); + } + //wide char + if (strlen(st)){ + send_to_interp(line_interp); + if(r>0){ + if(align[c] == 'l'){ + swprintf(line_interp_align, BUFFERSIZE, L"leftjustify %s", v_name(rownr, c)); + } + else if(align[c] == 'r'){ + swprintf(line_interp_align, BUFFERSIZE, L"rightjustify %s", v_name(rownr, c)); + } + else{ + swprintf(line_interp_align, BUFFERSIZE, L"center %s", v_name(rownr, c)); + } + send_to_interp(line_interp_align); + } + + } + free(st); + + if (++c > cf) cf = c; + token = xstrtok(NULL, delim); + } } - free(st); - if (++c > cf) cf = c; - token = xstrtok(NULL, delim); - } + roman->cur_sh->maxcol = cf-1; + r++; + if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; } + roman->cur_sh->maxrow = r-1; + roman->cur_sh->maxcol = cf-1; - maxcol = cf-1; - r++; - if (r > MAXROWS - GROWAMT - 1 || c > ABSMAXCOLS - 1) break; - } - maxrow = r-1; - maxcol = cf-1; - - auto_justify(0, maxcols, DEFWIDTH); + auto_fit(roman->cur_sh, 0, roman->cur_sh->maxcols, DEFWIDTH); - fclose(f); + fclose(f); - EvalAll(); - return 0; + EvalAll(); + return 0; } - /** * \brief Export to CSV, TAB, or plain TXT - * * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn - * * \return none */ void do_export(int r0, int c0, int rn, int cn) { + char * curfile = session->cur_doc->name; int force_rewrite = 0; char type_export[4] = ""; char ruta[PATHLEN]; @@ -1383,7 +1426,7 @@ // Use curfile name and '.csv' o '.tab' extension // Remove current '.sc' extension if necessary - } else if (curfile[0]) { + } else if (curfile != NULL && curfile[0]) { strcpy(ruta, curfile); char * ext = strrchr(ruta, '.'); if (ext != NULL) del_range_chars(ruta, strlen(ruta) - strlen(ext), strlen(ruta)-1); @@ -1431,16 +1474,15 @@ /** * \brief Export to md file with markdown table - * * \param[in] fname file name * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn - * * \return none */ void export_markdown(char * fname, int r0, int c0, int rn, int cn) { + struct roman * roman = session->cur_doc; FILE * f; int row, col; register struct ent ** pp; @@ -1458,9 +1500,9 @@ } // to prevent empty lines at the end of the file - struct ent * ent = go_end(); + struct ent * ent = go_end(roman->cur_sh); if (rn > ent->row) rn = ent->row; - ent = goto_last_col(); // idem with columns + ent = goto_last_col(roman->cur_sh); // idem with columns if (cn > ent->col) cn = ent->col; char num [FBUFLEN] = ""; @@ -1472,13 +1514,15 @@ int dash_num; int rowfmt; + int ignore_hidden = get_conf_int("ignore_hidden"); + for (row = r0; row <= rn; row++) { - for (rowfmt=0; rowfmtcur_sh->row_format[row]; rowfmt++) { // ignore hidden rows - //if (row_hidden[row]) continue; + if (ignore_hidden && roman->cur_sh->row_hidden[row]) continue; - for (pp = ATBL(tbl, row, col = c0); col <= cn; col++, pp++) { + for (pp = ATBL(roman->cur_sh, roman->cur_sh->tbl, row, col = c0); col <= cn; col++, pp++) { // ignore hidden cols //if (col_hidden[col]) continue; @@ -1496,7 +1540,7 @@ } else { strcat (dashline, "-"); } - for (dash_num = 0; dash_num < fwidth[col]; dash_num++) { + for (dash_num = 0; dash_num < roman->cur_sh->fwidth[col]; dash_num++) { strcat (dashline, "-"); } if(align >= 0) { @@ -1523,7 +1567,7 @@ if (res == 0 || res == 1) { strcpy(num, formated_s); } else if (res == -1) { - sprintf(num, "%.*f", precision[col], (*pp)->v); + sprintf(num, "%.*f", roman->cur_sh->precision[col], (*pp)->v); } } @@ -1541,18 +1585,18 @@ } - pad_and_align (text, num, fwidth[col], align, 0, out, row_format[row]); + pad_and_align (text, num, roman->cur_sh->fwidth[col], align, 0, out, roman->cur_sh->row_format[row]); wchar_t new[wcslen(out)+1]; wcscpy(new, out); - int cw = count_width_widestring(new, fwidth[col]); + int cw = count_width_widestring(new, roman->cur_sh->fwidth[col]); if (wcslen(new) > cw && rowfmt) { int count_row = 0; for (count_row = 0; count_row < rowfmt; count_row++) { - cw = count_width_widestring(new, fwidth[col]); + cw = count_width_widestring(new, roman->cur_sh->fwidth[col]); if (cw) del_range_wchars(new, 0, cw-1); - int whites = fwidth[col] - wcslen(new); + int whites = roman->cur_sh->fwidth[col] - wcslen(new); while (whites-- > 0) add_wchar(new, L' ', wcslen(new)); } new[cw] = L'\0'; @@ -1561,10 +1605,10 @@ if (get_conf_int("truncate") || !get_conf_int("overlap")) new[cw] = L'\0'; fprintf (f, "%ls", new); } else { - fprintf (f, "%*s", fwidth[col], " "); + fprintf (f, "%*s", roman->cur_sh->fwidth[col], " "); } } else { - fprintf (f, "%*s", fwidth[col], " "); + fprintf (f, "%*s", roman->cur_sh->fwidth[col], " "); } } fprintf(f," |\n"); @@ -1581,18 +1625,18 @@ } } + /** * \brief Export to plain TXT - * * \param[in] fname file name * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn - * * \return none */ void export_plain(char * fname, int r0, int c0, int rn, int cn) { + struct roman * roman = session->cur_doc; FILE * f; int row, col; register struct ent ** pp; @@ -1610,9 +1654,9 @@ } // to prevent empty lines at the end of the file - struct ent * ent = go_end(); + struct ent * ent = go_end(roman->cur_sh); if (rn > ent->row) rn = ent->row; - ent = goto_last_col(); // idem with columns + ent = goto_last_col(roman->cur_sh); // idem with columns if (cn > ent->col) cn = ent->col; char num [FBUFLEN] = ""; @@ -1622,13 +1666,15 @@ int align = 1; int rowfmt; + int ignore_hidden = get_conf_int("ignore_hidden"); + for (row = r0; row <= rn; row++) { - for (rowfmt=0; rowfmtcur_sh->row_format[row]; rowfmt++) { // ignore hidden rows - //if (row_hidden[row]) continue; + if (ignore_hidden && roman->cur_sh->row_hidden[row]) continue; - for (pp = ATBL(tbl, row, col = c0); col <= cn; col++, pp++) { + for (pp = ATBL(roman->cur_sh, roman->cur_sh->tbl, row, col = c0); col <= cn; col++, pp++) { // ignore hidden cols //if (col_hidden[col]) continue; @@ -1649,7 +1695,7 @@ if (res == 0 || res == 1) { strcpy(num, formated_s); } else if (res == -1) { - sprintf(num, "%.*f", precision[col], (*pp)->v); + sprintf(num, "%.*f", roman->cur_sh->precision[col], (*pp)->v); } } @@ -1666,18 +1712,18 @@ } } - pad_and_align (text, num, fwidth[col], align, 0, out, row_format[row]); + pad_and_align (text, num, roman->cur_sh->fwidth[col], align, 0, out, roman->cur_sh->row_format[row]); wchar_t new[wcslen(out)+1]; wcscpy(new, out); - int cw = count_width_widestring(new, fwidth[col]); + int cw = count_width_widestring(new, roman->cur_sh->fwidth[col]); if (wcslen(new) > cw && rowfmt) { int count_row = 0; for (count_row = 0; count_row < rowfmt; count_row++) { - cw = count_width_widestring(new, fwidth[col]); + cw = count_width_widestring(new, roman->cur_sh->fwidth[col]); if (cw) del_range_wchars(new, 0, cw-1); - int whites = fwidth[col] - wcslen(new); + int whites = roman->cur_sh->fwidth[col] - wcslen(new); while (whites-- > 0) add_wchar(new, L' ', wcslen(new)); } new[cw] = L'\0'; @@ -1686,10 +1732,10 @@ if (get_conf_int("truncate") || !get_conf_int("overlap")) new[cw] = L'\0'; fprintf (f, "%ls", new); } else { - fprintf (f, "%*s", fwidth[col], " "); + fprintf (f, "%*s", roman->cur_sh->fwidth[col], " "); } } else { - fprintf (f, "%*s", fwidth[col], " "); + fprintf (f, "%*s", roman->cur_sh->fwidth[col], " "); } } fprintf(f,"\n"); @@ -1704,16 +1750,27 @@ } + +/** + * \brief Export current tbl to latex format + * \param[in] fname file name + * \param[in] r0 + * \param[in] c0 + * \param[in] rn + * \param[in] cn + * \return none + */ void export_latex(char * fname, int r0, int c0, int rn, int cn, int verbose) { + struct roman * roman = session->cur_doc; FILE * f; int row, col; register struct ent ** pp; int pid; // to prevent empty lines at the end of the file - struct ent * ent = go_end(); + struct ent * ent = go_end(roman->cur_sh); if (rn > ent->row) rn = ent->row; - ent = goto_last_col(); // idem with columns + ent = goto_last_col(roman->cur_sh); // idem with columns if (cn > ent->col) cn = ent->col; if (verbose) sc_info("Writing file \"%s\"...", fname); @@ -1728,28 +1785,28 @@ } // do the stuff - fprintf(f,"%% ** SC-IM spreadsheet output\n\\begin{tabular}{"); + fprintf(f,"%% ** sc-im spreadsheet output\n\\begin{tabular}{"); for (col=c0;col<=cn; col++) fprintf(f,"c"); fprintf(f, "}\n"); char coldelim = '&'; for (row=r0; row<=rn; row++) { - for (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) { + for (pp = ATBL(roman->cur_sh, roman->cur_sh->tbl, row, col=c0); col<=cn; col++, pp++) { if (*pp) { char *s; if ((*pp)->flags & is_valid) { if ((*pp)->cellerror) { - (void) fprintf (f, "%*s", fwidth[col], ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID")); + (void) fprintf (f, "%*s", roman->cur_sh->fwidth[col], ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID")); } else if ((*pp)->format) { char field[FBUFLEN]; if (*((*pp)->format) == ctl('d')) { time_t v = (time_t) ((*pp)->v); strftime(field, sizeof(field), ((*pp)->format)+1, localtime(&v)); } else - format((*pp)->format, precision[col], (*pp)->v, field, sizeof(field)); + format((*pp)->format, roman->cur_sh->precision[col], (*pp)->v, field, sizeof(field)); unspecial(f, field, coldelim); } else { char field[FBUFLEN]; - (void) engformat(realfmt[col], fwidth[col], precision[col], (*pp) -> v, field, sizeof(field)); + (void) engformat(roman->cur_sh->realfmt[col], roman->cur_sh->fwidth[col], roman->cur_sh->precision[col], (*pp) -> v, field, sizeof(field)); unspecial(f, field, coldelim); } } @@ -1761,45 +1818,54 @@ fprintf(f,"\n"); } - fprintf(f,"\\end{tabular}\n%% ** end of SC-IM spreadsheet output\n"); + fprintf(f,"\\end{tabular}\n%% ** end of sc-im spreadsheet output\n"); if (fname != NULL) closefile(f, pid, 0); if (! pid && verbose) sc_info("File \"%s\" written", fname); } + /** - * \brief TODO Document unspecial() + * \brief escape special characters and output cell to file * - * \details Unspecial (backquotes - > ") things that are special - * chars in a table + * \details For the export formats delimiter-separated value + * and LaTex. Escapes the special characters in one cell value + * and appends the cell to the file. * * \param[in] f file pointer - * \param[in] srt string pointer + * \param[in] str string pointer * \param[in] delim * * \return none */ void unspecial(FILE * f, char * str, int delim) { int backquote = 0; + if (strchr(str, delim) != NULL) backquote = 1; - if (str_in_str(str, ",") != -1) backquote = 1; - if (backquote) putc('\"', f); if (*str == '\\') str++; // delete wheeling string operator, OK? - while (*str) { - // for LATEX export - if (delim == '&' && ( (*str == '&') || (*str == '$') || - (*str == '#') || (*str == '%') || (*str == '{') || (*str == '}') || (*str == '&'))) - putc('\\', f); - putc(*str, f); - str++; + + if (delim == '&') { // the export format is LaTex + while (*str) { + if ( (*str == '&') || (*str == '$') || (*str == '#') || + (*str == '%') || (*str == '{') || (*str == '}') || (*str == '_') ) + putc('\\', f); + putc(*str, f); + str++; + } + } else { + if (backquote) putc('\"', f); + while (*str) { + putc(*str, f); + str++; + } + if (backquote) putc('\"', f); } - if (backquote) putc('\"', f); } + /** - * \brief TODO Document export_delim - * + * \brief export_delim() - export current tbl to delimited format * \param[in] fname full path of the file * \param[in] coldelim * \param[in] r0 @@ -1807,19 +1873,20 @@ * \param[in] rn * \param[in] cn * \param[in] verbose - * * \return none */ void export_delim(char * fname, char coldelim, int r0, int c0, int rn, int cn, int verbose) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; FILE * f; int row, col; - register struct ent ** pp; + struct ent ** pp; int pid; // to prevent empty lines at the end of the file - struct ent * ent = go_end(); + struct ent * ent = go_end(sh); if (rn > ent->row) rn = ent->row; - ent = goto_last_col(); // idem with columns + ent = goto_last_col(sh); // idem with columns if (cn > ent->col) cn = ent->col; if (verbose) sc_info("Writing file \"%s\"...", fname); @@ -1833,28 +1900,30 @@ } } + int ignore_hidden = get_conf_int("ignore_hidden"); for (row = r0; row <= rn; row++) { - for (pp = ATBL(tbl, row, col = c0); col <= cn; col++, pp++) { - int last_valid_col = right_limit(row)->col; // for issue #374 + if (ignore_hidden && sh->row_hidden[row]) continue; + for (pp = ATBL(sh, sh->tbl, row, col = c0); col <= cn; col++, pp++) { + int last_valid_col = right_limit(sh, row)->col; // for issue #374 if (col > last_valid_col) continue; if (*pp) { char * s; if ((*pp)->flags & is_valid) { if ((*pp)->cellerror) { - (void) fprintf (f, "%*s", fwidth[col], ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID")); + (void) fprintf (f, "%*s", sh->fwidth[col], ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID")); } else if ((*pp)->format) { char field[FBUFLEN]; if (*((*pp)->format) == 'd') { // Date format time_t v = (time_t) ((*pp)->v); strftime(field, sizeof(field), ((*pp)->format)+1, localtime(&v)); } else { // Numeric format - format((*pp)->format, precision[col], (*pp)->v, field, sizeof(field)); + format((*pp)->format, sh->precision[col], (*pp)->v, field, sizeof(field)); } ltrim(field, ' '); unspecial(f, field, coldelim); } else { //eng number format char field[FBUFLEN] = ""; - (void) engformat(realfmt[col], fwidth[col], precision[col], (*pp)->v, field, sizeof(field)); + (void) engformat(sh->realfmt[col], sh->fwidth[col], sh->precision[col], (*pp)->v, field, sizeof(field)); ltrim(field, ' '); unspecial(f, field, coldelim); } @@ -1877,12 +1946,11 @@ } } + /** * \brief Check what is the max length of all the lines in a file - * * \details Check the maximum length of lines in a file. Note: * FILE * f shall be opened. - * * \param[in] f file pointer * \return file length + 1 */ @@ -1905,12 +1973,11 @@ return max + 1; } + /** * \brief Check the number of lines of a file - * * \details Check the numbers of lines of a file. it count \n chars. * FILE * f shall be opened. - * * \param[in] f file pointer * \return number */ @@ -1926,13 +1993,12 @@ return count; } + /** - * \brief TODO Document plugin_exists() - * + * \brief plugin_exists() * \param[in] name * \param[in] len * \param[in] path - * * \return none */ int plugin_exists(char * name, int len, char * path) { @@ -1983,15 +2049,18 @@ return 0; } + /** * \brief TODO Document do_autobackup() * \return none */ void * do_autobackup() { - int len = strlen(curfile); - //if (loading || ! len) return (void *) -1; - //if (! len || ! modflg) return (void *) -1; - if (! len) return (void *) -1; + struct sheet * sh = session->cur_doc->cur_sh; + char * curfile = session->cur_doc->name; + int len; + if (curfile == NULL || ! (len = strlen(curfile))) return (void *) -1; + //if (session->cur_doc->loading || ! len) return (void *) -1; + //if (! len || ! session->cur_doc->modflg) return (void *) -1; char * pstr = strrchr(curfile, '/'); int pos = pstr == NULL ? -1 : pstr - curfile; @@ -2007,17 +2076,17 @@ if (! strcmp(&name[strlen(name)-7], ".sc.bak")) { register FILE * f; if ((f = fopen(namenew , "w")) == NULL) return (void *) -1; - write_fd(f, 0, 0, maxrow, maxcol); + write_fd(f, session->cur_doc); fclose(f); } else if (! strcmp(&name[strlen(name)-8], ".csv.bak")) { - export_delim(namenew, get_delim("csv"), 1, 0, maxrow, maxcol, 0); + export_delim(namenew, get_delim("csv"), 1, 0, sh->maxrow, sh->maxcol, 0); #ifdef XLSX_EXPORT } else if (! strcmp(&name[strlen(name)-9], ".xlsx.bak")) { - export_delim(namenew, ',', 0, 0, maxrow, maxcol, 0); - export_xlsx(namenew, 0, 0, maxrow, maxcol); + export_delim(namenew, ',', 0, 0, sh->maxrow, sh->maxcol, 0); + export_xlsx(namenew); #endif } else if (! strcmp(&name[strlen(name)-8], ".tab.bak") || ! strcmp(&name[strlen(name)-8], ".tsv.bak")) { - export_delim(namenew, '\t', 0, 0, maxrow, maxcol, 0); + export_delim(namenew, '\t', 0, 0, sh->maxrow, sh->maxcol, 0); } // delete if exists name @@ -2029,6 +2098,7 @@ return (void *) 0; } + /** * \brief Check if it is time to do an autobackup * \return none @@ -2052,6 +2122,7 @@ return; } + /** * \brief Remove autobackup file * \details Remove autobackup file. Used when quitting or when loading @@ -2072,6 +2143,7 @@ return; } + /** * \brief TODO Document backup_exists() * \param[in] file file pointer @@ -2094,6 +2166,7 @@ return 0; } + /** * \brief open file nested * \param[in] file name string @@ -2102,23 +2175,169 @@ void openfile_nested(char * file) { char * cmd = get_conf_value("default_open_file_under_cursor_cmd"); if (cmd == NULL || ! strlen(cmd)) return; - char syscmd[PATHLEN + strlen(cmd)]; - sprintf(syscmd, "%s", cmd); - sprintf(syscmd + strlen(syscmd), " %s", file); - system(syscmd); + pid_t pid = fork(); + if (pid == 0) { + execlp(cmd, cmd, file, NULL); + exit(EXIT_FAILURE); + } else if (pid > 0) { + waitpid(pid, NULL, 0); + } } + /** * \brief open file under cursor * \param[in] current row and column * \return none */ void openfile_under_cursor(int r, int c) { + struct roman * roman = session->cur_doc; register struct ent ** pp; - pp = ATBL(tbl, r, c); + pp = ATBL(roman->cur_sh, roman->cur_sh->tbl, r, c); if (*pp && (*pp)->label) { char text[FBUFLEN] = ""; strcpy(text, (*pp)->label); openfile_nested(text); } } + + +/* + * function that takes argv arguments and create a new + * roman struct for each file and attach it to main session + * DISABLED BY DESIGN +void readfile_argv(int argc, char ** argv) { + for (int i = 1; i < argc; i++) { + if (strncmp(argv[i], "--", 2) ) { // a file was passed as argv. try to handle it + printf("%s\n", argv[i]); + + struct roman * roman = calloc(1, sizeof(struct roman)); + roman->name = argv[i]; + roman->first_sh = NULL; + roman->cur_sh = NULL; + + // save roman inside session + INSERT(roman, (session->first_doc), (session->last_doc), next, prev); + session->cur_doc = roman; // important: set cur_doc! + + // malloc a sheet + roman->cur_sh = roman->first_sh = new_sheet(roman, "Sheet1"); + + // grow sheet tbl + growtbl(roman->first_sh, GROWNEW, 0, 0); + + load_sc(argv[i]); + } + } + return; +} +*/ + + +/* + * \brief load a file into a roman struct + * the file may contain multiple sheets + * \return none + */ +void load_file(char * file) { + if (file == NULL || file[0] == '\0') return; + struct roman * roman = calloc(1, sizeof(struct roman)); + roman->name = ! strlen(file) ? NULL : strdup(file); + roman->first_sh = NULL; + roman->cur_sh = NULL; + + // save roman inside session + INSERT(roman, (session->first_doc), (session->last_doc), next, prev); + session->cur_doc = roman; // important: set cur_doc! + + // malloc a clean sheet + // to make old sc file loading backwards compatible, mark it as is_allocated + roman->cur_sh = roman->first_sh = new_sheet(roman, "Sheet1"); + roman->cur_sh->flags |= is_allocated; + + // grow sheet tbl + growtbl(roman->first_sh, GROWNEW, 0, 0); + + // load_tbl may open an sc file or a new sc-im file that can handle sheets. + // new_sheet() would reuse Sheet1 if loading sc-im file. + load_tbl(file); + + // now mark 'Sheet1' as empty, removing is_allocated mark. + roman->first_sh->flags &= ~is_allocated; + roman->first_sh->flags |= is_empty; + return; +} + + +/** + * \brief Attempt to load a tbl into a sheet + * \return none + */ +void load_tbl(char * loading_file) { + char name[PATHLEN]; + strcpy(name, ""); //force name to be empty + #ifdef NO_WORDEXP + size_t len; + #else + int c; + wordexp_t p; + #endif + + #ifdef NO_WORDEXP + if ((len = strlen(loading_file)) >= sizeof(name)) { + sc_info("File path too long: '%s'", loading_file); + return; + } + memcpy(name, loading_file, len+1); + #else + wordexp(loading_file, &p, 0); + for (c=0; c < p.we_wordc; c++) { + if (c) sprintf(name + strlen(name), " "); + sprintf(name + strlen(name), "%s", p.we_wordv[c]); + } + wordfree(&p); + #endif + + if (strlen(name) != 0) { + sc_readfile_result result = readfile(name, 0); + if (! get_conf_int("nocurses")) { + if (result == SC_READFILE_DOESNTEXIST) { + // It's a new record! + sc_info("New file: \"%s\"", name); + } else if (result == SC_READFILE_ERROR) { + sc_info("\"%s\" is not a sc-im compatible file", name); + } + } + } +} + + +/** + * \brief create an empty workbook and attach it to session + * \return [int] -> return -1 (and quit app) if cannot alloc - return 0 on success + */ +int create_empty_wb() { + struct roman * roman = calloc(1, sizeof(struct roman)); + roman->name = NULL; + roman->first_sh = NULL; + roman->cur_sh = NULL; + + // save roman inside session + INSERT(roman, (session->first_doc), (session->last_doc), next, prev); + session->cur_doc = roman; // important: set cur_doc! + + // malloc a sheet + roman->cur_sh = roman->first_sh = new_sheet(roman, "Sheet1"); + + // grow sheet tbl + if (! growtbl(roman->first_sh, GROWNEW, 0, 0)) { + exit_app(-1); + return -1; + } + + erasedb(roman->first_sh, 0); + + // mark 'Sheet1' as empty, removing is_allocated mark. + roman->first_sh->flags |= is_empty; + return 0; +} diff -Nru sc-im-0.8.2+ds/src/file.h sc-im-0.8.3+ds/src/file.h --- sc-im-0.8.2+ds/src/file.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/file.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -41,18 +41,9 @@ * \date 2017-07-18 * \brief Header file for file.c */ +#include "sc.h" -#include "freeze.h" - -void erasedb(); -void loadrc(void); int modcheck(); -int savefile(); -int writefile(char *fname, int r0, int c0, int rn, int cn, int verbose); -void write_fd(register FILE *f, int r0, int c0, int rn, int cn); -void write_cells(register FILE *f, int r0, int c0, int rn, int cn, int dr, int dc); -void write_marks(register FILE *f); -void write_franges(register FILE *f); typedef enum { SC_READFILE_ERROR = 0, @@ -64,11 +55,8 @@ int file_exists(const char * fname); char * findhome(char *path); int backup_file(char *path); -FILE * openfile(char *fname, int *rpid, int *rfd); void closefile(FILE *f, int pid, int rfd); void print_options(FILE *f); -int import_csv(char * fname, char d); -int import_markdown(char * fname); void do_export(int r0, int c0, int rn, int cn); void export_delim(char * fname, char coldelim, int r0, int c0, int rn, int cn, int verbose); void export_plain(char * fname, int r0, int c0, int rn, int cn); @@ -84,3 +72,23 @@ int backup_exists(char * file); void openfile_nested(char * file); void openfile_under_cursor(int r, int c); + +// load functions +void load_file(char * loading_file); +void load_tbl(char * loading_file); +void erasedb(struct sheet * sheet, int _free); +void load_rc(void); +FILE * openfile(char *fname, int *rpid, int *rfd); +int import_csv(char * fname, char d); +int next_unquot_delim(char *start, char d); +int import_markdown(char * fname); +int create_empty_wb(); +//void readfile_argv(int argc, char ** argv); + +// save functions +int savefile(); +int writefile(char * fname, int verbose); +void write_fd(FILE * f, struct roman * roman); +void write_cells(FILE * f, struct roman * doc, struct sheet * sh, int r0, int c0, int rn, int cn, int dr, int dc); +void write_marks(FILE *f); +void write_franges(FILE *f); diff -Nru sc-im-0.8.2+ds/src/filter.c sc-im-0.8.3+ds/src/filter.c --- sc-im-0.8.2+ds/src/filter.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/filter.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,265 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file filter.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include // for isalpha toupper -#include - -#include "macros.h" -#include "tui.h" -#include "conf.h" -#include "xmalloc.h" -#include "filter.h" -#include "math.h" -#include "utils/string.h" -#include "sc.h" -#include "cmds.h" - -static int howmany = 0; /**< how many filters were definedi */ -static int active = 0; /**< indicates if those filters are applied or not */ -static int * results = NULL; /**< this keeps the results of the applied filters */ -static struct filter_item * filters = NULL; - -/** - * \brief Add a filter to filters structure - * - * \param[in] criteria - * - * \return none - */ - -void add_filter(char * criteria) { - int cp = 0; - char c; - - while (criteria[cp]) { - int pos = exists_freed_filter(); // we check if there exists a freed filter - if (pos == -1) { // if not we alloc a new one - filters = (struct filter_item *) scxrealloc((char *) filters, (howmany++ + 1) * (sizeof(struct filter_item))); - pos = howmany-1; - } - - filters[pos].eval = (char *) scxmalloc(sizeof(char) * strlen(criteria) + 1); - filters[pos].eval[0] = '\0'; - - while (criteria[cp] && criteria[cp] != ';' && criteria[cp] != '\n') { - c = criteria[cp]; - if (c == '"') { cp++; continue; } - if (criteria[cp++] == '\'') c ='"'; - sprintf(filters[pos].eval + strlen(filters[pos].eval), "%c", c); - } - - if (criteria[cp] == ';') cp++; - } - return; -} - -/** - * \brief Apply filters to a range - * - * \param[in] left - * \param[in] right - * - * \return none - */ - -void enable_filters(struct ent * left, struct ent * right) { - int minr = left->row < right->row ? left->row : right->row; - int maxr = left->row > right->row ? left->row : right->row; - int i, r, c = 0; - wchar_t cadena [BUFFERSIZE] = L""; - wchar_t aux [BUFFERSIZE] = L""; - results = (int *) scxrealloc((char *) results, (maxr - minr + 3) * sizeof(int)); - results[0] = minr; // keep in first position the first row of the range! - results[1] = maxr; // keep in second position the last row of the range! - if (filters == NULL) { - sc_error("There are no filters defined"); - return; - } - active = 1; - - for (r = minr; r <= maxr; r++) { - results[r-minr+2] = 0; // show row by default (0 = NOT HIDDEN) - for (i = 0; i < howmany; i++, c=0) { - cadena[0]=L'\0'; - if (filters[i].eval == NULL) continue; - while (filters[i].eval[c] != '\0') { - - if (filters[i].eval[c] == '#' || filters[i].eval[c] == '$') { - if (isalpha(toupper(filters[i].eval[++c]))) - swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%c", filters[i].eval[c]); - if (isalpha(toupper(filters[i].eval[++c]))) - swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%c", filters[i].eval[c]); - swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%d", r); - continue; - } else - swprintf(cadena + wcslen(cadena), BUFFERSIZE, L"%c", filters[i].eval[c]); - c++; - } - - swprintf(aux, BUFFERSIZE, L"eval %ls", cadena); - send_to_interp(aux); - if ( (! seval_result && str_in_str(filters[i].eval, "seval") != -1) || ! eval_result) { - results[r-minr+2] = 1; // this row does not eval to expression. we hide it. (1 = HIDDEN)! - i = howmany; - } - if (seval_result != NULL) free(seval_result); - } - } - - // Hide rows that don't match with filters - for (r = results[0]; r <= results[1]; r++) { - row_hidden[r] = results[r-results[0]+2]; - } - sc_info("Filters enabled"); - return; -} - -/** - * \brief Disable any applied filters - * - * \return none - */ - -void disable_filters() { - if (results == NULL) { - sc_error("There are no filters active"); - return; - } - // Hide rows that don't match with filters - int r; - for (r=results[0]; r<=results[1]; r++) { - row_hidden[r] = 0; - } - active = 0; - sc_info("Filters disabled"); - return; -} - -// Show details of each filter -/** - * \brief Show details of each filter - * - * \return none - */ - -void show_filters() { - if (filters == NULL) { - sc_error("There are no filters defined"); - return; - } - - int i, size = 0; - char init_msg[BUFFERSIZE]; - sprintf(init_msg, "Filters status: %s\nFilters:\n", active == 1 ? "ON" : "OFF"); - - size += sizeof(init_msg); - for (i=0; i < howmany; i++) - size += sizeof(filters[i].eval) + 4 + floor(log10(howmany)); - - char valores[ size + howmany ]; - valores[0]='\0'; - - strcpy(valores, init_msg); - for (i=0; i < howmany; i++) - if (filters[i].eval != NULL) sprintf(valores + strlen(valores), "%d + %s\n", i, filters[i].eval); - - ui_show_text(valores); - return; -} - -/** - * \brief Free memory of entire filters structure - * - * \return int: -1 not removed - 0 removed - */ - -int free_filters() { - if (filters == NULL) return -1; - int i; - for (i=0; i < howmany; i++) - if (filters[i].eval != NULL) scxfree((char *) filters[i].eval); - scxfree((char *) filters); - filters = NULL; - return 0; -} - -/** - * \brief Remove a filter, freeing its memory - * - * \param[in] id - * - * \return int: -1 not removed - 0 removed - */ - -int del_filter(int id) { - if (filters == NULL || id < 0 || id > howmany) { - sc_error("Cannot delete the filter"); - return -1; - } - if (filters[id].eval != NULL) { - scxfree((char *) filters[id].eval); - filters[id].eval = NULL; - } - return 0; -} - -/** - * \brief Check if a filter was deleted - * - * \details This function checks if a filter was deleted, so there would - * be room in filters structure for a new filter and preventing - * an unnecessary realloc. - * - * \return how many filters exist; -1 otherwise - */ - -int exists_freed_filter() { - if (filters == NULL) return -1; - int i; - for (i=0; i < howmany; i++) - if (filters[i].eval == NULL) return i; - return -1; -} diff -Nru sc-im-0.8.2+ds/src/filter.h sc-im-0.8.3+ds/src/filter.h --- sc-im-0.8.2+ds/src/filter.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/filter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file filter.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for filter.c - */ - -struct filter_item { - char * eval; -}; - -void show_filters(); -void add_filter(char * criteria); -void enable_filters(struct ent * left, struct ent * right); -void disable_filters(); -int free_filters(); -int del_filter(int id); -int exists_freed_filter(); diff -Nru sc-im-0.8.2+ds/src/format.c sc-im-0.8.3+ds/src/format.c --- sc-im-0.8.2+ds/src/format.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/format.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -38,8 +38,7 @@ /** * \file format.c * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. + * \date 2021-05-22 */ /* @@ -55,7 +54,7 @@ * The format function will produce a string representation of a number * given a _format_ (described below) and a double value. The result is * written into the passed buffer -- if the resulting string is too - * long to fit into the passed buffer, the function returns false. + * long to fit into the passed buffer, the function returns FALSE. * Otherwise the function returns true. * * The fmt parameter contains the format to use to convert the number. @@ -125,24 +124,23 @@ * into the formatted number with no change made to the actual * number. */ - #include #include #include #include #include "sc.h" +#include "xmalloc.h" -#define true 1 -#define false 0 #define EOS '\0' #define MAXBUF 256 -static char *fmt_int(char *val, char *fmt, int comma, int negative); -static char *fmt_frac(char *val, char *fmt, int lprecision); -static char *fmt_exp(int val, char *fmt); -static void reverse(register char *buf); +static char * fmt_int(char * val, char * fmt, int comma, int negative); +static char * fmt_frac(char * val, char * fmt, int lprecision); +static char * fmt_exp(int val, char * fmt); +static void reverse(char * buf); char * colformat[COLFORMATS]; + /** * \brief TODO Document format() * @@ -154,11 +152,10 @@ * * returns: ret */ - int format(char *fmt, int lprecision, double val, char *buf, int buflen) { register char *cp; char *tmp, *tp; - int comma = false, negative = false; + int comma = FALSE, negative = FALSE; char *integer = NULL, *decimal = NULL; char *exponent = NULL; int exp_val = 0; @@ -171,7 +168,7 @@ int zero_pad = 0; if (fmt == NULL) - return(true); + return(TRUE); if (strlen(fmt) + 1 > fmtlen) { fmtlen = strlen(fmt) + 40; @@ -213,7 +210,7 @@ break; case ',': - comma = true; + comma = TRUE; break; case '.': @@ -242,7 +239,7 @@ */ val = (val + 1.0) - 1.0; if (val < 0.0) { - negative = true; + negative = TRUE; val = -val; } /* @@ -327,7 +324,7 @@ static unsigned cilen = 0, cflen = 0; char * ci, * cf, * ce; int len_ci, len_cf, len_ce; - int ret = false; + int ret = FALSE; ci = fmt_int(integer, fmt, comma, negative); len_ci = strlen(ci); @@ -354,7 +351,7 @@ */ if (len_ci + len_cf + len_ce < buflen) { (void) sprintf(buf, "%s%s%s", ci, cf, ce); - ret = true; + ret = TRUE; } return (ret); @@ -366,11 +363,10 @@ * * \param[in] val integer part of the value to be formatted * \param[in] fmt integer part of the format - * \param[in] comma true if we should comma-ify the value - * \param[in] negative true if the value is actually negative + * \param[in] comma TRUE if we should comma-ify the value + * \param[in] negative TRUE if the value is actually negative * \return none */ - static char * fmt_int(char *val, char *fmt, int comma, int negative) { int digit, f, v; @@ -423,16 +419,16 @@ return (buf); } + /** * \brief TODO Document fmt_frac() * * \param[in] val fractional part of the value to be formatted * \param[in] fmt fractional portion of format * \param[in] precision, for interpreting the "&" - * + * * \return none */ - static char * fmt_frac(char *val, char *fmt, int lprecision) { static char buf[MAXBUF]; @@ -462,20 +458,20 @@ return (buf); } + /** * \brief TODO Document fmt_exp * * \param[in] val value of the exponent * \param[in] fmt exponent part of the format - * + * * \return none */ - static char * fmt_exp(int val, char *fmt) { static char buf[MAXBUF]; register char *bufptr = buf; char valbuf[64]; - int negative = false; + int negative = FALSE; *bufptr++ = *fmt++; if (*fmt == '+') @@ -487,14 +483,15 @@ if (val < 0) { val = -val; - negative = false; + negative = FALSE; } (void) sprintf(valbuf, "%d", val); - (void) strcat(buf, fmt_int(valbuf, fmt, false, negative)); + (void) strcat(buf, fmt_int(valbuf, fmt, FALSE, negative)); return (buf); } + /** * \brief TODO Document reverse() * @@ -502,7 +499,6 @@ * * \return none */ - static void reverse(register char *buf) { register char *cp = buf + strlen(buf) - 1; register char tmp; @@ -514,6 +510,7 @@ } } + /* * Tom Anderson * 10/14/90 @@ -531,7 +528,7 @@ * * This formatted value is written into the passed buffer. if the * resulting string is too long to fit into the passed buffer, the - * function returns false. Otherwise the function returns true. + * function returns FALSE. Otherwise the function returns TRUE. * * When a number is formatted as engineering and is outside of the range, * the format reverts to scientific. @@ -552,7 +549,7 @@ #endif /** - * \brief TODO Document engformat() + * \brief engformat() * * \param[in] fmt * \param[in] width @@ -563,7 +560,6 @@ * * \return none */ - int engformat(int fmt, int width, int lprecision, double val, char *buf, int buflen) { static char * engmult[] = { @@ -574,16 +570,16 @@ int engind = 0; double engmant, pow(), engabs, engexp; - if (buflen < width) return (false); + if (buflen < width) return (FALSE); if (fmt >= 0 && fmt < COLFORMATS && colformat[fmt]) return (format(colformat[fmt], lprecision, val, buf, buflen)); if (fmt == REFMTFIX) - (void) sprintf(buf,"%*.*f", width, lprecision, val); + (void) snprintf(buf, buflen, "%*.*f", width, lprecision, val); if (fmt == REFMTFLT) - (void) sprintf(buf,"%*.*e", width, lprecision, val); + (void) snprintf(buf, buflen, "%*.*e", width, lprecision, val); if (fmt == REFMTENG) { if (val == 0e0) { /* Hack to get zeroes to line up in engr fmt */ - (void) sprintf((buf-1),"%*.*f ", width, lprecision, val); + (void) snprintf(buf-1, buflen, "%*.*f ", width, lprecision, val); } else { engabs = (val); if ( engabs < 0e0) engabs = -engabs; @@ -602,11 +598,11 @@ if ((engabs >= 1e18) && (engabs < 1e21 )) engind=12; if ((engabs < 1e-18) || (engabs >= 1e21 )) { /* Revert to floating point */ - (void) sprintf(buf,"%*.*e", width, lprecision, val); + (void) snprintf(buf, buflen, "%*.*e", width, lprecision, val); } else { engexp = (double) (engind-6)*3; - engmant = val/pow(10.0e0,engexp); - (void) sprintf(buf,"%*.*fe%s", width-4, lprecision, engmant, engmult[engind]); + engmant = val/pow(10.0e0, engexp); + (void) snprintf(buf, buflen, "%*.*fe%s", width-4, lprecision, engmant, engmult[engind]); } } } @@ -619,7 +615,7 @@ buf[i] = '\0'; } else { secs = (time_t)val; - strftime(buf,buflen,"%e %b %y",localtime(&secs)); + strftime(buf, buflen, "%e %b %y", localtime(&secs)); for (i = 9; i < width; i++) buf[i] = ' '; buf[i] = '\0'; } @@ -633,10 +629,24 @@ buf[i] = '\0'; } else { secs = (time_t)val; - strftime(buf,buflen,"%e %b %Y",localtime(&secs)); + strftime(buf, buflen, "%e %b %Y", localtime(&secs)); for (i = 11; i < width; i++) buf[i] = ' '; buf[i] = '\0'; } } - return (true); + return (TRUE); +} + +/** + * \brief free_formats() + * \return none + */ +void free_formats() { + int c; + for (c = 0; c < COLFORMATS; c++) { + if (colformat[c] != NULL) + scxfree(colformat[c]); + colformat[c] = NULL; + } + return; } diff -Nru sc-im-0.8.2+ds/src/format.h sc-im-0.8.3+ds/src/format.h --- sc-im-0.8.2+ds/src/format.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/format.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -44,3 +44,4 @@ int format(char *fmt, int lprecision, double val, char *buf, int buflen); int engformat(int fmt, int width, int lprecision, double val, char *buf, int buflen); +void free_formats(); diff -Nru sc-im-0.8.2+ds/src/formats/ods.c sc-im-0.8.3+ds/src/formats/ods.c --- sc-im-0.8.2+ds/src/formats/ods.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/ods.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file xlsx.c + * \author Andrés Martinelli + * \date 2021-03-27 + * \brief file that contains the functions to support ods file import + * + * \details ods import requires: + * - libzip-dev + * - libxml2-dev + */ + +#ifdef ODS +#include +#include +#include + +#include "../tui.h" +#include "../cmds/cmds.h" +#include "../sc.h" +#include "../utils/string.h" +#endif + +extern struct session * session; + +/** + * \brief open_ods() files + * + * \param[in] fname + * \param[in] encoding + * + * \return none + */ + +int open_ods(char * fname, char * encoding) { +#ifdef ODS + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + struct zip * za; + struct zip_file * zf; + struct zip_stat sb_content; + + char buf[100]; + int err; + int len; + + // open zip file + if ((za = zip_open(fname, 0, &err)) == NULL) { + zip_error_to_str(buf, sizeof(buf), err, errno); + sc_error("can't open zip archive `%s': %s", fname, buf); + return -1; + } + + // open content.xml + char * name = "content.xml"; + zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); + char * content = NULL; + if (zf) { + // some files may not have strings + zip_stat(za, name, ZIP_FL_UNCHANGED, &sb_content); + content = (char *) malloc(sb_content.size); + len = zip_fread(zf, content, sb_content.size); + if (len < 0) { + sc_error("cannot read file %s.\n", name); + free(content); + return -1; + } + zip_fclose(zf); + } + + // XML parse for the sheet file + xmlDoc * doc = NULL; + + // this initialize the library and check potential ABI mismatches + // between the version it was compiled for and the actual shared + // library used. + LIBXML_TEST_VERSION + + + doc = xmlReadMemory(content, sb_content.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); + + if (doc == NULL) { + sc_error("error: could not parse ods file"); + if (content != NULL) free(content); + return -1; + } + + // parse here + xmlNode * cur_node = xmlDocGetRootElement(doc)->xmlChildrenNode; + xmlNode * child_node = NULL; + wchar_t line_interp[FBUFLEN] = L""; + int r=0, c=-1; + while (cur_node != NULL && strcmp((char *) cur_node->name, "body")) cur_node = cur_node->next; // forward until reach body + cur_node = cur_node->xmlChildrenNode; + while (cur_node != NULL && strcmp((char *) cur_node->name, "spreadsheet")) cur_node = cur_node->next; // forward until reach spreadsheet + cur_node = cur_node->xmlChildrenNode; + while (cur_node != NULL && strcmp((char *) cur_node->name, "table")) cur_node = cur_node->next; // forward until reach table + cur_node = cur_node->xmlChildrenNode; + + char * strvalue = NULL; + char * st = NULL; + char * strtype = NULL; + char * value = NULL; + char * strf; + char * value_type = NULL; + + // here traverse table content + while (cur_node != NULL) { + if (! strcmp((char *) cur_node->name, "table-row")) { + // we are inside a table-row + // each of these is a row + child_node = cur_node->xmlChildrenNode; + r++; + c=-1; + + while (child_node != NULL) { + c++; + if ((value_type = (char *) xmlGetProp(child_node, (xmlChar *) "value-type")) == NULL) { child_node = child_node->next; continue; }; + // each of these is table-cell (a column) + + strtype = value_type; // type + + //if (!strcmp(strtype, "time") //get time-value + //TODO + //if (!strcmp(strtype, "date") //get date-value + //TODO + if (!strcmp(strtype, "float")) { + char * formula = (char *) xmlGetProp(child_node, (xmlChar *) "formula"); + if (formula != NULL) { + strf = str_replace (formula, "of:=",""); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "[.",""); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, ";",","); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, ":.",":"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "]",""); + strcpy(formula, strf); + free(strf); + // we take some common function and adds a @ to them + strf = str_replace (formula, "COUNT","@COUNT"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "SUM","@SUM"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "PRODUCT","@PROD"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "AVERAGE","@AVG"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "MIN","@MIN"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "MAX","@MAX"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "ABS","@ABS"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "STDEV","@STDDEV"); + strcpy(formula, strf); + free(strf); + swprintf(line_interp, FBUFLEN, L"let %s%d=%s", coltoa(c), r, formula); + xmlFree(formula); + formula = NULL; + } else { + value = (char *) xmlGetProp(child_node, (xmlChar *) "value"); // type + double l = atof((char *) value); + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, l); + xmlFree(value); + value = NULL; + } + send_to_interp(line_interp); + } else if (!strcmp(strtype, "string") && !strcmp((char *) child_node->xmlChildrenNode->name, "p")) { + strvalue = (char *) xmlNodeGetContent(child_node->xmlChildrenNode); + st = str_replace (strvalue, "\"", "''"); + clean_carrier(st); // we handle padding + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, st); + send_to_interp(line_interp); + free(st); + xmlFree(strvalue); + strvalue = NULL; + } + child_node = child_node->next; + + xmlFree(value_type); + value_type = NULL; + } + } + cur_node = cur_node->next; // forward until reach table + } + int_deleterow(sh, sh->currow, 1); /* delete the first row */ + + // free the document + xmlFreeDoc(doc); + + // Free the global variables that may have been allocated by the parser + xmlCleanupParser(); + + free(content); + + // close zip file + if (zip_close(za) == -1) { + sc_error("cannot close zip archive `%s'", fname); + return -1; + } +#endif + return 0; +} diff -Nru sc-im-0.8.2+ds/src/formats/ods.h sc-im-0.8.3+ds/src/formats/ods.h --- sc-im-0.8.2+ds/src/formats/ods.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/ods.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ +/** + * \file ods.h + * \author Andrés Martinelli + * \date 2021-03-27 + * \brief Header file for ods.c + */ + +int open_ods(char * fname, char * encoding); diff -Nru sc-im-0.8.2+ds/src/formats/tags sc-im-0.8.3+ds/src/formats/tags --- sc-im-0.8.2+ds/src/formats/tags 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/tags 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,19 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ +!_TAG_OUTPUT_FILESEP slash /slash or backslash/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/ +!_TAG_PROC_CWD /home/mongo/scim/src/formats/ // +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 5.9.0 /2b88b80ac/ +export_xlsx xlsx.c /^int export_xlsx(char * filename) {$/;" f typeref:typename:int +get_sheet_data xlsx.c /^void get_sheet_data(xmlDocPtr doc, xmlDocPtr doc_strings, xmlDocPtr doc_styles) {$/;" f typeref:typename:void +get_xlsx_number_format_by_id xlsx.c /^char * get_xlsx_number_format_by_id(xmlDocPtr doc_styles, int id) {$/;" f typeref:typename:char * +get_xlsx_string xlsx.c /^char * get_xlsx_string(xmlDocPtr doc, int pos) {$/;" f typeref:typename:char * +get_xlsx_styles xlsx.c /^char * get_xlsx_styles(xmlDocPtr doc_styles, int pos) {$/;" f typeref:typename:char * +open_ods ods.c /^int open_ods(char * fname, char * encoding) {$/;" f typeref:typename:int +open_xls xls.c /^int open_xls(char * fname, char * encoding) {$/;" f typeref:typename:int +open_xlsx xlsx.c /^int open_xlsx(char * fname, char * encoding) {$/;" f typeref:typename:int diff -Nru sc-im-0.8.2+ds/src/formats/xls.c sc-im-0.8.3+ds/src/formats/xls.c --- sc-im-0.8.2+ds/src/formats/xls.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/xls.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file TODO + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + */ + +#include +#include +#include +#include + +#include "xls.h" +#include "../sc.h" +#include "../cmds/cmds.h" +#include "../color.h" +#include "../macros.h" +#include "../utils/string.h" + +/* + * xls.h is part of libxls. make sure its installed and headers are in path. + * build must be done with '-lxlsreader' + */ +#ifdef XLS +#include +#endif + +extern struct session * session; + +/** + * \brief TODO + * + * \details This function loads an excel file into tbl. As sc-im still + * does not handle multiple sheets, if excel file has multiple sheets, + * only the first one is read. + * + * \return -1 on error + */ +int open_xls(char * fname, char * encoding) { +#ifdef XLS + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + + // Set date format reading LOCALE + char fmt[15] = "%d/%m/%Y"; + + #ifdef USELOCALE + #include + #include + char * loc = NULL; + char * f = NULL; + loc = setlocale(LC_TIME, ""); + + if (loc != NULL) { + f = nl_langinfo(D_FMT); + strcpy(fmt, f); + } + #endif + + // Read XLS file + xlsWorkBook * pWB; + xlsWorkSheet * pWS; + WORD r, c; + pWB = xls_open(fname, encoding); + + wchar_t line_interp[FBUFLEN] = L""; + struct ent * n; + + if (pWB == NULL) { + sc_error("Error loading %s", fname); + return -1; + } + + pWS = xls_getWorkSheet(pWB, 0); //only the first sheet + if (pWS == NULL) return -1; + xls_parseWorkSheet(pWS); + + for (r = 0; r <= pWS->rows.lastrow; r++) { // rows + for (c = 0; c <= pWS->rows.lastcol; c++) { // cols + xlsCell * cell = xls_cell(pWS, r, c); + if ((! cell) || (cell->isHidden)) continue; + + // TODO enable rowspan ? + //if (cell->rowspan > 1) continue; + + struct st_xf_data * xf = &pWB->xfs.xf[cell->xf]; + + //sc_debug("%d %d fmt:%d id:%x %d %d", r, c, xf->format, cell->id, cell->d, cell->l); + + // these are dates + if (((xf->format >= 14 && xf->format <= 22) || + (xf->format >= 165 && xf->format <= 180) || + xf->format == 278 || xf->format == 185 || xf->format == 196 || xf->format + == 217 || xf->format == 326 ) + && cell->id != 0x06 + //&& cell->id != 0x27e + && cell->id != 0x0BD + && cell->id != 0x203 ) { + + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15g", coltoa(c), r, (cell->d - 25569) * 86400); + send_to_interp(line_interp); + n = lookat(sh, r, c); + n->format = 0; + char * s = scxmalloc((unsigned)(strlen(fmt) + 2)); + sprintf(s, "%c", 'd'); + strcat(s, "%d/%m/%Y"); + n->format = s; + continue; + + // display the value of the cell (either numeric or string) + } else if (cell->id == 0x27e || cell->id == 0x0BD || cell->id == 0x203) { + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15g", coltoa(c), r, cell->d); + + } else if (cell->id == 0x06) { // formula + if (cell->l == 0) { // its a number + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15g", coltoa(c), r, cell->d); + } else { + if (!strcmp((char *) cell->str, "bool")) { // its boolean, and test cell->d + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, (int) cell->d ? "true" : "false"); + } else if (! strcmp((char *) cell->str, "error")) { // formula is in error + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, "error"); //FIXME + } else { + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, (char *) cell->str); + } + } + + } else if (cell->str != NULL) { + int pad_pos; + if ((pad_pos = str_in_str((char *) cell->str, "\n")) != -1) ((char *) cell->str)[pad_pos] = '\0'; // For spanning + // clean_carrier((char *) cell->str); // For spanning + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, (char *) cell->str); + } else { + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, ""); + } + send_to_interp(line_interp); + } + } + xls_close_WS(pWS); + xls_close_WB(pWB); + auto_fit(sh, 0, sh->maxcols, DEFWIDTH); + return 0; +#else + return -1; +#endif +} diff -Nru sc-im-0.8.2+ds/src/formats/xls.h sc-im-0.8.3+ds/src/formats/xls.h --- sc-im-0.8.2+ds/src/formats/xls.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/xls.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ +/** + * \file xls.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for xls.c + */ + +int open_xls(char * fname, char * encoding); diff -Nru sc-im-0.8.2+ds/src/formats/xlsx.c sc-im-0.8.3+ds/src/formats/xlsx.c --- sc-im-0.8.2+ds/src/formats/xlsx.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/xlsx.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,756 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file xlsx.c + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief TODO Write a tbrief file description. + * + * \details xlsx import requires: + * - libzip-dev + * - libxml2-dev + * + * \details xlsx export requires + * - libxlsxwriter + */ + +#include +#include +#include +#include // for isdigit +#include // for atoi + +#include "../macros.h" +#include "../sc.h" +#include "../cmds/cmds.h" +#include "../tui.h" +#include "../conf.h" +#include "../lex.h" +#include "../interp.h" +#include "../utils/string.h" + +#ifdef XLSX +#include +#include +#include +#include "xlsx.h" + +extern struct session * session; + +/** + * \brief TODO Document get_xlsx_string() + * + * \details This function takes the DOM of the sharedStrings file + * and based on position, it returns the according string. Note + * that 0 is the first string. + * + * \param[in] doc + * \param[in] pos + * + * \return none + */ + +char * get_xlsx_string(xmlDocPtr doc, int pos) { + xmlNode * cur_node = xmlDocGetRootElement(doc)->xmlChildrenNode; + xmlNode * father; + char * result = NULL; + + while (pos--) cur_node = cur_node->next; + + father = cur_node; + cur_node = father->xmlChildrenNode; + + while (father != NULL) { // traverse children + while (cur_node != NULL) { // traverse relatives + if ( ! xmlStrcmp(cur_node->name, (const xmlChar *) "t") + && cur_node->xmlChildrenNode != NULL + && cur_node->xmlChildrenNode->content != NULL + ) { + result = (char *) cur_node->xmlChildrenNode->content; + //sc_debug("%s %s", cur_node->name, result); + return result; + } + cur_node = cur_node->next; + } + + father = father->xmlChildrenNode; + if (father != NULL) cur_node = father->xmlChildrenNode; + } + + return result; +} + +/* + * this functions takes the DOM of the styles file + * and based on a position, it returns the according numFmtId + * IMPORTANT: note that 0 is the first "xf". + */ +/** + * \brief TODO Document get_xlsx_styles + * + * \details This function takes the DOM of the styles file + * and mased on position, it returns the according numFmtId. + * IMPORTANT: Note that 0 is the first "xf". + * + * \param[in] doc_styles + * \param[in] pos + * + * \return none + */ + +char * get_xlsx_styles(xmlDocPtr doc_styles, int pos) { + // we go forward up to styles data + xmlNode * cur_node = xmlDocGetRootElement(doc_styles)->xmlChildrenNode; + while (cur_node != NULL && !(cur_node->type == XML_ELEMENT_NODE && !strcmp((char *) cur_node->name, "cellXfs"))) + cur_node = cur_node->next; + + cur_node = cur_node->xmlChildrenNode; + // we go forward up to desidered numFmtId + while (pos--) cur_node = cur_node->next; + char * id = (char *) xmlGetProp(cur_node, (xmlChar *) "numFmtId"); + return id; +} + +/** + * \brief get_xlsx_number_format_by_id() + * \param[in] doc_styles + * \param[in] id + * \return none + */ +char * get_xlsx_number_format_by_id(xmlDocPtr doc_styles, int id) { + if (doc_styles == NULL) + return NULL; + + // we go forward up to numFmts section + xmlNode * cur_node = xmlDocGetRootElement(doc_styles)->xmlChildrenNode; + while (cur_node != NULL && !(cur_node->type == XML_ELEMENT_NODE && !strcmp((char *) cur_node->name, "numFmts"))) + cur_node = cur_node->next; + + cur_node = cur_node->xmlChildrenNode; + // we go forward up to desidered format + char * idFile = (char *) xmlGetProp(cur_node, (xmlChar *) "numFmtId"); + while (idFile && atoi(idFile) != id) { + cur_node = cur_node->next; + free(idFile); + idFile = (char *) xmlGetProp(cur_node, (xmlChar *) "numFmtId"); + } + + if (idFile && atoi(idFile) == id) { + free(idFile); + return (char *) xmlGetProp(cur_node, (xmlChar *) "formatCode"); + } else { + free(idFile); + return NULL; + } +} + +/** + * \brief TODO Document get_sheet_data() + * + * \details This function takes the sheetfile DOM and builds the tbl + * spreadsheet (sc-im format) + * + * \return none + */ + +void get_sheet_data(xmlDocPtr doc, xmlDocPtr doc_strings, xmlDocPtr doc_styles) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + xmlNode * cur_node = xmlDocGetRootElement(doc)->xmlChildrenNode; + xmlNode * child_node = NULL; + wchar_t line_interp[FBUFLEN] = L""; + int r, c; + + // we go forward up to sheet data + while (cur_node != NULL && !(cur_node->type == XML_ELEMENT_NODE && !strcmp((char *) cur_node->name, "sheetData"))) + cur_node = cur_node->next; + + cur_node = cur_node->xmlChildrenNode; // this is sheetdata + while (cur_node != NULL) { + child_node = cur_node->xmlChildrenNode; // these are rows + while (child_node != NULL) { // these are cols + + // We get r y c + char * row = (char *) xmlGetProp(cur_node, (xmlChar *) "r"); + r = atoi(row); + char * col = (char *) xmlGetProp(child_node, (xmlChar *) "r"); + while (isdigit(col[strlen(col)-1])) col[strlen(col)-1]='\0'; + c = atocol(col, strlen(col)); + + char * s = (char *) xmlGetProp(child_node, (xmlChar *) "t"); // type + char * style = NULL; + style = (char *) xmlGetProp(child_node, (xmlChar *) "s"); // style + char * fmtId = style == NULL ? NULL : get_xlsx_styles(doc_styles, atoi(style)); // numfmtId by style number + char * numberFmt = NULL; + char * shared = NULL; + int i_fmtid = -1; + if (fmtId != NULL) { + i_fmtid = atoi(fmtId); + if (i_fmtid != 0) numberFmt = get_xlsx_number_format_by_id(doc_styles, i_fmtid); + } + + // try to handle custom formats + if (i_fmtid == 278 || i_fmtid == 185 || + i_fmtid == 196 || i_fmtid == 217 || i_fmtid == 326 || + i_fmtid == 100 || (i_fmtid > 163 && i_fmtid < 181)) { + char * strFormatCode = NULL; + strFormatCode = get_xlsx_number_format_by_id(doc_styles, i_fmtid); + if (strFormatCode != NULL && ! strcmp(strFormatCode, "General")) i_fmtid = 0; + else if (strFormatCode != NULL && str_in_str(strFormatCode, "/") != -1) i_fmtid = 14; + } + + // string + if ( s != NULL && ! strcmp(s, "s") ) { + char * st = NULL; + char * strvalue = NULL; + if (child_node->xmlChildrenNode != NULL) + strvalue = get_xlsx_string(doc_strings, atoi((char *) child_node-> xmlChildrenNode-> xmlChildrenNode->content)); + if (strvalue != NULL && strvalue[0] != '\0') { + st = str_replace (strvalue, "\"", "''"); + clean_carrier(st); // we handle padding + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, st); + send_to_interp(line_interp); + free(st); + } + + // inlinestring + } else if ( s != NULL && ! strcmp(s, "inlineStr") ) { + char * st = NULL; + char * strvalue = (char *) child_node->xmlChildrenNode->xmlChildrenNode->xmlChildrenNode->content; + if (strvalue != NULL && strvalue[0] != '\0') { + st = str_replace (strvalue, "\"", "''"); + clean_carrier(st); // we handle padding + swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, st); + send_to_interp(line_interp); + free(st); + } + + // numbers (can be dates, results from formulas or simple numbers) + } else { + // date value in v + if (i_fmtid != -1 && child_node->xmlChildrenNode != NULL && + ! strcmp((char *) child_node->xmlChildrenNode->name, "v") && + (i_fmtid > 13 && i_fmtid < 18)) { + long l = strtol((char *) child_node->xmlChildrenNode->xmlChildrenNode->content, (char **) NULL, 10); + + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15ld", coltoa(c), r, (l - 25568) * 86400 - get_conf_int("tm_gmtoff")); + send_to_interp(line_interp); + struct ent * n = lookat(sh, r, c); + n->format = 0; + char * stringFormat = scxmalloc((unsigned)(strlen("%d/%m/%Y") + 2)); + sprintf(stringFormat, "%c", 'd'); + strcat(stringFormat, "%d/%m/%Y"); + n->format = stringFormat; + + // time value in v + } else if (i_fmtid != -1 && child_node->xmlChildrenNode != NULL && + ! strcmp((char *) child_node->xmlChildrenNode->name, "v") + && (i_fmtid > 17 && i_fmtid < 22) + ) { + double l = atof((char *) child_node->xmlChildrenNode->xmlChildrenNode->content); + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, (l - get_conf_int("tm_gmtoff") * 1.0 / 60 / 60 / 24) * 86400); + send_to_interp(line_interp); + struct ent * n = lookat(sh, r, c); + n->format = 0; + char * stringFormat = scxmalloc((unsigned)(strlen("%H:%M:%S") + 2)); + sprintf(stringFormat, "%c", 'd'); + strcat(stringFormat, "%H:%M:%S"); + n->format = stringFormat; + + // v - straight int value + } else if ( + child_node->xmlChildrenNode != NULL && + ! strcmp((char *) child_node->xmlChildrenNode->name, "v") ){ + double l = atof((char *) child_node->xmlChildrenNode->xmlChildrenNode->content); + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, l); + send_to_interp(line_interp); + + // f - numeric value that is a result from formula + } else if ( + child_node->xmlChildrenNode != NULL && ! strcmp((char *) child_node->xmlChildrenNode->name, "f")) { + + // handle the formula if that is whats desidered!! + if (get_conf_int("xlsx_readformulas") && + // dont handle shared formulas right now + ! (xmlHasProp(child_node->xmlChildrenNode, (xmlChar *) "t") && + ! strcmp((shared = (char *) xmlGetProp(child_node->xmlChildrenNode, (xmlChar *) "t")), "shared")) + ) { + char * formula = (char *) child_node->xmlChildrenNode->xmlChildrenNode->content; + char * strf; + uppercase(formula); + + // we take some excel common function and adds a @ to them + // we replace count sum avg with @count, @sum, @prod, @avg, @min, @max + strf = str_replace (formula, "COUNT","@COUNT"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "SUM","@SUM"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "PRODUCT","@PROD"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "AVERAGE","@AVG"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "MIN","@MIN"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "MAX","@MAX"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "ABS","@ABS"); + strcpy(formula, strf); + free(strf); + strf = str_replace (formula, "STDEV","@STDDEV"); + strcpy(formula, strf); + free(strf); + + // we send the formula to the interpreter and hope to resolve it! + swprintf(line_interp, FBUFLEN, L"let %s%d=%s", coltoa(c), r, formula); + + } else { + double l = atof((char *) child_node->last->xmlChildrenNode->content); + swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, l); + } + send_to_interp(line_interp); + } + } + + xmlFree(s); + xmlFree(fmtId); + xmlFree(style); + xmlFree(numberFmt); + xmlFree(shared); + + child_node = child_node->next; + xmlFree(col); + xmlFree(row); + } + cur_node = cur_node->next; + } + return; +} + +/** + * \brief TODO Document open_xlsx() + * + * \param[in] fname + * \param[in] encoding + * + * \return none + */ + +int open_xlsx(char * fname, char * encoding) { + //struct roman * roman = session->cur_doc; + //struct sheet * sh = roman->cur_sh; + struct zip * za; + struct zip_file * zf; + struct zip_stat sb_sheet, sb_strings, sb_styles, sh_strings; + char buf[100]; + int err; + int len; + + // open zip file + if ((za = zip_open(fname, 0, &err)) == NULL) { + zip_error_to_str(buf, sizeof(buf), err, errno); + sc_error("can't open zip archive `%s': %s", fname, buf); + return -1; + } + + // open xl/sharedStrings.xml + char * name = "xl/sharedStrings.xml"; + zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); + char * strings = NULL; + if (zf) { + // some files may not have strings + zip_stat(za, name, ZIP_FL_UNCHANGED, &sb_strings); + strings = (char *) malloc(sb_strings.size); + len = zip_fread(zf, strings, sb_strings.size); + if (len < 0) { + sc_error("cannot read file %s.\n", name); + free(strings); + return -1; + } + zip_fclose(zf); + } + + // open xl/styles.xml + name = "xl/styles.xml"; + zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); + if ( ! zf ) { + sc_error("cannot open %s file.", name); + if (strings != NULL) free(strings); + return -1; + } + zip_stat(za, name, ZIP_FL_UNCHANGED, &sb_styles); + char * styles = NULL; + styles = (char *) malloc(sb_styles.size); + len = zip_fread(zf, styles, sb_styles.size); + if (len < 0) { + sc_error("cannot read file %s.", name); + if (strings != NULL) free(strings); + free(styles); + return -1; + } + zip_fclose(zf); + + //open xml file with sheet names + name = "xl/workbook.xml"; + zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); + if ( zf ) { + zip_stat(za, name, ZIP_FL_UNCHANGED, &sh_strings); + char * wb_strings = (char *) malloc(sh_strings.size); + len = zip_fread(zf, wb_strings, sh_strings.size); + if (len < 0) { + sc_error("cannot read file %s.", name); + if (strings != NULL) free(strings); + if (styles != NULL) free(styles); + free(wb_strings); + return -1; + } + zip_fclose(zf); + + // search workbook xml for sheet names + xmlDoc * sheet_search = xmlReadMemory(wb_strings, sh_strings.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); + xmlNode * cur_node = xmlDocGetRootElement(sheet_search)->xmlChildrenNode; + while (cur_node != NULL && strcmp((char *) cur_node->name,"sheets")) + cur_node = cur_node->next; + cur_node = cur_node->xmlChildrenNode; + + char * sheet_name = NULL; + char * sheet_id = NULL; + wchar_t cline [BUFFERSIZE]; + char sheet_filename [BUFFERSIZE]; + // here traverse for the sheets + while (cur_node != NULL) { + sheet_name = (char *) xmlGetProp(cur_node, (xmlChar *) "name"); + + swprintf(cline, BUFFERSIZE, L"newsheet \"%s\"", sheet_name); + send_to_interp(cline); + + sheet_id = (char *) xmlGetProp(cur_node, (xmlChar *) "sheetId"); + + snprintf(sheet_filename, BUFFERSIZE, "xl/worksheets/sheet%s.xml", sheet_id); + + // open the sheet and load it + //sheet_filename = name = "xl/worksheets/sheet1.xml"; + //open each xml sheet file and parse it + zf = zip_fopen(za, sheet_filename, ZIP_FL_UNCHANGED); + if ( ! zf ) { + sc_error("cannot open %s file.", sheet_filename); + if (strings != NULL) free(strings); + if (styles != NULL) free(styles); + return -1; + } + zip_stat(za, sheet_filename, ZIP_FL_UNCHANGED, &sb_sheet); + char * sheet = NULL; + sheet = (char *) malloc(sb_sheet.size); + len = zip_fread(zf, sheet, sb_sheet.size); + if (len < 0) { + sc_error("cannot read file %s.", sheet_filename); + if (strings != NULL) free(strings); + if (styles != NULL) free(styles); + if (sheet != NULL) free(sheet); + return -1; + } + zip_fclose(zf); + + // XML parse for the sheet file + xmlDoc * doc = NULL; + xmlDoc * doc_strings = NULL; + xmlDoc * doc_styles = NULL; + + // this initialize the library and check potential ABI mismatches + // between the version it was compiled for and the actual shared + // library used. + LIBXML_TEST_VERSION + + // parse the file and get the DOM + doc_strings = xmlReadMemory(strings, sb_strings.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); + doc_styles = xmlReadMemory(styles, sb_styles.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); + doc = xmlReadMemory(sheet, sb_sheet.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); + + if (doc == NULL) { + sc_error("error: could not parse file"); + if (strings != NULL) free(strings); + if (styles != NULL) free(styles); + if (sheet != NULL) free(sheet); + return -1; + } + + get_sheet_data(doc, doc_strings, doc_styles); + + // free the document + xmlFreeDoc(doc); + xmlFreeDoc(doc_strings); + xmlFreeDoc(doc_styles); + + // now free and iterate to other sheet + xmlFree(sheet_name); + sheet_name = NULL; + xmlFree(sheet_id); + sheet_id = NULL; + if (sheet != NULL) free(sheet); + + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + auto_fit(sh, 0, sh->maxcols, DEFWIDTH); + deleterow(sh, sh->currow, 1); + + cur_node = cur_node->next; + } + xmlFreeDoc(sheet_search); + if (wb_strings != NULL) free(wb_strings); + } + + // Free the global variables that may have been allocated by the parser + xmlCleanupParser(); + + // free both styles and strings variables + if (strings != NULL) free(strings); + if (styles != NULL) free(styles); + + // close zip file + if (zip_close(za) == -1) { + sc_error("cannot close zip archive `%s'", fname); + return -1; + } + + return 0; +} +#endif + +#ifdef XLSX_EXPORT +#include "xlsxwriter.h" +/** + * \brief export_xlsx() + * \param[in] filename + * \return none + */ +int export_xlsx(char * filename) { + int row, col; + struct ent ** pp; + struct roman * roman = session->cur_doc; + lxw_workbook * workbook = workbook_new(filename); + + int ignore_hidden = get_conf_int("ignore_hidden"); + struct sheet * sh = roman->first_sh; + while (sh != NULL) { + + lxw_worksheet * worksheet = workbook_add_worksheet(workbook, NULL); + int bkp_currow = sh->currow; + sh->currow = 0; + insert_row(sh, 0); //add a row so that scim formulas apply to excel + + for (row = 0; row <= sh->maxrow+1; row++) + for (pp = ATBL(sh, sh->tbl, row, col = 0); col <= sh->maxcol; col++, pp++) { + // ignore hidden rows + if (ignore_hidden && sh->row_hidden[row]) continue; + + if (*pp) { + // Check format here + lxw_format * format = workbook_add_format(workbook); + + // handle alignment + if ((*pp)->label && (*pp)->flags & is_label) // center align + format_set_align(format, LXW_ALIGN_CENTER); + else if ((*pp)->label && (*pp)->flags & is_leftflush) // left align + format_set_align(format, LXW_ALIGN_LEFT); + else if ((*pp)->label) // right align + format_set_align(format, LXW_ALIGN_RIGHT); + + // handle bold, italic and underline + if ((*pp)->ucolor != NULL && (*pp)->ucolor->bold) + format_set_bold(format); + else if ((*pp)->ucolor != NULL && (*pp)->ucolor->italic) + format_set_italic(format); + else if ((*pp)->ucolor != NULL && (*pp)->ucolor->underline) + format_set_underline(format, LXW_UNDERLINE_SINGLE); + + // handle fg color + if ((*pp)->ucolor != NULL && (*pp)->ucolor->fg) { + int fgcolor; + switch ((*pp)->ucolor->fg) { + case BLACK: + fgcolor = LXW_COLOR_BLACK; + break; + case RED: + fgcolor = LXW_COLOR_RED; + break; + case GREEN: + fgcolor = LXW_COLOR_GREEN; + break; + case YELLOW: + fgcolor = LXW_COLOR_YELLOW; + break; + case BLUE: + fgcolor = LXW_COLOR_BLUE; + break; + case MAGENTA: + fgcolor = LXW_COLOR_MAGENTA; + break; + case CYAN: + fgcolor = LXW_COLOR_CYAN; + break; + case WHITE: + fgcolor = LXW_COLOR_WHITE; + break; + } + format_set_font_color(format, fgcolor); + } + + // handle bg color + if ((*pp)->ucolor != NULL && (*pp)->ucolor->bg) { + int bgcolor; + switch ((*pp)->ucolor->bg) { + case BLACK: + bgcolor = LXW_COLOR_BLACK; + break; + case RED: + bgcolor = LXW_COLOR_RED; + break; + case GREEN: + bgcolor = LXW_COLOR_GREEN; + break; + case YELLOW: + bgcolor = LXW_COLOR_YELLOW; + break; + case BLUE: + bgcolor = LXW_COLOR_BLUE; + break; + case MAGENTA: + bgcolor = LXW_COLOR_MAGENTA; + break; + case CYAN: + bgcolor = LXW_COLOR_CYAN; + break; + case WHITE: + bgcolor = LXW_COLOR_WHITE; + break; + } + format_set_bg_color(format, bgcolor); + } + + // dateformat + if ((*pp) && (*pp)->format && (*pp)->format[0] == 'd') { + char sc_format[BUFFERSIZE]; + char * st = NULL; + strcpy(sc_format, &((*pp)->format[1])); + + st = str_replace(sc_format, "%Y", "yyyy"); + strcpy(sc_format, st); + free(st); + st = str_replace(sc_format, "%y", "yy"); + strcpy(sc_format, st); + free(st); + st = str_replace(sc_format, "%m", "mm"); + strcpy(sc_format, st); + free(st); + st = str_replace(sc_format, "%d", "dd"); + strcpy(sc_format, st); + free(st); + format_set_num_format(format, sc_format); + worksheet_write_number(worksheet, row-1, col, (((*pp)->v + get_conf_int("tm_gmtoff")) / 86400 + 25568) , format); + + // formula + } else if ((*pp) && (*pp)->expr && get_conf_int("xlsx_readformulas")) { + linelim = 0; + editexp(sh, (*pp)->row, (*pp)->col); + linelim = -1; + + char * strf; + char formula[BUFFERSIZE]; + strcpy(formula, line); + + strf = str_replace(formula, "@count","count"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@sum","sum"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@prod","product"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@avg","average"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@min","min"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@max","max"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@abs","abs"); + strcpy(formula, strf); + free(strf); + + strf = str_replace(formula, "@stddev","stdev"); + strcpy(formula, strf); + free(strf); + + add_char(formula, '=', 0); + worksheet_write_formula(worksheet, row-1, col, formula, NULL); + worksheet_write_formula_num(worksheet, row-1, col, formula, NULL, (*pp)->v); + + // If a numeric value exists + } else if ( (*pp)->flags & is_valid) { + worksheet_write_number(worksheet, row-1, col, (*pp)->v, format); + + } else if ((*pp)->label) { + worksheet_write_string(worksheet, row-1, col, (*pp)->label, format); + } + /* TODO: handle hidden rows and columns? */ + } + } + sh->currow = 0; + int_deleterow(sh, 0, 1); /* delete the added row */ + sh->currow = bkp_currow; + + sh = sh->next; + } + + return workbook_close(workbook); +} +#endif diff -Nru sc-im-0.8.2+ds/src/formats/xlsx.h sc-im-0.8.3+ds/src/formats/xlsx.h --- sc-im-0.8.2+ds/src/formats/xlsx.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/formats/xlsx.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file xlsx.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for xlsx.c + */ + +#ifdef XLSX +#include +void get_sheet_data(xmlDocPtr doc, xmlDocPtr doc_strings, xmlDocPtr doc_styles); +char * get_xlsx_string(xmlDocPtr doc, int pos); +char * get_xlsx_styles(xmlDocPtr doc_styles, int pos); +char * get_xlsx_number_format_by_id(xmlDocPtr doc_styles, int id); +#endif +int open_xlsx(char * fname, char * encoding); +#ifdef XLSX_EXPORT +int export_xlsx(char * filename); +#endif diff -Nru sc-im-0.8.2+ds/src/freeze.c sc-im-0.8.3+ds/src/freeze.c --- sc-im-0.8.2+ds/src/freeze.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/freeze.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file freeze.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include - -#include "freeze.h" -#include "macros.h" -#include "tui.h" -#include "undo.h" - -struct frange * freeze_ranges = NULL; - -/** - * \brief TODO Document add_frange() - * \details type = 'r' -> freeze a row - * \details type = 'c' -> freeze a col - * \details type = 'a' -> freeze an area - * \param[in] tl_ent - * \param[in] br_ent - * \param[in] type - * \return none - */ - -void add_frange(struct ent * tl_ent, struct ent * br_ent, char type) { - struct frange * f = (struct frange *) malloc(sizeof(struct frange)); - f->tl = tl_ent; - f->br = br_ent; - f->type = type; - f->next = freeze_ranges; - if (freeze_ranges != NULL) free(freeze_ranges); - freeze_ranges = f; - - //sc_debug("freeze range: %d %d %d %d - type:%c", freeze_ranges->tl->row, freeze_ranges->tl->col, freeze_ranges->br->row, freeze_ranges->br->col, type); - return; -} - -/** - * \brief handle_freeze. freeze/unfreeze a row/column - * \param[in] tl_ent: top ent that defines area - * \param[in] br_ent: bottom ent that defines area - * \param[in] value: 0 (unfreeze) or 1 (freeze) - * \param[in] type: 'r' or 'c' - * \return none - */ -void handle_freeze(struct ent * tl_ent, struct ent * br_ent, char value, char type) { - int i; - -#ifdef UNDO - create_undo_action(); -#endif - if (type == 'r') - for (i=tl_ent->row; i<=br_ent->row; i++) { - row_frozen[i]=value; -#ifdef UNDO - undo_freeze_unfreeze(i, -1, value == 1 ? 'f' : 'u', 1); -#endif - } - else if (type == 'c') - for (i=tl_ent->col; i<=br_ent->col; i++) { - col_frozen[i]=value; -#ifdef UNDO - undo_freeze_unfreeze(-1, i, value == 1 ? 'f' : 'u', 1); -#endif - } -#ifdef UNDO - end_undo_action(); -#endif - return; -} - -/** - * \brief TODO Document remove_frange() - * \return none - */ -void remove_frange() { - free(freeze_ranges); - freeze_ranges = NULL; - ui_update(TRUE); - return; -} diff -Nru sc-im-0.8.2+ds/src/freeze.h sc-im-0.8.3+ds/src/freeze.h --- sc-im-0.8.2+ds/src/freeze.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/freeze.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file freeze.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for freeze.c - */ - -#include "sc.h" - -extern struct frange * freeze_ranges; - -void handle_freeze(struct ent * tl_ent, struct ent * br_ent, char value, char type); -void add_frange(struct ent * tl_ent, struct ent * br_ent, char type); -void remove_frange(); - -// freeze ranges -struct frange { - struct ent * tl; - struct ent * br; - char type; - struct frange * next; /* chained ranges */ - //struct frange * prev; -}; diff -Nru sc-im-0.8.2+ds/src/function.c sc-im-0.8.3+ds/src/function.c --- sc-im-0.8.2+ds/src/function.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/function.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,1162 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file function.c + * \author Andrés Martinelli + * \date 24/05/2021 + * \brief Source file that implement the different functions that sc-im can handle + * Based on sc + * + */ +#include +#include +#include // for islower toupper tolower isalpha isalnum isupper +#include + +#include "sc.h" +#include "macros.h" +#include "cmds/cmds.h" +#include "function.h" +#include "tui.h" +#include "interp.h" +#include "xmalloc.h" // for scxfree +#include "conf.h" +#include "utils/string.h" + +extern struct session * session; +extern int cellerror; // get rid of this +extern int rowoffset, coloffset; /* row & col offsets for range functions */ + +#ifndef M_PI + #define M_PI (double)3.14159265358979323846 +#endif + + +/** + * \brief finfunc() + * \param[in] fun + * \param[in] v1 + * \param[in] v2 + * \param[in] v3 + * \return double + */ +double finfunc(int fun, double v1, double v2, double v3) { + double answer,p; + + p = fn2_eval(pow, 1 + v2, v3); + + switch (fun) { + case PV: + if (v2) + answer = v1 * (1 - 1/p) / v2; + else { + cellerror = CELLERROR; + answer = (double)0; + } + break; + case FV: + if (v2) + answer = v1 * (p - 1) / v2; + else { + cellerror = CELLERROR; + answer = (double)0; + } + break; + case PMT: + /* CHECK IF ~= 1 - 1/1 */ + if (p && p != (double)1) + answer = v1 * v2 / (1 - 1/p); + else { + cellerror = CELLERROR; + answer = (double)0; + } + break; + default: + sc_error("Unknown function in finfunc"); + cellerror = CELLERROR; + return ((double)0); + } + return (answer); +} + + +/** + * \brief dostindex() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] val + * \return char * + */ +char * dostindex(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * val) { + int r, c; + struct ent * p; + char * pr; + + p = (struct ent *) 0; + if (minr == maxr) { /* look along the row */ + r = minr; + c = minc + (int) eval(sh, NULL, val) - 1; + } else if (minc == maxc) { /* look down the column */ + r = minr + (int) eval(sh, NULL, val) - 1; + c = minc; + } else { + r = minr + (int) eval(sh, NULL, val->e.o.left) - 1; + c = minc + (int) eval(sh, NULL, val->e.o.right) - 1; + } + if (c <= maxc && c >=minc && r <= maxr && r >=minr) + p = *ATBL(sh, sh->tbl, r, c); + + if (p && p->label) { + pr = scxmalloc((size_t) (strlen(p->label) + 1)); + (void) strcpy(pr, p->label); + if (p->cellerror) + cellerror = CELLINVALID; + return (pr); + } else + return ((char *) 0); +} + + +/** + * \brief doascii() + * \param[in] s + * \return double + */ +double doascii(char * s) { + double v = 0.; + int i ; + if ( !s ) return ((double) 0); + + for (i = 0; s[i] != '\0' ; v = v*256 + (unsigned char)(s[i++]) ) ; + scxfree(s); + return(v); +} + + +/** + * \brief doindex() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] val + * \return double + */ +double doindex(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * val) { + int r, c; + struct ent * p; + + if (val->op == ',') { /* index by both row and column */ + r = minr + (int) eval(sh, NULL, val->e.o.left) - 1; + c = minc + (int) eval(sh, NULL, val->e.o.right) - 1; + } else if (minr == maxr) { /* look along the row */ + r = minr; + c = minc + (int) eval(sh, NULL, val) - 1; + } else if (minc == maxc) { /* look down the column */ + r = minr + (int) eval(sh, NULL, val) - 1; + c = minc; + } else { + sc_error("Improper indexing operation"); + return (double) 0; + } + + if (c <= maxc && c >=minc && r <= maxr && r >=minr && + (p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) + cellerror = CELLINVALID; + return p->v; + } else + return (double) 0; +} + + +/** + * \brief dolookup() + * \param[in] val + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] offset + * \param[in] vflag + * \return double + */ +double dolookup(struct sheet * sh, struct enode * val, int minr, int minc, int maxr, int maxc, int offset, int vflag) { + double v, ret = (double) 0; + int r, c; + struct ent * p = (struct ent *) 0; + int incr, incc, fndr, fndc; + char * s; + + incr = vflag; incc = 1 - vflag; + if (etype(val) == NUM) { + cellerror = CELLOK; + v = eval(sh, NULL, val); + for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) { + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->v <= v) { + fndr = incc ? (minr + offset) : r; + fndc = incr ? (minc + offset) : c; + if (ISVALID(sh, fndr, fndc)) + if (p == NULL) // three lines added + cellerror = CELLINVALID; + else // useful when the lookup ends up in a cell with no value + p = *ATBL(sh, sh->tbl, fndr, fndc); + else { + sc_error(" range specified to @[hv]lookup"); + cellerror = CELLERROR; + } + if (p && p->flags & is_valid) { + if (p->cellerror) + cellerror = CELLINVALID; + ret = p->v; + } + } else break; + } + } + } else { + cellerror = CELLOK; + s = seval(sh, NULL, val); + for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) { + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->label) { + if (s && strcmp(p->label,s) == 0) { + fndr = incc ? (minr + offset) : r; + fndc = incr ? (minc + offset) : c; + if (ISVALID(sh, fndr,fndc)) { + p = *ATBL(sh, sh->tbl, fndr, fndc); + if (p->cellerror) + cellerror = CELLINVALID; + } else { + sc_error(" range specified to @[hv]lookup"); + cellerror = CELLERROR; + } + break; + } + } + } + if (p && p->flags & is_valid) + ret = p->v; + if (s != NULL) scxfree(s); + } + return ret; +} + + +/** + * \brief docount() + * + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * + * \return double + */ +double docount(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + int v; + int r, c; + int cellerr = CELLOK; + struct ent *p; + + v = 0; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if (!e || eval(sh, NULL, e)) + // the following changed for #430. docount should also count cells with strings. not just numbers + // TODO: create @counta to count both, and leave @count for just numbers + if ((p = *ATBL(sh, sh->tbl, r, c)) && (p->flags & is_valid || p->label) ) { + if (p->cellerror) cellerr = CELLINVALID; + v++; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + return v; +} + + +/** + * \brief dosum() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * \return double + */ +double dosum(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + double v; + int r, c; + int cellerr = CELLOK; + struct ent * p; + + v = (double)0; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if ( !e || eval(sh, NULL, e)) + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) + cellerr = CELLINVALID; + v += p->v; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + return v; +} + +/** + * \brief doprod() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * \return double + */ +double doprod(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + double v; + int r, c; + int cellerr = CELLOK; + struct ent * p; + + v = 1; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if ( !e || eval(sh, NULL, e)) + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) cellerr = CELLINVALID; + v *= p->v; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + return v; +} + + +/** + * \brief doavg() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * \return double + */ +double doavg(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + double v; + int r, c; + int count; + int cellerr = CELLOK; + struct ent * p; + + v = (double) 0; + count = 0; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if (!e || eval(sh, NULL, e)) + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) cellerr = CELLINVALID; + v += p->v; + count++; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + + if (count == 0) return ((double)0); + + return (v / (double)count); +} + + +/** + * \brief dostddev() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * \return double + */ +double dostddev(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + double lp, rp, v, nd; + int r, c; + int n; + int cellerr = CELLOK; + struct ent * p; + + n = 0; + lp = 0; + rp = 0; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if (!e || eval(sh, NULL, e)) + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) cellerr = CELLINVALID; + v = p->v; + lp += v*v; + rp += v; + n++; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + + if ((n == 0) || (n == 1)) return ((double)0); + nd = (double) n; + return ( sqrt((nd*lp-rp*rp) / (nd*(nd-1))) ); +} + + +/** + * \brief domax() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * \return double + */ +double domax(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + double v = (double) 0; + int r, c; + int count; + int cellerr = CELLOK; + struct ent * p; + + count = 0; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if (!e || eval(sh, NULL, e)) + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) cellerr = CELLINVALID; + + if (! count) { + v = p->v; + count++; + } else if (p->v > v) + v = p->v; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + + if (count == 0) return ((double)0); + + return (v); +} + + +/** + * \brief domin() + * \param[in] minr + * \param[in] minc + * \param[in] maxr + * \param[in] maxc + * \param[in] e + * \return double + */ +double domin(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e) { + double v = (double)0; + int r, c; + int count; + int cellerr = CELLOK; + struct ent * p; + + count = 0; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + if (e) { + rowoffset = r - minr; + coloffset = c - minc; + } + if (!e || eval(sh, NULL, e)) + if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) { + if (p->cellerror) cellerr = CELLINVALID; + if (! count) { + v = p->v; + count++; + } else if (p->v < v) + v = p->v; + } + } + cellerror = cellerr; + rowoffset = coloffset = 0; + + if (count == 0) return ((double) 0); + + return (v); +} + + +int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +/** + * \brief dodts() + * \param[in] e1 + * \param[in] e2 + * \param[in] e3 + * \return double + */ +double dodts(int e1, int e2, int e3) { + int yr, mo, day; + time_t secs; + struct tm t; + + if (e2 > 12 || e3 > 31) { + mo = e1; + day = e2; + yr = e3; + } else { + yr = e1; + mo = e2; + day = e3; + } + mdays[1] = 28 + (yr % 4 == 0) - (yr % 100 == 0) + (yr % 400 == 0); + + t.tm_hour = t.tm_min = t.tm_sec = 0; + t.tm_mon = --mo; + t.tm_mday = day; + t.tm_year = yr -= 1900; + t.tm_isdst = -1; + + if (mo < 0 || mo > 11 || day < 1 || day > mdays[mo] || (secs = mktime(&t)) == -1) { + sc_error("@dts: invalid argument or date out of range"); + cellerror = CELLERROR; + return (0.0); + } + + return ((double) secs); +} + + +/** + * \brief dotts() + * \param[in] hr + * \param[in] min + * \param[in] sec + * \return double + */ +double dotts(int hr, int min, int sec) { + if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) { + sc_error ("@tts: Invalid argument"); + cellerror = CELLERROR; + return ((double) 0); + } + return ((double) (sec + min * 60 + hr * 3600)); +} + + +/** + * \brief dorow() + * \param[in] ep + * \return double + */ +double dorow(struct enode * ep) { + return (double) ep->e.v.vp->row; +} + + +/** + * \brief docol() + * \param[in] ep + * \return double + */ +double docol(struct enode * ep) { + return (double) ep->e.v.vp->col; +} + + +/** + * \brief dotime() + * \param[in] which + * \param[in] when + * \return double + */ +double dotime(int which, double when) { + static time_t t_cache; + static struct tm tm_cache; + struct tm *tp; + time_t tloc; + + if (which == NOW) + return (double) time(NULL); + + tloc = (time_t)when; + + if (tloc != t_cache) { + tp = localtime(&tloc); + tm_cache = *tp; + tm_cache.tm_mon += 1; + tm_cache.tm_year += 1900; + t_cache = tloc; + } + + switch (which) { + case HOUR: return ((double)(tm_cache.tm_hour)); + case MINUTE: return ((double)(tm_cache.tm_min)); + case SECOND: return ((double)(tm_cache.tm_sec)); + case MONTH: return ((double)(tm_cache.tm_mon)); + case DAY: return ((double)(tm_cache.tm_mday)); + case YEAR: return ((double)(tm_cache.tm_year)); + } + /* Safety net */ + cellerror = CELLERROR; + return ((double)0); +} + + +/** + * \brief doston() + * \param[in] s + * \return double + */ +double doston(char * s) { + double v; + + if ( !s ) return ((double)0); + + v = strtod(s, NULL); + scxfree(s); + return(v); +} + + +/** + * \brief doevaluate(): take a char * with a formula and eval it + * \param[in] s + * \return double + */ +double doevaluate(char * s) { + if ( !s) return ((double)0); + wchar_t cline [BUFFERSIZE]; + swprintf(cline, BUFFERSIZE, L"eval %s", s); + send_to_interp(cline); + double d = eval_result; + scxfree(s); + return (double) d; +} + + +/** + * \brief doslen() + * \param[in] s + * \return int + */ +int doslen(char * s) { + if (!s) return 0; + + //int i = strlen(s); + int i = 0; + + wchar_t widestring[BUFFERSIZE] = { L'\0' }; + const char * mbsptr = s; + size_t result = mbsrtowcs(widestring, &mbsptr, BUFFERSIZE, NULL); + if ( result != (size_t) -1 ) i = wcslen(widestring); + scxfree(s); + return i; +} + + +/** + * \brief doeqs() + * \param[in] s1 + * \param[in] s2 + * \return double + */ +double doeqs(char * s1, char * s2) { + double v; + + if ( !s1 && !s2 ) return ((double)1.0); + + if ( !s1 || !s2 ) + v = 0.0; + else if (strcmp(s1, s2) == 0) + v = 1.0; + else + v = 0.0; + + if (s1) scxfree(s1); + + if (s2) scxfree(s2); + + return(v); +} + + +/** + * \brief donval() + * \details Given a string representing a column name and a value which is a + * column number, return the selected cell's numeric value, if any. + * \param[in] struct sheet * sh + * \param[in] colstr + * \param[in] rowdoub + * \return double + */ +double donval(struct sheet * sh, char * colstr, double rowdoub) { + struct ent * ep; + return (((ep = getent(sh, colstr, rowdoub, 0)) && ((ep->flags) & is_valid)) ? (ep->v) : (double)0); +} + + +/** + * \brief dolmax() + * \details The list routines (e.g. dolmax) are called with an LMAX + * enode. The left pointer is a chain of ELIST nodes, the right + * pointer is a value. + * \param[in] e + * \param[in] ep + * \return double + */ +double dolmax(struct sheet * sh, struct ent * e, struct enode * ep) { + int count = 0; + double maxval = 0; /* Assignment to shut up lint */ + struct enode * p; + double v; + + cellerror = CELLOK; + for (p = ep; p; p = p->e.o.left) { + v = eval(sh, e, p->e.o.right); + if ( !count || v > maxval) { + maxval = v; + count++; + } + } + if (count) return maxval; + else return (double)0; +} + + +/** + * \brief dolmin() + * \param[in] e + * \param[in] ep + * \return double + */ +double dolmin(struct sheet * sh, struct ent * e, struct enode * ep) { + int count = 0; + double minval = 0; /* Assignment to shut up lint */ + struct enode * p; + double v; + + cellerror = CELLOK; + for (p = ep; p; p = p->e.o.left) { + v = eval(sh, e, p->e.o.right); + if ( !count || v < minval) { + minval = v; + count++; + } + } + if (count) return minval; + else return (double)0; +} + + +/** + * \brief docat() + * \details Tules for string functions: + * Take string arguments which they scxfree. All returned strings + * are assumed to be xalloced. + * \param[in] s1 + * \param[in] s2 + * \return char * + */ +char * docat(char * s1, char * s2) { + char * p; + char * arg1, * arg2; + + if ( !s1 && !s2 ) + return ((char *) 0); + arg1 = s1 ? s1 : ""; + arg2 = s2 ? s2 : ""; + p = scxmalloc( (size_t) (strlen(arg1) + strlen(arg2) + 1)); + (void) strcpy(p, arg1); + (void) strcat(p, arg2); + if (s1) + scxfree(s1); + if (s2) + scxfree(s2); + return (p); +} + + +/** + * \brief dodate() + * \param[in] tloc + * \param[in] fmstr + * \return char * + */ +char * dodate(time_t tloc, char * fmtstr) { + char buff[FBUFLEN]; + char * p; + + if (! fmtstr) + fmtstr = "%a %b %d %H:%M:%S %Y"; + strftime(buff, FBUFLEN, fmtstr, localtime(&tloc)); + p = scxmalloc( (size_t) (strlen(buff) + 1)); + (void) strcpy(p, buff); + return (p); +} + + +/** + * \brief Conversion reverse from doascii + * \param[in] ascii + * \return char * + */ +char * dochr(double ascii) { + char * p = scxmalloc((size_t) 10); + char * q = p; + int digit ; + int nbdigits = 0; + int i = 0; + double stopnbdigits = 1; + + for (stopnbdigits = 1; ascii >= stopnbdigits && nbdigits < 9 ; stopnbdigits *= 256, ++ nbdigits) ; + for (; nbdigits > 0 ; -- nbdigits) { + for (stopnbdigits = 1, i = 0; i < nbdigits - 1 ; stopnbdigits *= 256, ++ i) ; + digit = floor (ascii / stopnbdigits) ; + ascii -= digit * stopnbdigits ; + if (ascii >= stopnbdigits && digit < 256) { digit ++ ; ascii += stopnbdigits ; } + if (ascii < 0 && digit >= 0) { digit -- ; ascii -= stopnbdigits ; } + *q++ = digit ; + } + *q = '\0'; + return p; +} + + +/** + * \brief dofmt() + * \param[in] fmtstr + * \param[in] v + * \return char * + */ +char * dofmt(char * fmtstr, double v) { + char buff[FBUFLEN]; + char * p; + + if (!fmtstr) + return ((char *) 0); + (void) snprintf(buff, FBUFLEN, fmtstr, v); + p = scxmalloc( (size_t) (strlen(buff) + 1)); + (void) strcpy(p, buff); + scxfree(fmtstr); + return (p); +} + + +/** + * \brief doext() + * \details Given a command name and a value, run the command with the given + * value and read and return its first output line (only) as an allocated + * string, always a copy of se->e.o.s, whic is set appropriately first + * unless external functions are disabled, in which case the previous value + * is used. The handling of se->e.o.s. and freezing of command is tricky. + * Returning an allocated string in all cases, even if null, insures cell + * expressions are written to files, etc.. + * \param[in] se + * \return char * + */ +char * doext(struct sheet * sh, struct enode *se) { + char buff[FBUFLEN]; /* command line/return, not permanently alloc */ + char * command; + double value; + + command = seval(sh, NULL, se->e.o.left); + value = eval(sh, NULL, se->e.o.right); + if ( ! get_conf_int("external_functions") ) { + sc_error("Warning: external functions disabled; using %s value", + (se->e.o.s && *se->e.o.s) ? "previous" : "null"); + + if (command) scxfree(command); + } else { + if (( !command ) || ( ! *command )) { + sc_error ("Warning: external function given null command name"); + cellerror = CELLERROR; + if (command) scxfree(command); + } else { + FILE *pp; + + (void) sprintf(buff, "%s %g", command, value); /* build cmd line */ + scxfree(command); + + sc_info("Running external function..."); + //(void) refresh(); + + if ((pp = popen(buff, "r")) == (FILE *) NULL) { /* run it */ + sc_error("Warning: running \"%s\" failed", buff); + cellerror = CELLERROR; + } else { + if (fgets(buff, sizeof(buff)-1, pp) == NULL) { /* one line */ + sc_error("Warning: external function returned nothing"); + } else { + char *cp; + //sc_error(""); /* erase notice */ + buff[sizeof(buff)-1] = '\0'; + + if ((cp = strchr(buff, '\n'))) /* contains newline */ + *cp = '\0'; /* end string there */ + + if (!se->e.o.s || strlen(buff) != strlen(se->e.o.s)) + se->e.o.s = scxrealloc(se->e.o.s, strlen(buff)+1); + (void) strcpy (se->e.o.s, buff); + /* save alloc'd copy */ + } + (void) pclose(pp); + + } /* else */ + } /* else */ + } /* else */ + if (se->e.o.s) + return (strcpy(scxmalloc((size_t) (strlen(se->e.o.s)+1)), se->e.o.s)); + else + return (strcpy(scxmalloc((size_t)1), "")); +} + + +/** + * \brief dosval() + * \details Given a string representing a column name and a value which + * is a column number, return the selected cell's string value, if any. + * Even if none, still allocate and return a null string, so the cell + * has a label value, so the expression is saved in a file, etc.. + * \param[in] struct sheet * sh + * \param[in] colstr + * \param[in] rowdoub + * \return char * + */ +char * dosval(struct sheet * sh, char * colstr, double rowdoub) { + struct ent * ep; + char * llabel; + + //llabel = (ep = getent(colstr, rowdoub, 0)) ? (ep -> label) : ""; + + // getent don't return NULL for a cell with no string. + llabel = ( ep = getent(sh, colstr, rowdoub, 0) ) && ep -> label ? (ep -> label) : ""; + + return (strcpy(scxmalloc( (size_t) (strlen(llabel) + 1)), llabel)); +} + + +/** + * \brief doreplace() + * \param[in] source + * \param[in] old + * \param[in] new + * \return char * + */ +char * doreplace(char * source, char * old, char * newstr) { + return str_replace(source, old, newstr); +} + + +/** + * \brief dosubstring() + * \param[in] s + * \param[in] v1 + * \param[in] v2 + * \return char * + */ +char * dosubstr(char * s, int v1, int v2) { + char * s1, * s2; + char * p; + + if ( !s ) return ((char *) 0); + + if (v2 >= strlen(s)) /* past end */ + v2 = strlen(s) - 1; /* to end */ + + if (v1 < 0 || v1 > v2) { /* out of range, return null string */ + scxfree(s); + p = scxmalloc( (size_t) 1); + p[0] = '\0'; + return (p); + } + s2 = p = scxmalloc( (size_t) (v2-v1 + 2)); + s1 = &s[v1]; + for (; v1 <= v2; s1++, s2++, v1++) + *s2 = *s1; + *s2 = '\0'; + scxfree (s); + return (p); +} + + +/** + * \brief dosevaluate(): take a char * with a formula and seval it + * \param[in] s + * \return char * + */ +char * dosevaluate(char * s) { + if ( !s ) return ((char *) 0); + char * p; + + wchar_t cline [BUFFERSIZE]; + swprintf(cline, BUFFERSIZE, L"seval %s", s); + send_to_interp(cline); + + p = scxmalloc(sizeof(char) * strlen(seval_result)+1); + strcpy(p, seval_result); + free(seval_result); + + scxfree(s); + return p; +} + + +/** + * \brief Character casing: make upper case, make lower case, set 8th bit + * \param[in] acase + * \param[in] s + * \return char * + */ +char * docase(int acase, char * s) { + char * p = s; + + if (s == NULL) + return(NULL); + + if ( acase == UPPER ) { + while( *p != '\0' ) { + if( islower(*p) ) + *p = toupper(*p); + p++; + } + } else if (acase == SET8BIT) { + while (*p != '\0') { + if (*p >= 0) + *p += 128 ; + p++; + } + } else if (acase == LOWER) { + while (*p != '\0') { + if (isupper(*p)) + *p = tolower(*p); + p++; + } + } + return (s); +} + + +/** + * \brief docapital + * \details Make proper capitals of every word in a string. If the string + * has mixed case, we say the string is lower and we will upcase only + * first letters of words. If the string is all upper, we will lower rest + * of words. + * \param[in] s + * \return char * + */ +char * docapital(char * s) { + char * p; + int skip = 1; + int AllUpper = 1; + + if (s == NULL) + return (NULL); + for (p = s; *p != '\0' && AllUpper != 0; p++) + if (isalpha(*p) && islower(*p)) AllUpper = 0; + for (p = s; *p != '\0'; p++) { + if (!isalnum(*p)) skip = 1; + else if (skip == 1) { + skip = 0; + if (islower(*p)) *p = toupper(*p); + } else /* if the string was all upper before */ + if (isupper(*p) && AllUpper != 0) + *p = tolower(*p); + } + return (s); +} + + +#ifdef RINT +/** + * \brief Round-to-even + * + * \details Round-to-even, also known as "banker's rounding". With + * round-to-even, a number exactly halfway between two values is + * rounded to whichever is even; e.g. rnd(0.5)=0, rnd(1.5)=2, + * rnd(3.5)=4. This is the default rounding mode for IEEE floating + * point. for good reason: it has better njmeric properties. For example, + * if X+Y is an integer, then X+Y = rnd(X)+rnd(Y) will round-to-even, but + * not always with sc's rounding (which is round-to-positive-infinity). I + * ran into this problem when trying to split interest in an account to + * two people fairly. + * + * \param[in] d + * + * \return none + */ +double rint(double d) { + /* as sent */ + double fl = floor(d), fr = d-fl; + return + fr<0.5 || fr==0.5 && fl==floor(fl/2)*2 ? fl : ceil(d); +} +#endif diff -Nru sc-im-0.8.2+ds/src/function.h sc-im-0.8.3+ds/src/function.h --- sc-im-0.8.2+ds/src/function.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/function.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file function.c + * \author Andrés Martinelli + * \date 24/05/2021 + * \brief Header file for function.c + */ + + +double finfunc(int fun, double v1, double v2, double v3); +char * dostindex(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * val); +double doindex(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * val); +double dolookup(struct sheet * sh, struct enode * val, int minr, int minc, int maxr, int maxc, int offset, int vflag); +double docount(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double dosum(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double doprod(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double doavg(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double dostddev(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double domax(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double domin(struct sheet * sh, int minr, int minc, int maxr, int maxc, struct enode * e); +double dodts(int e1, int e2, int e3); +double dotts(int hr, int min, int sec); +double dotime(int which, double when); +double doston(char * s); +int doslen(char * s); +double doeqs(char * s1, char * s2); +struct ent * dogetent(int r, int c); +double donval(struct sheet * sh, char * colstr, double rowdoub); +double dolmax(struct sheet * sh, struct ent * e, struct enode * ep); +double dolmin(struct sheet * sh, struct ent * e, struct enode * ep); +char * docat(char * s1, char * s2); +#include +char * dodate(time_t tloc, char * fmtstr); +char * dofmt(char * fmtstr, double v); +char * doext(struct sheet * sh, struct enode * se); +char * dosval(struct sheet * sh, char * colstr, double rowdoub); +char * dosubstr(char * s, int v1, int v2); +char * docase(int acase, char * s); +char * docapital(char * s); +double doevaluate(char * s); +char * dosevaluate(char * s); +double rint(double d); +double dorow(struct enode * ep); +double docol(struct enode * ep); +double doascii(char * s); +char * doreplace(char * source, char * old, char * new_); +char * dochr(double ascii); + +#define dtr(x) ((x)*(M_PI/(double)180.0)) +#define rtd(x) ((x)*(180.0/(double)M_PI)) +#define ISVALID(s,r,c) ((r)>=0 && (r) < s->maxrows && (c) >=0 && (c) < s->maxcols) diff -Nru sc-im-0.8.2+ds/src/gdb.gdb sc-im-0.8.3+ds/src/gdb.gdb --- sc-im-0.8.2+ds/src/gdb.gdb 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/gdb.gdb 2023-01-16 15:38:03.000000000 +0000 @@ -1,3 +1,2 @@ target remote localhost:12345 -b interp.c:1343 -b dep_graph.c:802 +b graph.c:535 diff -Nru sc-im-0.8.2+ds/src/gram.y sc-im-0.8.3+ds/src/gram.y --- sc-im-0.8.2+ds/src/gram.y 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/gram.y 2023-01-16 15:38:03.000000000 +0000 @@ -2,34 +2,38 @@ #include #include "sc.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "interp.h" #include "macros.h" -#include "sort.h" -#include "filter.h" +#include "actions/sort.h" +#include "actions/filter.h" #include "maps.h" #include "marks.h" #include "xmalloc.h" // for scxfree -#include "hide_show.h" -#include "cmds_normal.h" +#include "actions/hide_show.h" +#include "cmds/cmds_normal.h" #include "conf.h" #include "pipe.h" #include "main.h" #include "file.h" #include "tui.h" #include "undo.h" -#include "dep_graph.h" +#include "yank.h" +#include "graph.h" #include "utils/dictionary.h" #include "trigger.h" -#include "shift.h" +#include "actions/shift.h" #include "clipboard.h" -#include "plot.h" -#include "subtotal.h" - -#include "cmds_command.h" +#include "actions/plot.h" +#include "actions/subtotal.h" +#include "actions/freeze.h" +#include "sheet.h" +#include "vmtbl.h" +#include "cmds/cmds_command.h" void yyerror(char *err); // error routine for yacc (gram.y) int yylex(); +extern struct session * session; #ifdef USELOCALE #include @@ -85,7 +89,7 @@ %token S_FREEZE %token S_UNFREEZE %token S_MARK -%token S_AUTOJUS +%token S_AUTOFIT %token S_PAD /* token S_INSERTCOL @@ -191,6 +195,8 @@ %token S_VALUEIZEALL %token S_SHIFT %token S_GETNUM +%token S_YANKAREA +%token S_PASTEYANKED %token S_GETSTRING %token S_GETEXP %token S_GETFMT @@ -206,6 +212,12 @@ %token S_UNDO %token S_IMAP %token S_CMAP +%token S_NEWSHEET +%token S_NEXTSHEET +%token S_PREVSHEET +%token S_DELSHEET +%token S_MOVETOSHEET +%token S_RENAMESHEET %token S_NMAP %token S_VMAP %token S_INOREMAP @@ -227,6 +239,13 @@ %token S_TRIGGER %token S_UNTRIGGER +%token S_OFFSCR_SC_COLS +%token S_OFFSCR_SC_ROWS +%token S_NB_FROZEN_ROWS +%token S_NB_FROZEN_COLS +%token S_NB_FROZEN_SCREENROWS +%token S_NB_FROZEN_SCREENCOLS + %token K_AUTOBACKUP %token K_NOAUTOBACKUP %token K_AUTOCALC @@ -249,11 +268,11 @@ %token K_NONUMERIC_DECIMAL %token K_NUMERIC_ZERO %token K_NONUMERIC_ZERO -%token K_FILENAME_WITH_MODE -%token K_NOFILENAME_WITH_MODE %token K_OVERLAP %token K_NOOVERLAP %token K_INPUT_BAR_BOTTOM +%token K_IGNORE_HIDDEN +%token K_NOIGNORE_HIDDEN %token K_UNDERLINE_GRID %token K_TRUNCATE %token K_NOTRUNCATE @@ -269,6 +288,7 @@ %token K_DEFAULT_PASTE_FROM_CLIPBOARD_CMD %token K_COPY_TO_CLIPBOARD_DELIMITED_TAB %token K_NOCOPY_TO_CLIPBOARD_DELIMITED_TAB +%token K_DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD %token K_IGNORECASE %token K_NOIGNORECASE %token K_TM_GMTOFF @@ -393,6 +413,7 @@ %token K_CHR %token K_FACT + %right ';' %left '?' ':' %left '|' @@ -402,22 +423,29 @@ %left '*' '/' '%' %left '^' + %% command: - S_LET var_or_range '=' e { let($2.left.vp, $4); } + S_LET var_or_range '=' e { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + let(roman, sh, $2.left.vp, $4); + } | S_LET var_or_range '=' { // TODO get this code out of gram.y - reeval cells that depends on $2 extern graphADT graph; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; #ifdef UNDO // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range($2.left.vp->row, $2.left.vp->col, $2.left.vp->row, $2.left.vp->col); + ents_that_depends_on_range(sh, $2.left.vp->row, $2.left.vp->col, $2.left.vp->row, $2.left.vp->col); create_undo_action(); - copy_to_undostruct($2.left.vp->row, $2.left.vp->col, $2.left.vp->row, $2.left.vp->col, UNDO_DEL, HANDLE_DEPS, NULL); + copy_to_undostruct(sh, $2.left.vp->row, $2.left.vp->col, $2.left.vp->row, $2.left.vp->col, UNDO_DEL, HANDLE_DEPS, NULL); #endif - if (getVertex(graph, lookat($2.left.vp->row, $2.left.vp->col), 0) != NULL) destroy_vertex(lookat($2.left.vp->row, $2.left.vp->col)); + if (getVertex(graph, sh, lookat(sh, $2.left.vp->row, $2.left.vp->col), 0) != NULL) destroy_vertex(sh, lookat(sh, $2.left.vp->row, $2.left.vp->col)); $2.left.vp->v = (double) 0.0; if ($2.left.vp->expr && !($2.left.vp->flags & is_strexpr)) { @@ -427,7 +455,7 @@ $2.left.vp->cellerror = CELLOK; $2.left.vp->flags &= ~is_valid; $2.left.vp->flags |= is_changed; - modflg++; + roman->modflg++; // clearing the value counts as a write, so run write triggers if (( $2.left.vp->trigger ) && (($2.left.vp->trigger->flag & TRG_WRITE) == TRG_WRITE)) @@ -435,7 +463,7 @@ #ifdef UNDO // here we save in undostruct, all the ents that depends on the deleted one (after change) - copy_to_undostruct($2.left.vp->row, $2.left.vp->col, $2.left.vp->row, $2.left.vp->col, UNDO_ADD, HANDLE_DEPS, NULL); + copy_to_undostruct(sh, $2.left.vp->row, $2.left.vp->col, $2.left.vp->row, $2.left.vp->col, UNDO_ADD, HANDLE_DEPS, NULL); extern struct ent_ptr * deps; if (deps != NULL) { free(deps); @@ -445,32 +473,72 @@ #endif } - | S_LABEL var_or_range '=' e { slet($2.left.vp, $4, 0); } - | S_LEFTSTRING var_or_range '=' e { slet($2.left.vp, $4, -1); } - | S_RIGHTSTRING var_or_range '=' e { slet($2.left.vp, $4, 1); } - | S_LEFTJUSTIFY var_or_range { ljustify($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } - | S_RIGHTJUSTIFY var_or_range { rjustify($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } - - | S_CENTER var_or_range { center($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } - | S_FMT var_or_range STRING { format_cell($2.left.vp, $2.right.vp, $3); - scxfree($3); + | S_LABEL var_or_range '=' e { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + slet(roman, sh, $2.left.vp, $4, 0); + } + + | S_LEFTSTRING var_or_range '=' e { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + slet(roman, sh, $2.left.vp, $4, -1); + } + | S_RIGHTSTRING var_or_range '=' e { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + slet(roman, sh, $2.left.vp, $4, 1); + } + | S_LEFTJUSTIFY var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + ljustify(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } + | S_RIGHTJUSTIFY var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + rjustify(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } + + | S_CENTER var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + center(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } + | S_FMT var_or_range STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + format_cell(sh, $2.left.vp, $2.right.vp, $3); + scxfree($3); } - | S_DATEFMT var_or_range STRING { dateformat($2.left.vp, $2.right.vp, $3); - scxfree($3); } - | S_DATEFMT STRING { dateformat(lookat(currow, curcol), lookat(currow, curcol), $2); + | S_DATEFMT var_or_range STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + dateformat(sh, $2.left.vp, $2.right.vp, $3); + scxfree($3); + } + | S_DATEFMT STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + dateformat(sh, lookat(sh, sh->currow, sh->curcol), lookat(sh, sh->currow, sh->curcol), $2); scxfree($2); } -/* para compatibilidad con sc */ +/* to be sc compatible */ | S_HIDE COL { hide_col($2, 1); } // hide de una unica columna | S_HIDE NUMBER { hide_row($2, 1); } // hide de una unica fila | S_SHOW COL { show_col($2, 1); } // show de una unica columna | S_SHOW NUMBER { show_row($2, 1); } // show de una unica fila /* more scripting commands */ - | S_DELETECOL COL { deletecol($2, 1); } - | S_DELETEROW NUMBER { deleterow($2, 1); } + | S_DELETECOL COL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + deletecol(sh, $2, 1); + } + | S_DELETEROW NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + deleterow(sh, $2, 1); + } -/* agregados para scim */ +/* added for sc-im */ | S_HIDECOL COL { hide_col($2, 1); } // hide de una unica columna | S_SHOWCOL COL { @@ -484,64 +552,127 @@ | S_SHOWROW NUMBER ':' NUMBER { show_row($2, $4-$2+1); } // show de un rango de filas | S_HIDECOL COL ':' COL { - int c = curcol, arg; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int c = sh->curcol, arg; if ($2 < $4) { - curcol = $2; + sh->curcol = $2; arg = $4 - $2 + 1; } else { - curcol = $4; + sh->curcol = $4; arg = $2 - $4 + 1; } hide_col($2, arg); // hide de un rango de columnas - curcol = c < curcol ? c : c < curcol + arg ? curcol : c - arg; + sh->curcol = c < sh->curcol ? c : c < sh->curcol + arg ? sh->curcol : c - arg; } | S_HIDEROW NUMBER ':' NUMBER { - int r = currow, arg; // hide de un rango de filas + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r = sh->currow, arg; // hide de un rango de filas if ($2 < $4) { - currow = $2; + sh->currow = $2; arg = $4 - $2 + 1; } else { - currow = $4; + sh->currow = $4; arg = $2 - $4 + 1; } hide_row($2, arg); - currow = r < currow ? r : r < currow + arg ? currow : r - arg; + sh->currow = r < sh->currow ? r : r < sh->currow + arg ? sh->currow : r - arg; } - | S_VALUEIZEALL { valueize_area(0, 0, maxrow, maxcol); } + | S_VALUEIZEALL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + valueize_area(sh, 0, 0, sh->maxrow, sh->maxcol); } + | S_SHIFT var_or_range STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; if (strlen($3) != 1 || ($3[0] != 'h' && $3[0] != 'j' && $3[0] != 'k' && $3[0] != 'l')) { sc_error("wrong parameter for shift command"); } else { wchar_t wstr[2] = L""; swprintf(wstr, BUFFERSIZE, L"%c", $3[0]); - shift($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, wstr[0]); + shift(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, wstr[0]); } scxfree($3); } - | S_MARK COL var_or_range { set_cell_mark($2 + 97, $3.left.vp->row, $3.left.vp->col); } + | S_MARK COL var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + set_cell_mark($2 + 97, sh, $3.left.vp->row, $3.left.vp->col); + } - | S_MARK COL var_or_range var_or_range { ; + | S_MARK COL var_or_range var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; srange * sr = create_range('\0', '\0', $3.left.vp, $4.left.vp); unselect_ranges(); - set_range_mark($2 + 97, sr); + set_range_mark($2 + 97, sh, sr); + } + + | S_MARK COL STRING var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $3)) != NULL ) { + set_cell_mark($2 + 97, sh, $4.left.vp->row, $4.left.vp->col); + } + scxfree($3); } - | S_FILL var_or_range num num { fill($2.left.vp, $2.right.vp, $3, $4); } + | S_MARK COL STRING var_or_range var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $3)) != NULL ) { + srange * sr = create_range('\0', '\0', $4.left.vp, $5.left.vp); + unselect_ranges(); + set_range_mark($2 + 97, sh, sr); + } + scxfree($3); + } + | S_FILL var_or_range num num { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + fill(sh, $2.left.vp, $2.right.vp, $3, $4); + } | S_FILL num num { sc_error("Not enough parameters for fill command"); } - | S_FREEZE NUMBER ':' NUMBER { handle_freeze(lookat($2, 0), lookat($4, 0), 1, 'r'); } - | S_FREEZE NUMBER { handle_freeze(lookat($2, 0), lookat($2, 0), 1, 'r'); } - | S_FREEZE COL ':' COL { handle_freeze(lookat(0, $2), lookat(0, $4), 1, 'c'); } - | S_FREEZE COL { handle_freeze(lookat(0, $2), lookat(0, $2), 1, 'c'); } - | S_UNFREEZE NUMBER ':' NUMBER{ handle_freeze(lookat($2, 0), lookat($4, 0), 0, 'r'); } - | S_UNFREEZE NUMBER { handle_freeze(lookat($2, 0), lookat($2, 0), 0, 'r'); } - | S_UNFREEZE COL ':' COL { handle_freeze(lookat(0, $2), lookat(0, $4), 0, 'c'); } - | S_UNFREEZE COL { handle_freeze(lookat(0, $2), lookat(0, $2), 0, 'c'); } + | S_FREEZE NUMBER ':' NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, $2, 0), lookat(sh, $4, 0), 1, 'r'); } + | S_FREEZE NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, $2, 0), lookat(sh, $2, 0), 1, 'r'); } + | S_FREEZE COL ':' COL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, 0, $2), lookat(sh, 0, $4), 1, 'c'); } + | S_FREEZE COL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, 0, $2), lookat(sh, 0, $2), 1, 'c'); } + | S_UNFREEZE NUMBER ':' NUMBER{ + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, $2, 0), lookat(sh, $4, 0), 0, 'r'); } + | S_UNFREEZE NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, $2, 0), lookat(sh, $2, 0), 0, 'r'); } + | S_UNFREEZE COL ':' COL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, 0, $2), lookat(sh, 0, $4), 0, 'c'); } + | S_UNFREEZE COL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + handle_freeze(sh, lookat(sh, 0, $2), lookat(sh, 0, $2), 0, 'c'); } - | S_SORT range STRING { sortrange($2.left.vp, $2.right.vp, $3); + | S_SORT range STRING { sortrange(session->cur_doc->cur_sh, $2.left.vp, $2.right.vp, $3); //scxfree($3); //do not free here } @@ -564,43 +695,219 @@ scxfree(tmp); } */ - | S_AUTOJUS COL ':' COL { auto_justify($2, $4, DEFWIDTH); } // auto justificado de columnas - | S_AUTOJUS COL { auto_justify($2, $2, DEFWIDTH); } // auto justificado de columna + | S_AUTOFIT COL ':' COL { auto_fit(session->cur_doc->cur_sh, $2, $4, DEFWIDTH); } // auto justificado de columnas + | S_AUTOFIT COL { auto_fit(session->cur_doc->cur_sh, $2, $2, DEFWIDTH); } // auto justificado de columna - | S_PAD NUMBER COL ':' COL { pad($2, 0, $3, maxrow, $5); } - | S_PAD NUMBER COL { pad($2, 0, $3, maxrow, $3); } - | S_PAD NUMBER var_or_range { pad($2, $3.left.vp->row, $3.left.vp->col, $3.right.vp->row, $3.right.vp->col); } - | S_GETFORMAT COL { getformat($2, fdoutput); } - | S_FORMAT COL NUMBER NUMBER NUMBER { doformat($2,$2,$3,$4,$5); } - | S_FORMAT NUMBER NUMBER { dorowformat($2, $3); } + | S_PAD NUMBER COL ':' COL { + pad(session->cur_doc->cur_sh, $2, 0, $3, session->cur_doc->cur_sh->maxrow, $5); } + | S_PAD NUMBER COL { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + pad(sh, $2, 0, $3, sh->maxrow, $3); } + | S_PAD NUMBER var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + pad(sh, $2, $3.left.vp->row, $3.left.vp->col, $3.right.vp->row, $3.right.vp->col); } + | S_GETFORMAT COL { getformat($2, fdoutput); } + | S_FORMAT COL NUMBER NUMBER NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + doformat(sh, $2,$2,$3,$4,$5); + } + | S_FORMAT NUMBER NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + dorowformat(sh, $2, $3); + } | S_FILTERON range { enable_filters($2.left.vp, $2.right.vp); } - | S_GOTO var_or_range var_or_range { moveto($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3.left.vp->row, $3.left.vp->col); } - | S_GOTO var_or_range { moveto($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, -1, -1); } - | S_GOTO num { num_search($2, 0, 0, maxrow, maxcol, 0, 1); } - | S_GOTO STRING { str_search($2, 0, 0, maxrow, maxcol, 0, 1); } + | S_GOTO var_or_range var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + moveto(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3.left.vp->row, $3.left.vp->col); + } + | S_GOTO var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + moveto(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, -1, -1); + } + | S_GOTO num { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + num_search(sh, $2, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 0, 1); } + | S_GOTO STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + str_search(sh, $2, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 0, 1); } //scxfree($2); shall not free here - | S_GOTO '#' STRING { str_search($3, 0, 0, maxrow, maxcol, 1, 1); } + | S_GOTO '#' STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + str_search(sh, $3, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 1, 1); } //scxfree($3); shall not free here - | S_GOTO '%' STRING { str_search($3, 0, 0, maxrow, maxcol, 2, 1); } + | S_GOTO '%' STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + str_search(sh, $3, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 2, 1); } //scxfree($3); shall not free here - | S_GOTOB num { num_search($2, 0, 0, maxrow, maxcol, 0, 0); } - - | S_GOTOB STRING { str_search($2, 0, 0, maxrow, maxcol, 0, 0); } - - | S_GOTOB '#' STRING { str_search($3, 0, 0, maxrow, maxcol, 1, 0); } - - | S_GOTOB '%' STRING { str_search($3, 0, 0, maxrow, maxcol, 2, 0); } + | S_GOTOB num { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + num_search(sh, $2, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 0, 0); } + + | S_GOTOB STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + str_search(sh, $2, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 0, 0); } + + | S_GOTOB '#' STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + str_search(sh, $3, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 1, 0); } + + | S_GOTOB '%' STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + str_search(sh, $3, 0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol, 2, 0); } // | S_GOTO WORD { /* don't repeat last goto on "unintelligible word" */ ; } | S_CCOPY range { copy_to_clipboard($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_STRTONUM range { convert_string_to_number($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_CPASTE { paste_from_clipboard(); } - | S_LOCK var_or_range { lock_cells($2.left.vp, $2.right.vp); } - | S_UNLOCK var_or_range { unlock_cells($2.left.vp, $2.right.vp); } + | S_LOCK var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + lock_cells(sh, $2.left.vp, $2.right.vp); + } + | S_UNLOCK var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + unlock_cells(sh, $2.left.vp, $2.right.vp); + } + | S_NEWSHEET STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh; + + // do not need to alloc a new 'Sheet1' + // just reuse the just allocated 'Sheet1' in load_file(); + if (! strcmp($2, "Sheet1") && (sh = search_sheet(roman, $2)) != NULL && sh->flags & is_allocated) { + sh->flags &= ~is_allocated; + sh->flags |= is_empty; + scxfree($2); + chg_mode('.'); + + // if a sheet already exists with the name we are trying to create + } else if ((sh = search_sheet(roman, $2)) != NULL ) { + sc_info("sheet already exist with that name"); + scxfree($2); + chg_mode('.'); + + // if a just allocated 'Sheet1' exists, reuse it and do not malloc a new one. + } else if ((sh = search_sheet(roman, "Sheet1")) != NULL && sh->flags & is_allocated) { + sh->flags &= ~is_allocated; + sh->flags |= is_empty; + free(sh->name); + sh->name = $2; + chg_mode('.'); + ui_update(TRUE); + + // if reached here, now yes malloc a new one + } else { + roman->cur_sh = new_sheet(roman, $2); + growtbl(roman->cur_sh, GROWNEW, 0, 0); + erasedb(roman->cur_sh, 0); + scxfree($2); + roman->modflg++; + chg_mode('.'); + ui_update(TRUE); + } + } + | S_DELSHEET STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $2)) == NULL ) { + sc_info("No sheet exists with that name"); + scxfree($2); + } else if (roman->cur_sh == sh && sh->next == NULL && sh->prev == NULL) { + sc_info("Cannot delete the only sheet of document"); + scxfree($2); + } else { + if (roman->cur_sh == sh && sh->next != NULL) + roman->cur_sh = sh->next; + else if (roman->cur_sh == sh) + roman->cur_sh = sh->prev; + delete_sheet(roman, sh, 0); + sh = NULL; + roman->modflg++; + scxfree($2); + chg_mode('.'); + ui_update(TRUE); + } + } + | S_DELSHEET { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + if (sh->next == NULL && sh->prev == NULL) { + sc_info("Cannot delete the only sheet of document"); + } else { + if (roman->cur_sh == sh && sh->next != NULL) + roman->cur_sh = sh->next; + else if (roman->cur_sh == sh) + roman->cur_sh = sh->prev; + delete_sheet(roman, sh, 0); + sh = NULL; + roman->modflg++; + chg_mode('.'); + ui_update(TRUE); + } + } + | S_NEXTSHEET { + struct roman * roman = session->cur_doc; + if (roman->cur_sh->next != NULL) { + roman->cur_sh = roman->cur_sh->next; + } else if (roman->next != NULL) { + session->cur_doc = roman->next; + session->cur_doc->cur_sh = session->cur_doc->first_sh; + } else { + session->cur_doc = session->first_doc; + session->cur_doc->cur_sh = session->cur_doc->first_sh; + } + chg_mode('.'); + ui_update(TRUE); + } + | S_PREVSHEET { + struct roman * roman = session->cur_doc; + if (roman->cur_sh->prev != NULL) { + roman->cur_sh = roman->cur_sh->prev; + } else if (roman->prev != NULL) { + session->cur_doc = roman->prev; + session->cur_doc->cur_sh = session->cur_doc->last_sh; + } else { + session->cur_doc = session->last_doc; + session->cur_doc->cur_sh = session->cur_doc->last_sh; + } + chg_mode('.'); + ui_update(TRUE); + } + + | S_MOVETOSHEET STRING { + struct sheet * sh; + if ((sh = search_sheet(session->cur_doc, $2)) != NULL ) + session->cur_doc->cur_sh = sh; + scxfree($2); + } + | S_RENAMESHEET STRING { + struct sheet * sh = session->cur_doc->cur_sh; + if (sh->name != NULL) free(sh->name); + session->cur_doc->modflg++; + sh->name = $2; + chg_mode('.'); + ui_show_header(); + } + | S_NMAP STRING STRING { add_map($2, $3, NORMAL_MODE, 1); scxfree($2); @@ -692,38 +999,77 @@ | S_CELLCOLOR var_or_range STRING { #ifdef USECOLORS + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; if ( ! get_conf_int("nocurses")) - color_cell($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3); + color_cell(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3); #endif scxfree($3); } | S_TRIGGER var_or_range STRING { - set_trigger($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3); + set_trigger(session->cur_doc->cur_sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3); scxfree($3); } + | S_OFFSCR_SC_COLS NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sh->offscr_sc_cols = $2; + } + | S_OFFSCR_SC_ROWS NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sh->offscr_sc_rows = $2; + } + | S_NB_FROZEN_ROWS NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sh->nb_frozen_rows = $2; + } + | S_NB_FROZEN_COLS NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sh->nb_frozen_cols = $2; + } + | S_NB_FROZEN_SCREENROWS NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sh->nb_frozen_screenrows = $2; + } + | S_NB_FROZEN_SCREENCOLS NUMBER { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sh->nb_frozen_screencols = $2; + } + | S_UNTRIGGER var_or_range { - del_trigger($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); + del_trigger(session->cur_doc->cur_sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_CELLCOLOR STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; #ifdef USECOLORS if ( ! get_conf_int("nocurses")) - color_cell(currow, curcol, currow, curcol, $2); + color_cell(sh, sh->currow, sh->curcol, sh->currow, sh->curcol, $2); #endif scxfree($2); } | S_UNFORMAT var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; #ifdef USECOLORS - if ( ! get_conf_int("nocurses")) unformat($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); + if ( ! get_conf_int("nocurses")) unformat(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); #endif } | S_UNFORMAT { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; #ifdef USECOLORS - if ( ! get_conf_int("nocurses")) unformat(currow, curcol, currow, curcol); + if ( ! get_conf_int("nocurses")) unformat(sh, sh->currow, sh->curcol, sh->currow, sh->curcol); #endif } @@ -735,9 +1081,9 @@ define_color($2, $3, $4, $5); scxfree($2); } - | S_FCOPY { fcopy(""); } - | S_FCOPY strarg { fcopy($2); } - | S_FSUM { fsum(); } + | S_FCOPY { fcopy(session->cur_doc->cur_sh, ""); } + | S_FCOPY strarg { fcopy(session->cur_doc->cur_sh, $2); } + | S_FSUM { fsum(session->cur_doc->cur_sh); } | S_PLOT STRING var_or_range { plot($2, $3.left.vp->row, $3.left.vp->col, $3.right.vp->row, $3.right.vp->col); @@ -750,10 +1096,12 @@ | S_SET setlist { //if (! loading) sc_debug("INT: Config value changed"); } /* - | S_DEFINE strarg { struct ent_ptr arg1, arg2; - arg1.vp = lookat(showsr, showsc); + | S_DEFINE strarg { + struct roman * roman = session->cur_doc; + struct ent_ptr arg1, arg2; + arg1.vp = lookat(roman->cur_sh, showsr, showsc); arg1.vf = 0; - arg2.vp = lookat(currow, curcol); + arg2.vp = lookat(roman->cur_sh, roman->cur_sh->currow, roman->cur_sh->curcol); arg2.vf = 0; if (arg1.vp == arg2.vp ) add_range($2, arg2, arg2, 0); @@ -767,7 +1115,9 @@ | S_UNDEFINE var_or_range { del_range($2.left.vp, $2.right.vp); } | S_EVAL e { - eval_result = eval(NULL, $2); + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + eval_result = eval(sh, NULL, $2); efree($2); } | S_EXECUTE STRING { @@ -795,10 +1145,11 @@ scxfree($2); } | S_EXPORT STRING STRING { - swprintf(inputline, BUFFERSIZE, L"e! %s %s", $2, $3); - do_export(0, 0, maxrow, maxcol); - scxfree($2); - scxfree($3); + struct roman * roman = session->cur_doc; + swprintf(inputline, BUFFERSIZE, L"e! %s %s", $2, $3); + do_export(0, 0, roman->cur_sh->maxrow, roman->cur_sh->maxcol); + scxfree($2); + scxfree($3); } | S_QUIT { printf("quitting. unsaved changes will be lost.\n"); @@ -810,12 +1161,12 @@ } | S_PRINT_GRAPH { print_vertexs(); } - | S_SYNCREFS { sync_refs(); } + | S_SYNCREFS { sync_refs(session->cur_doc->cur_sh); } | S_UNDO { #ifdef UNDO do_undo(); - // sync_refs(); + // sync_refs(session->cur_doc->cur_sh); EvalAll(); ui_update(TRUE); #endif @@ -824,7 +1175,7 @@ | S_REDO { #ifdef UNDO do_redo(); - // sync_refs(); + // sync_refs(session->cur_doc->cur_sh); EvalAll(); ui_update(TRUE); #endif @@ -837,9 +1188,19 @@ //changed = 0; } | S_GETNUM var_or_range { - getnum($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, fdoutput); + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + getnum(sh, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, fdoutput); } + | S_GETNUM '{' STRING '}' '!' var_or_range { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $3)) == NULL ) + sh = roman->cur_sh; + getnum(sh, $6.left.vp->row, $6.left.vp->col, $6.right.vp->row, $6.right.vp->col, fdoutput); + scxfree($3); + } | S_GETSTRING var_or_range { getstring($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, fdoutput); } | S_GETEXP var_or_range { getexp($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, fdoutput); } @@ -847,7 +1208,28 @@ | S_GETFMT var_or_range { getfmt($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, fdoutput); } - | S_SEVAL e { seval_result = seval(NULL, $2); // always make sure this seval_result is always freed afterwards + | S_YANKAREA '{' STRING '}' '!' var_or_range STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $3)) == NULL ) + sh = roman->cur_sh; + yank_area(sh, $6.left.vp->row, $6.left.vp->col, $6.right.vp->row, $6.right.vp->col, $7[0], 1); + scxfree($3); + scxfree($7); + } + | S_PASTEYANKED '{' STRING '}' NUMBER STRING { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $3)) == NULL ) + sh = roman->cur_sh; + paste_yanked_ents(sh, $5, $6[0]); + scxfree($3); + scxfree($6); + } + | S_SEVAL e { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + seval_result = seval(sh, NULL, $2); // always make sure this seval_result is always freed afterwards efree($2); } | S_ERROR STRING { sc_error($2); @@ -856,7 +1238,7 @@ | // nothing | error { - sc_error("syntax error"); + sc_error("syntax error: %s", line); line[0]='\0'; //linelim = 0; //yyparse(); @@ -866,9 +1248,33 @@ }; term: var { - if ($1.vf & GETENT) + if ($1.vf & GET_ENT) $$ = $1.expr; - else $$ = new_var(O_VAR, $1); + else { + $1.sheet = NULL; + $$ = new_var(O_VAR, $1); + $$->e.r.left.expr = NULL; + $$->e.r.right.expr = NULL; + } + } + + | '{' STRING '}' '!' var { + struct roman * roman = session->cur_doc; + struct sheet * sh; + if ((sh = search_sheet(roman, $2)) != NULL) { + struct ent_ptr ep; + ep.vf = $5.vf; + ep.vp = lookat(sh, $5.vp->row, $5.vp->col); + ep.sheet = sh; + $$ = new_var(O_VAR, ep); + $$->e.r.left.expr = NULL; + $$->e.r.right.expr = NULL; + scxfree($2); + } else { + //sc_debug("not sheet found"); + $$ = NULL; + scxfree($2); + } } | '@' K_FIXED term { $$ = new('f', $3, ENULL); } @@ -1060,7 +1466,7 @@ | e '&' e { $$ = new('&', $1, $3); } | e '|' e { $$ = new('|', $1, $3); } | e '<' '=' e { $$ = new('!', new('>', $1, $4), ENULL); } - | e '!' '=' e { $$ = new('!', new('=', $1, $4), ENULL); } + /* | e '!' '=' e { $$ = new('!', new('=', $1, $4), ENULL); } */ | e '<' '>' e { $$ = new('!', new('=', $1, $4), ENULL); } | e '>' '=' e { $$ = new('!', new('<', $1, $4), ENULL); } | e '#' e { $$ = new('#', $1, $3); } @@ -1077,23 +1483,35 @@ | RANGE { $$ = $1; } ; -var: COL NUMBER { $$.vp = lookat($2, $1); +var: + + COL NUMBER { + struct roman * roman = session->cur_doc; + $$.vp = lookat(roman->cur_sh, $2, $1); $$.vf = 0; } - | '$' COL NUMBER { $$.vp = lookat($3, $2); + | '$' COL NUMBER { + struct roman * roman = session->cur_doc; + $$.vp = lookat(roman->cur_sh, $3, $2); $$.vf = FIX_COL; } - | COL '$' NUMBER { $$.vp = lookat($3, $1); + | COL '$' NUMBER { + struct roman * roman = session->cur_doc; + $$.vp = lookat(roman->cur_sh, $3, $1); $$.vf = FIX_ROW; } | '$' COL '$' NUMBER { - $$.vp = lookat($4, $2); + struct roman * roman = session->cur_doc; + $$.vp = lookat(roman->cur_sh, $4, $2); $$.vf = FIX_ROW | FIX_COL; } + | '@' K_GETENT '(' e ',' e ')' { - $$.vp = lookat(eval(NULL, $4), eval(NULL, $6)); - $$.vf = GETENT; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + $$.vp = lookat(sh, eval(sh, NULL, $4), eval(sh, NULL, $6)); + $$.vf = GET_ENT; if ($$.expr != NULL) efree($$.expr); $$.expr = new(GETENT, $4, $6); } @@ -1101,6 +1519,7 @@ | VAR { $$ = $1.left; } + ; var_or_range: range { $$ = $1; } @@ -1132,12 +1551,7 @@ /* things that you can 'set' */ setitem : - K_FILENAME_WITH_MODE '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "filename_with_mode=0", TRUE); - else parse_str(user_conf_d, "filename_with_mode=1", TRUE); } - | K_FILENAME_WITH_MODE { parse_str(user_conf_d, "filename_with_mode=1", TRUE); } - | K_NOFILENAME_WITH_MODE { parse_str(user_conf_d, "filename_with_mode=0", TRUE); } - - | K_OVERLAP '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "overlap=0", TRUE); + K_OVERLAP '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "overlap=0", TRUE); else parse_str(user_conf_d, "overlap=1", TRUE); } | K_OVERLAP { parse_str(user_conf_d, "overlap=1", TRUE); } | K_INPUT_BAR_BOTTOM '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "input_bar_bottom=0", TRUE); @@ -1196,6 +1610,13 @@ { if ($3 == 0) parse_str(user_conf_d, "half_page_scroll=0", TRUE); else parse_str(user_conf_d, "half_page_scroll=1", TRUE); } | K_NOHALF_PAGE_SCROLL { parse_str(user_conf_d, "half_page_scroll=0", TRUE); } + + | K_IGNORE_HIDDEN { parse_str(user_conf_d, "ignore_hidden=1", TRUE); } + | K_IGNORE_HIDDEN '=' NUMBER + { if ($3 == 0) parse_str(user_conf_d, "ignore_hidden=0", TRUE); + else parse_str(user_conf_d, "ignore_hidden=1", TRUE); } + | K_NOIGNORE_HIDDEN { parse_str(user_conf_d, "ignore_hidden=0", TRUE); } + | K_QUIET '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "quiet=0", TRUE); else parse_str(user_conf_d, "quiet=1", TRUE); } @@ -1211,10 +1632,12 @@ { if ($3 == 0) parse_str(user_conf_d, "xlsx_readformulas=0", TRUE); else parse_str(user_conf_d, "xlsx_readformulas=1", TRUE); } | K_NOXLSX_READFORMULAS { parse_str(user_conf_d, "xlsx_readformulas=0", TRUE); } - | K_NOCURSES { parse_str(user_conf_d, "nocurses=1", TRUE); } - | K_NOCURSES '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "nocurses=0", TRUE); - else parse_str(user_conf_d, "nocurses=1", TRUE); } - | K_CURSES { parse_str(user_conf_d, "nocurses=0", TRUE); } + | K_NOCURSES { if (! session->cur_doc->loading) parse_str(user_conf_d, "nocurses=1", TRUE); } + | K_NOCURSES '=' NUMBER { if (! session->cur_doc->loading) { + if ($3 == 0) parse_str(user_conf_d, "nocurses=0", TRUE); + else parse_str(user_conf_d, "nocurses=1", TRUE); } + } + | K_CURSES { if (! session->cur_doc->loading) parse_str(user_conf_d, "nocurses=0", TRUE); } | K_NUMERIC { parse_str(user_conf_d, "numeric=1", TRUE); } | K_NUMERIC '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "numeric=0", TRUE); else parse_str(user_conf_d, "numeric=1", TRUE); } @@ -1262,6 +1685,14 @@ else parse_str(user_conf_d, "copy_to_clipboard_delimited_tab=1", TRUE); } | K_NOCOPY_TO_CLIPBOARD_DELIMITED_TAB { parse_str(user_conf_d, "copy_to_clipboard_delimited_tab=0", TRUE); } + | K_DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD '=' strarg { + char cmd[MAXCMD]; + char * s = (char *) $3; + sprintf(cmd, "default_open_file_under_cursor_cmd=%s", s); + parse_str(user_conf_d, cmd, FALSE); + scxfree(s); + } + | K_NEWLINE_ACTION '=' NUMBER { if ($3 == 0) parse_str(user_conf_d, "newline_action=0", TRUE); } | K_COMMAND_TIMEOUT { parse_str(user_conf_d, "command_timeout=3000", TRUE); } diff -Nru sc-im-0.8.2+ds/src/graph.c sc-im-0.8.3+ds/src/graph.c --- sc-im-0.8.2+ds/src/graph.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/graph.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,860 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file graph.c + * \author Andrés Martinelli + * \date 2021-04-29 + * \brief All the functions used to track cell dependencies + * + * \details This file contains all functions used for maintaining a + * dependence graph that keeps track of all the cells that depends on + * each other. This is done in a two way relationship. + * + * \details A vertex represents an ent and has in "edges", links to + * other vertex's(ents) which the first vertex depends on. + * + * \details The other relationship is "back_edges". This is a pointer + * to other vertex's and there you will keep linked all the vertex's that + * use the first vertex in their formulas. In other words, you will keep + * track of all the vertex's that depends on the first vertex. + * + * \details NOTE: an orphan vertex represents an ent that has an enode + * thats need to be evaluated, but do not depend in another cell. + */ + +#include +#include +#include +#include + +#include "graph.h" +#include "interp.h" +#include "tui.h" // for show_text +#include "sc.h" +#include "xmalloc.h" // for scxfree +#include "macros.h" +#include "trigger.h" + +extern jmp_buf fpe_save; +extern int cellerror; /* is there an error in this cell - TODO get rid of this */ + +#define CREATE_NEW(type) (type *) malloc(sizeof(type)) + +#define APPEND_TO_LINKLIST(firstNode, newNode, tempNode) \ + if( firstNode == NULL ) { \ + firstNode = newNode ; \ + } \ + else { \ + tempNode = firstNode; \ + while (tempNode->next != NULL) { \ + tempNode = tempNode->next; \ + } \ + tempNode->next = newNode; \ + } + +graphADT graph; /* Creates an empty graph, with no vertices. Allocate memory from the heap */ + +// used for saving dependencies of cells: +struct ent_ptr * deps = NULL; +int dep_size = 0; + +extern struct session * session; + +/************************************************************ + * These are the functions used for creating the depgraph + * **********************************************************/ + +/** + * \brief GraphCreate() + * \return An empty graph + */ +graphADT GraphCreate() { + graphADT emptyGraph = (graphCDT *) malloc(sizeof(graphCDT)); + emptyGraph->vertices = NULL; + return emptyGraph; +} + + +/** + * \brief GraphAddVertex + * \details This adds the vertex sorted in the list and not at the end. Given a row and + * column to insert as a new vertex, this function will create a new vertex + * with those values and add it in order to the list. + * \param[in] graph + * \param[in] struct sheet * + * \param[in] ent + * \return a pointer to the new vertex + */ +vertexT * GraphAddVertex(graphADT graph, struct sheet * sh, struct ent * ent) { + //if (ent == NULL) { + // sc_debug("add vertex- null ent"); + // return NULL; + //} + //sc_debug("will add vertex %d %d ", ent->row, ent->col); + vertexT * newVertex = (vertexT *) malloc(sizeof(vertexT)); + newVertex->visited = 0; + newVertex->eval_visited = 0; + newVertex->ent = ent; + newVertex->sheet = sh; + newVertex->edges = NULL; + newVertex->back_edges = NULL; + newVertex->next = NULL; + + vertexT * temp_ant = NULL; + vertexT * tempNode = NULL; + + // first element added to the list + if( graph->vertices == NULL) { + graph->vertices = newVertex; + + // append in first position + } else if ( + (sh->id < graph->vertices->sheet->id) || + (sh->id == graph->vertices->sheet->id && ent->row < graph->vertices->ent->row) || + (sh->id == graph->vertices->sheet->id && ent->row == graph->vertices->ent->row && ent->col < graph->vertices->ent->col) + ) { + newVertex->next = graph->vertices; + graph->vertices = newVertex; + + // append in second position or after that, keeping it ordered + } else { + tempNode = graph->vertices; + temp_ant = tempNode; + while (tempNode != NULL && ( + sh->id > tempNode->sheet->id || + (sh->id == tempNode->sheet->id && ent->row > tempNode->ent->row) || + (sh->id == tempNode->sheet->id && ent->row == tempNode->ent->row && ent->col > tempNode->ent->col))) { + temp_ant = tempNode; + tempNode = temp_ant->next; + } + temp_ant->next = newVertex; + newVertex->next = tempNode; + } + //sc_debug("Added vertex %d %d in the graph", ent->row, ent->col) ; + return newVertex; +} + + +/** + * \brief getVertex() + * + * \details This looks for a vertex representing a specific ent in + * a sorted list. We search for a vertex in graph and return it if + * found. If not found and create flag, we add add the vertex + * (malloc it) and return it. If not found, it returns NULL. + * + * \param[in] graph + * \param[in] ent + * \param[in] create + * + * \return vertex if found; NULL if not found + */ +vertexT * getVertex(graphADT graph, struct sheet * sh, struct ent * ent, int create) { + if (graph == NULL || ent == NULL || sh == NULL || (graph->vertices == NULL && !create)) return NULL; + vertexT * temp = graph->vertices; + //sc_debug("getVertex - looking for %d %d, create:%d", ent->row, ent->col, create); + while (temp != NULL + && + ((sh->id > temp->sheet->id) || + (sh->id == temp->sheet->id && ent->row > temp->ent->row) || + (sh->id == temp->sheet->id && ent->row == temp->ent->row && ent->col >= temp->ent->col) + ) ){ + //sc_debug("this vertex exists: %d %d", temp->ent->row, temp->ent->col); + if (temp->sheet == sh && temp->ent->row == ent->row && temp->ent->col == ent->col) { + //sc_debug("found vertex: %d %d", temp->ent->row, temp->ent->col); + return temp; + } + temp = temp->next; + } + //sc_debug("not found vertex: %d %d", ent->row, ent->col); + + + /* + * if we get to here, there is not vertex representing ent + * we add it if 'create' flag is set to true! + */ + return create ? GraphAddVertex(graph, sh, ent) : NULL; +} + + +/** + * \brief Add an edge to a graph + * \details This function adds an edge in out graph from the vertex "from" + * to the vertex "to". + * \return none + */ +void GraphAddEdge(vertexT * from, vertexT * to) { + if (from == NULL || to == NULL) { + sc_info("Error while adding edge: either of the vertices do not exist") ; + return; + } + // do we have to check this here? or shall we handle it outside from the caller? + markAllVerticesNotVisited(0); // needed to check if edge already exists + if (GraphIsReachable(from, to, 0)) { + //sc_info("Error while adding edge: the edge already exists! - %d %d - %d %d", from->ent->row, from->ent->col, to->ent->row, to->ent->col) ; + return; + } + + edgeT * newEdge = CREATE_NEW(edgeT) ; + newEdge->connectsTo = to; + newEdge->next = NULL; + edgeT * tempEdge = NULL; + APPEND_TO_LINKLIST(from->edges, newEdge, tempEdge); + //sc_info("Added the edge from %d %d to %d %d", from->row, from->col, to->row, to->col) ; + + // BACK APPEND + newEdge = CREATE_NEW(edgeT) ; + newEdge->connectsTo = from; + newEdge->next = NULL; + tempEdge = NULL; + APPEND_TO_LINKLIST(to->back_edges, newEdge, tempEdge); + //sc_info("Added BACK reference from %d %d to %d %d", to->row, to->col, from->row, from->col) ; + return; +} + + +/** + * \brief Iterate through all verticies and set visited to false + * + * Iterate through all verticies and set visited to false + * evalvisited + * + * \return none + */ +void markAllVerticesNotVisited (int eval_visited) { + vertexT * temp = graph->vertices; + while (temp != NULL) { + if (eval_visited) temp->eval_visited = 0; + else temp->visited = 0; + temp = temp->next; + } + return; +} + + +/** + * \brief Prints vertexes + * \return none + */ +void print_vertexs() { + char det[BUFFERSIZE] = ""; + if (graph == NULL) { + strcpy(det, "Graph is empty"); + ui_show_text((char *) &det); + return; + } + vertexT * temp = graph->vertices; + edgeT * etemp; + det[0]='\0'; + int msg_size = BUFFERSIZE; + char * msg = (char *) malloc(msg_size); + msg[0]='\0'; + strcpy(msg, "Content of graph:\n"); + + while (temp != NULL) { + sprintf(det + strlen(det), "sheet:{%s} vertex: %d %d vis:%d eval_vis:%d\n", temp->sheet->name, temp->ent->row, temp->ent->col, temp->visited, temp->eval_visited); + etemp = temp->edges; + + /* check not overflow msg size. if so, just realloc. */ + if (strlen(det) + strlen(msg) > msg_size) { + //sc_debug("realloc"), + msg_size += BUFFERSIZE; + msg = (char *) realloc(msg, msg_size); + } + sprintf(msg + strlen(msg), "%s", det); + det[0]='\0'; + /**/ + while (etemp != NULL) { + sprintf(det + strlen(det), " \\-> depends on the following ents: {%s} %d %d\n", etemp->connectsTo->sheet->name, etemp->connectsTo->ent->row, etemp->connectsTo->ent->col); + etemp = etemp->next; + + /* check not overflow msg size. if so, just realloc. */ + if (strlen(det) + strlen(msg) > msg_size) { + msg_size += BUFFERSIZE; + msg = (char *) realloc(msg, msg_size); + } + sprintf(msg + strlen(msg), "%s", det); + det[0]='\0'; + /**/ + } + etemp = temp->back_edges; + while (etemp != NULL) { + sprintf(det + strlen(det), "(back_edges) edges that depend on that ent: \\-> {%s} %d %d\n", etemp->connectsTo->sheet->name, etemp->connectsTo->ent->row, etemp->connectsTo->ent->col); + etemp = etemp->next; + + /* check not overflow msg size. if so, just realloc. */ + if (strlen(det) + strlen(msg) > msg_size) { + msg_size += BUFFERSIZE; + msg = (char *) realloc(msg, msg_size); + } + sprintf(msg + strlen(msg), "%s", det); + det[0]='\0'; + /**/ + } + temp = temp->next; + } + ui_show_text((char *) msg); + free(msg); + return; +} + + +/** + * \brief Destroy a vertex + * + * \details This function frees the memory of vertex's edges. This also + * frees the vertex itself, but only if it has no back_dependences. The + * only parameter is an int pointer. + * + * \param[in] ent + * + * \return none + */ +void destroy_vertex(struct sheet * sh, struct ent * ent) { + if (graph == NULL || ent == NULL) return; + //sc_debug("destroying vertex %d %d", ent->row, ent->col); + + vertexT * v_prev, * v_cur = graph->vertices; + + // if is in the middle of the list + if (v_cur->ent->row != ent->row || v_cur->ent->col != ent->col || v_cur->sheet != sh) { + if (v_cur->ent == NULL) sc_error("ERROR destroying vertex"); + v_prev = v_cur; + v_cur = v_cur->next; + //while (v_cur != NULL && (v_cur->ent->row < ent->row || (v_cur->ent->row == ent->row && v_cur->ent->col <= ent->col))) { + while (v_cur != NULL) { + if (v_cur->ent->row == ent->row && v_cur->ent->col == ent->col && v_cur->sheet == sh) break; + v_prev = v_cur; + v_cur = v_cur->next; + } + if (v_cur->ent->row != ent->row || v_cur->ent->col != ent->col || v_cur->sheet != sh) { + sc_error("Error while destroying a vertex. Vertex not found! Please rebuild graph"); + return; + } + v_prev->next = v_cur->next; + } + + /*FIXME + // for each edge in back_edges, we look for the reference to the vertex we are deleting, and we erase it! + edgeT * e2 = v_cur->back_edges; + while (e2 != NULL) { + // sc_debug("back_edge: we follow %d %d", e2->connectsTo->ent->row, e2->connectsTo->ent->col); + delete_reference(v_cur, e2->connectsTo, 0); + e2 = e2->next; + }*/ + + // for each edge in edges, we look for the reference to the vertex we are deleting, and we erase it! + edgeT * e = v_cur->edges; + if (v_cur->back_edges == NULL) + while (e != NULL && v_cur->back_edges == NULL) { + // sc_debug("edge: we follow %d %d", e->connectsTo->ent->row, e->connectsTo->ent->col); + delete_reference(v_cur, e->connectsTo, 1); + + // delete vertex only if it end up having no edges, no expression, no value, no label.... + if (e->connectsTo->edges == NULL && e->connectsTo->back_edges == NULL && !e->connectsTo->ent->expr && !(e->connectsTo->ent->flags & is_valid) && ! e->connectsTo->ent->label) + destroy_vertex(e->connectsTo->sheet, e->connectsTo->ent); + // WARNING: an orphan vertex now represents an ent that has an enode thats + // need to be evaluated, but do not depends on another cell. + e = e->next; + } + + destroy_list_edges(v_cur->edges); + v_cur->edges = NULL; + + destroy_list_edges(v_cur->back_edges); + v_cur->back_edges = NULL; + + // if vertex to free was the first one.. + if (graph->vertices && graph->vertices->ent->row == ent->row && graph->vertices->ent->col == ent->col && graph->vertices->sheet == sh) + graph->vertices = v_cur->next; + + free(v_cur); + return; +} + + +/** + * \brief TODO Write brief function description + * + * \details For each edge in edges, we look for the references to the + * vertex we are deleting and we erase it! + * + * \details v_cur is the reference. + * + * \details If back_reference is set, the delete is done over the + * back_edges list. If not, it is done over edges list. + * + * \param[in] v_cur + * \param[in] tc + * \param[in] back_reference + * + * \return none + */ +void delete_reference(vertexT * v_cur, vertexT * vc, int back_reference) { + if (v_cur == NULL || vc == NULL) return; + //sc_debug("we follow %d %d", vc->ent->row, vc->ent->col); + + // If v_cur is in the first position of back_edge list of vc + if (back_reference && vc->back_edges->connectsTo == v_cur) { + edgeT * e_cur = vc->back_edges; + vc->back_edges = e_cur->next; + free(e_cur); + return; + // If v_cur is in the first position of edge list of vc + } else if (! back_reference && vc->edges->connectsTo == v_cur) { + edgeT * e_cur = vc->edges; + vc->edges = e_cur->next; + free(e_cur); + return; + } + + // If v_cur is not in the first position + edgeT * eb = back_reference ? vc->back_edges : vc->edges; + edgeT * e_prev = eb; + edgeT * e_cur = eb->next; + while (e_cur != NULL && e_cur->connectsTo != v_cur) { + e_prev = e_cur; + e_cur = e_cur->next; + } + if (e_cur != NULL && e_cur->connectsTo == v_cur) { + e_prev->next = e_cur->next; + free(e_cur); + } + return; +} + + +/** + * \brief Free memory of an edge and its linked edges + * \return none + */ +void destroy_list_edges(edgeT * e) { + if (e == NULL) return; + edgeT * e_next, * e_cur = e; + + while (e_cur != NULL) { + e_next = e_cur->next; + e_cur->connectsTo = NULL; + free(e_cur); + e_cur = e_next; + } + return; +} + + +/** + * \brief Free the memory of a graph + * \param[in] graph + * \return none + */ +void destroy_graph(graphADT graph) { + if (graph == NULL) return; + + vertexT * v_next, * v_cur = graph->vertices; + while (v_cur != NULL) { + v_next = v_cur->next; + if (v_cur->edges != NULL) destroy_list_edges(v_cur->edges); + if (v_cur->back_edges != NULL) destroy_list_edges(v_cur->back_edges); + free(v_cur); + v_cur = v_next; + } + free(graph); + return; +} + +/** + * \brief All_vertexs_of_edges_visited + * \details Used in EvalBottomUp and GraphIsReachable + * \return int + */ +int All_vertexs_of_edges_visited(struct edgeTag * e, int eval_visited) { + struct edgeTag * edges = e; + while (edges != NULL) { + //sc_debug("1 r:%d c:%d visited:%d", edges->connectsTo->ent->row, edges->connectsTo->ent->col, edges->connectsTo->eval_visited); + if (eval_visited && ! edges->connectsTo->eval_visited) return 0; + else if (!eval_visited && ! edges->connectsTo->visited) return 0; + edges = edges->next; + } + return 1; +} + + +/************************************************************************************************* + * dependency functions + *************************************************************************************************/ +/** + * \brief ents_that_depends_on() + * \details get the list of ents that depends on an specific ent + * it adds the ents in "deps" variable, and reallocs as neccesary + * \param[in] struct sheet * sh + * \param[in] struct ent * ent + * \return none + */ +void ents_that_depends_on(struct sheet * sh, struct ent * ent) { + if (graph == NULL) return; + vertexT * v = getVertex(graph, sh, ent, 0); + if (v == NULL || v->visited) return; + + struct edgeTag * edges = v->back_edges; + while (edges != NULL) { + deps = (struct ent_ptr *) realloc(deps, sizeof(struct ent_ptr) * (++dep_size)); + deps[0].vf = dep_size; // we always keep size of list in the first position ! + //sc_debug("sheet:%s %d %d - dependency on:%s %d %d", sh->name, ent->row, ent->col, edges->connectsTo->sheet->name, edges->connectsTo->ent->row, edges->connectsTo->ent->col); + deps[dep_size-1].vp = lookat(edges->connectsTo->sheet, edges->connectsTo->ent->row, edges->connectsTo->ent->col); + deps[dep_size-1].sheet = edges->connectsTo->sheet; // we should save the sheet asociated with the ent as well + ents_that_depends_on(edges->connectsTo->sheet, edges->connectsTo->ent); + edges->connectsTo->visited = 1; + edges = edges->next; + } + return; +} + +/** + * \brief GraphIsReachable + * \details This method returns if a vertex called dest is reachable + * from the vertex called src (if back_dep is set to false). If back_dep + * is set to true, the relationship is evaluated in the opposite way. + * + * \param[in] src + * \param[out] dest + * \param[in] back_dep + * + * \return 1 true or 0 false + */ +int GraphIsReachable(vertexT * src, vertexT * dest, int back_dep) { + if (src == dest) { + return 1; + } else if (src->visited) { + return 0; + } else { + // visit all edges of vertexT * src + src->visited = 1; + + edgeT * tempe; + if ( ! back_dep ) + tempe = src->edges; + else + tempe = src->back_edges; + + while (tempe != NULL) { + if ( ! GraphIsReachable(tempe->connectsTo, dest, back_dep)) { + tempe = tempe->next; + } else { + return 1; + } + } + } + return 0; +} + +/** + * \brief ents_that_depends_on_range() + * + * \details Checks dependency of a range of ents. + * Keep the ents references in "deps" lists. + * + * \param[in] struct sheet * sh + * \param[in] r1 + * \param[in] c1 + * \param[in] r2 + * \param[in] c2 + * + * \return none + */ +void ents_that_depends_on_range(struct sheet * sh, int r1, int c1, int r2, int c2) { + if (graph == NULL) return; + + int r, c; + struct ent * p; + + // at this point deps must be NULL + deps = NULL; + dep_size = 0; + + for (r = r1; r <= r2; r++) { + for (c = c1; c <= c2; c++) { + markAllVerticesNotVisited(0); + p = *ATBL(sh, sh->tbl, r, c); + if (p == NULL) continue; + ents_that_depends_on(sh, p); + } + } + return; +} + + +/** + * \brief ents_that_depends_on_list() + * \details Checks dependency of list of ents. + * + * since this is used for pasting yanked ents, on which we may + * have a difference on rows and columns on which the cells are pasted + * we take care of it with deltar and deltac + * + * \param[in] struct ent * (e_ori) + * \param[in] deltar + * \param[in] deltac + * + * \return none + */ +void ents_that_depends_on_list(struct ent_ptr * e_ori, int deltar, int deltac) { + struct ent_ptr * e = e_ori; + struct ent * p; + if (graph == NULL || e == NULL) return; + + // at this point deps must be NULL + deps = NULL; + dep_size = 0; + + while (e != NULL) { + struct sheet * sh = e->sheet; + // update sheet to current sheet if is null (a sheet was deleted) + if (sh == NULL) sh = session->cur_doc->cur_sh; + p = *ATBL(sh, sh->tbl, e->vp->row+deltar, e->vp->col+deltac); + if (p != NULL) { + markAllVerticesNotVisited(0); + ents_that_depends_on(sh, p); + } + e = e->next; + } + return; +} + +/** + * \brief rebuild_graph() + * \details Rebuild entire graph and eval from top left to bottom right. + * \return none + */ +void rebuild_graph() { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->first_sh; + struct ent * p; + int first, second, fb, gb; + + destroy_graph(graph); + graph = GraphCreate(); + + while (sh != NULL) { + fb = calc_order == BYROWS ? sh->maxrow : sh->maxcol; + gb = calc_order == BYROWS ? sh->maxcol : sh->maxrow; + for (first = 0; first <= fb; first++) + for (second = 0; second <= gb; second++) { + p = *ATBL(sh, sh->tbl, calc_order == BYROWS ? first : second, calc_order == BYROWS ? second : first); + if (p && p->expr) { + EvalJustOneVertex(sh, p, 1); + //sc_debug("Expr %d %d", p->row, p->col); + } + } + sh = sh->next; + } + return; +} + +/************************************************************ + * Here we have the depgraph evaluation functions + * **********************************************************/ + +/** + * \brief Eval the entire depgraph + * \return none + */ +void EvalAll() { + EvalBottomUp(); + return; +} + + +/** + * \brief EvalBottomUp the entire dep graph + * It operates bottom up. + * \return none + */ +void EvalBottomUp() { + //print_vertexs(); + vertexT * temp = graph->vertices; + struct ent * p; + + markAllVerticesNotVisited(1); + int evalDone = 0; + + while (temp != NULL) { + //sc_debug("analizo %d %d", temp->ent->row, temp->ent->col); + if ( ! temp->eval_visited && (temp->edges == NULL || All_vertexs_of_edges_visited(temp->edges, 1))) { + //sc_debug("visito %d %d", temp->ent->row, temp->ent->col); + + if ((p = *ATBL(temp->sheet, temp->sheet->tbl, temp->ent->row, temp->ent->col)) && p->expr) { + EvalJustOneVertex(temp->sheet, temp->ent, 0); + } + temp->eval_visited = 1; + evalDone = 1; + } + temp = temp->next; + if (temp == NULL) { + //sc_debug("temp is null. evaldone: %d", evalDone); + if (! evalDone) return; + evalDone = 0; + temp = graph->vertices; + } + } + return; +} + + +/** + * \brief EvalRange + * \details Given a range of cells look up for their vertexs in the depgraph and Eval them. + * It also handles the cells that depends on the range and reeval those as well. + * \return none + */ +void EvalRange(struct sheet * sh, int tlrow, int tlcol, int brrow, int brcol) { + if (session->cur_doc->loading) return; + extern struct ent_ptr * deps; + extern int dep_size; + int i, fa, fb, ga, gb, first, second; + struct ent * e, * f; + + if (calc_order == BYROWS) + fa = tlrow, fb = brrow, ga = tlcol, gb = brcol; + else + fa = tlcol, fb = brcol, ga = tlrow, gb = brrow; + + for (first = fa; first <= fb; first++) { + for (second = ga; second <= gb; second++) { + // eval the cell + e = *ATBL(sh, sh->tbl, calc_order == BYROWS ? first : second, calc_order == BYROWS ? second : first); + + if (!e) continue; + if (e->expr) EvalJustOneVertex(sh, e, 0); + + // eval the dependencies + markAllVerticesNotVisited(0); + if (deps != NULL) free(deps); + deps = NULL; + dep_size = 0; + ents_that_depends_on(sh, e); + + for (i = 0; deps != NULL && i < deps->vf; i++) { + f = *ATBL(deps[i].sheet, deps[i].sheet->tbl, deps[i].vp->row, deps[i].vp->col); + if (f == NULL || ! f->expr) continue; + EvalJustOneVertex(sh, f, 0); + } + if (deps != NULL) free(deps); + deps = NULL; + } + } + + return; +} + + +/** + * \brief EvalAllVertexs + * \details Eval all vertexs of graph in the order that they were added + * >>>>> NO LONGER IN USE + * \return none + */ +void EvalAllVertexs() { + struct ent * p; + //(void) signal(SIGFPE, eval_fpe); + vertexT * temp = graph->vertices; + //int i = 0; + while (temp != NULL) { + //sc_debug("Evaluating cell %d %d: %d", temp->ent->row, temp->ent->col, ++i); + if ((p = *ATBL(temp->sheet, temp->sheet->tbl, temp->ent->row, temp->ent->col)) && p->expr) + EvalJustOneVertex(temp->sheet, p, 0); + temp = temp->next; + } + //(void) signal(SIGFPE, exit_app); +} + + +/** + * \brief Evaluate just one vertex + * \param[in] p + * \param[in] i + * \param[in] j + * \param[in] rebuild_graph + * \return none + */ +void EvalJustOneVertex(struct sheet * sh, struct ent * p, int rebuild_graph) { + int i = p->row; + int j = p->col; + + gmyrow=i; gmycol=j; + + if (p->flags & is_strexpr) { + char * v; + if (setjmp(fpe_save)) { + sc_error("Floating point exception %s", v_name(i, j)); + cellerror = CELLERROR; + v = ""; + } else { + cellerror = CELLOK; + v = rebuild_graph ? seval(sh, p, p->expr) : seval(sh, NULL, p->expr); + } + p->cellerror = cellerror; + if ( !v && !p->label) /* Everything's fine */ + return; + if ( !p->label || !v || strcmp(v, p->label) != 0 || cellerror) { + p->flags |= is_changed; + } + if (p->label) + scxfree(p->label); + p->label = v; + } else { + double v; + if (setjmp(fpe_save)) { + sc_error("Floating point exception %s", v_name(i, j)); + cellerror = CELLERROR; + v = (double) 0.0; + } else { + cellerror = CELLOK; + v = rebuild_graph ? eval(sh, p, p->expr) : eval(sh, NULL, p->expr); + + if (cellerror == CELLOK && ! isfinite(v)) + cellerror = CELLERROR; + } + if ((cellerror != p->cellerror) || (v != p->v)) { + p->cellerror = cellerror; + p->v = v; + p->flags |= is_changed | is_valid; + if (( p->trigger ) && ((p->trigger->flag & TRG_WRITE) == TRG_WRITE)) + do_trigger(p, TRG_WRITE); + } + } +} diff -Nru sc-im-0.8.2+ds/src/graph.h sc-im-0.8.3+ds/src/graph.h --- sc-im-0.8.2+ds/src/graph.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/graph.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file dep_graph.h + * \author Andrés Martinelli + * \date 2017-07-18 + * \brief Header file for dep_graph.c + */ + +#include "sc.h" + +typedef struct vertexTag { + struct ent * ent; + struct sheet * sheet; + int visited; + int eval_visited; // just to not to collide with previous. its used in EvalBottomUp. + struct edgeTag * edges; + struct edgeTag * back_edges; + struct vertexTag * next; +} vertexT; + +/* For each edge, we need a link to the vertex it connects to and a link to the next edge w.r.t source vertex */ +typedef struct edgeTag { + vertexT * connectsTo; + struct edgeTag * next; +} edgeT; + +typedef struct graphCDT { + vertexT * vertices; +} graphCDT; + +typedef struct graphCDT * graphADT; + + +graphADT GraphCreate(); +vertexT * GraphAddVertex(graphADT graph , struct sheet * sh, struct ent * ent); +vertexT * getVertex(graphADT graph, struct sheet * sh, struct ent * ent, int create); +void GraphAddEdge(vertexT * from, vertexT * to); +void print_vertexs(); + +void destroy_list_edges(edgeT * e); +void destroy_graph (graphADT graph); +void destroy_vertex(struct sheet * sh, struct ent * ent); +void delete_reference(vertexT * v_cur, vertexT * vc, int back_reference); + +void markAllVerticesNotVisited(int eval_visited); +void ents_that_depends_on(struct sheet * sh, struct ent * ent); +void ents_that_depends_on_range(struct sheet * sh, int r1, int c1, int r2, int c2); +void ents_that_depends_on_list(struct ent_ptr * e_ori, int deltar, int deltac); +int GraphIsReachable(vertexT * src, vertexT * dest, int back_dep); +void rebuild_graph(); + +void EvalAll(); +void EvalBottomUp(); +void EvalAllVertexs(); +void EvalRange(struct sheet * sh, int tlrow, int tlcol, int brrow, int brcol); +void EvalJustOneVertex(struct sheet * sh, struct ent * p, int rebuild_graph); diff -Nru sc-im-0.8.2+ds/src/help.c sc-im-0.8.3+ds/src/help.c --- sc-im-0.8.2+ds/src/help.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/help.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -37,6 +37,8 @@ /** * \file help.c + * \details this page handles the help page but also the + * show_version_and_quit and show_usage_and_quit functions * \author Andrés Martinelli * \date 2017-07-18 * \brief Help functions @@ -57,6 +59,7 @@ #include "help.h" #include "conf.h" + static char ** long_help; static int delta = 0; static int max; @@ -160,8 +163,10 @@ wclrtoeol(input_pad); ui_refresh_pad(0); + wbkgd(main_win, COLOR_PAIR((ucolors[DEFAULT].fg+1) * (COLORS) + ucolors[DEFAULT].bg + 2)); ui_set_ucolor(main_win, &ucolors[NORMAL], DEFAULT_COLOR); + ui_set_ucolor(input_win, &ucolors[NORMAL], DEFAULT_COLOR); wtimeout(input_win, -1); noecho(); curs_set(0); @@ -169,6 +174,7 @@ int option; + keypad(input_win, 1); while( ! quit_help_now ) { option = show_lines(); @@ -290,7 +296,7 @@ if (d == OKEY_ENTER && strlen(word_looked)) { find_word(word_looked, 'f'); } - mvwprintw(input_win, 0, 0, ""); + wmove(input_win, 0,0); wclrtoeol(input_win); wrefresh(input_win); curs_set(0); @@ -435,3 +441,160 @@ void help() { } #endif + + + + +extern struct dictionary * user_conf_d; /* User's configuration dictionary */ +extern struct session * session; +#include +#include "utils/dictionary.h" +#include "macros.h" +#include "version.h" + +/** + * \brief Send the version number to standard output and quit. + * \return none + * TODO Split this into two commands. One prints the version number + * the other prints the version number along with the other information. + */ +void show_version_and_quit() { + put(user_conf_d, "nocurses", "1"); + sc_info("sc-im - %s", rev); +#ifdef NCURSES + sc_info("-DNCURSES"); +#endif +#ifdef MAXROWS + sc_info("-DMAXROWS %d", MAXROWS); +#endif +#ifdef UNDO + sc_info("-DUNDO"); +#endif +#ifdef XLS + sc_info("-DXLS"); +#endif +#ifdef XLSX + sc_info("-DXLSX"); +#endif +#ifdef XLSX_EXPORT + sc_info("-DXLSX_EXPORT"); +#endif +#ifdef XLUA + sc_info("-DXLUA"); +#endif +#ifdef DEFAULT_COPY_TO_CLIPBOARD_CMD + sc_info("-DDEFAULT_COPY_TO_CLIPBOARD_CMD=\"%s\"", DEFAULT_COPY_TO_CLIPBOARD_CMD); +#endif +#ifdef DEFAULT_PASTE_FROM_CLIPBOARD_CMD + sc_info("-DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\"%s\"", DEFAULT_PASTE_FROM_CLIPBOARD_CMD); +#endif +#ifdef DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD + sc_info("-DDEFAULT_OPEN_FILE_UNDER_CURSOR_CMD=\"%s\"", DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD); +#endif +#ifdef USELOCALE + sc_info("-DUSELOCALE"); +#endif +#ifdef MOUSE + sc_info("-DMOUSE"); +#endif +#ifdef USECOLORS + sc_info("-DUSECOLORS"); +#endif +#ifdef _XOPEN_SOURCE_EXTENDED + sc_info("-D_XOPEN_SOURCE_EXTENDED"); +#endif +#ifdef _GNU_SOURCE + sc_info("-D_GNU_SOURCE"); +#endif +#ifdef SNAME + sc_info("-DSNAME=\"%s\"", SNAME); +#endif +#ifdef HELP_PATH + sc_info("-DHELP_PATH=\"%s\"", HELP_PATH); +#endif +#ifdef LIBDIR + sc_info("-DLIBDIR=\"%s\"", LIBDIR); +#endif +#ifdef DFLT_PAGER + sc_info("-DDFLT_PAGER=\"%s\"", DFLT_PAGER); +#endif +#ifdef DFLT_EDITOR + sc_info("-DDFLT_EDITOR=\"%s\"", DFLT_EDITOR); +#endif +#ifdef CONFIG_DIR + sc_info("-DCONFIG_DIR=\"%s\"", CONFIG_DIR); +#endif +#ifdef CONFIG_FILE + sc_info("-DCONFIG_FILE=\"%s\"", CONFIG_FILE); +#endif +#ifdef HISTORY_DIR + sc_info("-DHISTORY_DIR=\"%s\"", HISTORY_DIR); +#endif +#ifdef HISTORY_FILE + sc_info("-DHISTORY_FILE=\"%s\"", HISTORY_FILE); +#endif +#ifdef INS_HISTORY_FILE + sc_info("-DINS_HISTORY_FILE=\"%s\"", INS_HISTORY_FILE); +#endif +#ifdef HAVE_PTHREAD + sc_info("-DHAVE_PTHREAD"); +#endif +#ifdef AUTOBACKUP + sc_info("-DAUTOBACKUP"); +#endif + put(user_conf_d, "quit_afterload", "1"); +} + + +/** + * \brief Print usage message to stdout text and quit + * \return none + */ + // NOTE this is a quick and dirty command to search for arguments used in the sources (macOS 10.14) + // grep "get_conf_value(\"" -r ./src/*.c | grep get_conf_value |sed 's/"//g' |sed 's/.*get_conf_value(//g'|cut -d ')' -f1 |sort|uniq|sed 's/^/--/g' +void show_usage_and_quit(){ + put(user_conf_d, "nocurses", "1"); + printf("\ +\nsc-im - sc-improvised\ +\n\ +\nUsage: sc-im [arguments] [file] specified file\ +\n or: sc-im [arguments] - read text from stdin\ +\n\ +\nArguments:\ +\n\ +\n --autocalc Set variable 'autocalc'.\ +\n --copy_to_clipboard_delimited_tab Set variable 'copy_to_clipboard_delimited_tab'\ +\n --debug Set variable 'debug'\ +\n --default_copy_to_clipboard_cmd=COMMAND set variable 'default_copy_from_clipboard_cmd'\ +\n --default_paste_from_clipboard_cmd=COMMAND set variable 'default_paste_from_clipboard_cmd'\ +\n --default_open_file_under_cursor_cmd=COMMAND set variable 'default_open_file_under_cursor_cmd'\ +\n --export_csv Export to csv without interaction\ +\n --export_tab Export to tab without interaction\ +\n --export_txt Export to txt without interaction\ +\n --export_mkd Export to markdown without interaction\ +\n --external_functions Set variable 'external_functions'\ +\n --half_page_scroll Set variable 'half_page_scroll'\ +\n --ignorecase Set variable 'ignorecase'\ +\n --import_delimited_as_text Import text as\ +\n --newline_action={j or l} Set variable 'newline_action'\ +\n --nocurses Run interactive but without ncurses interface.\ +\n --numeric Set variable 'numeric'\ +\n --numeric_decimal Set variable 'numeric_decimal'\ +\n --output=FILE Save the results in FILE\ +\n --overlap Set variable 'overlap variable'\ +\n --quit_afterload Quit after loading all the files\ +\n --show_cursor Make the screen cursor follow the active cell\ +\n --tm_gmtoff={seconds} set gmt offset used for converting datetimes to localtime.\ +\n --txtdelim={\",\" or \";\" or \"\\t\" or \"|\"} Sets delimiter when opening a .tab of .csv file"); +#ifdef XLSX + printf("\n\ +\n --sheet=SHEET Open SHEET when loading xlsx file. Default is 1.\ +\n --xlsx_readformulas Set variable 'xlsx_readformulas'"); +#endif + printf("\n\ +\n --version Print version information and exit\ +\n --help Print Help (this message) and exit\n"); + put(user_conf_d, "quit_afterload", "1"); +} + +char * rev = "version 0.8.3"; diff -Nru sc-im-0.8.2+ds/src/help.h sc-im-0.8.3+ds/src/help.h --- sc-im-0.8.2+ds/src/help.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/help.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/hide_show.c sc-im-0.8.3+ds/src/hide_show.c --- sc-im-0.8.2+ds/src/hide_show.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/hide_show.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,249 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file hide_show.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include - -#include "sc.h" -#include "macros.h" -#include "tui.h" -#include "hide_show.h" -#include "conf.h" -#include "vmtbl.h" // for growtbl - -#ifdef UNDO -#include "undo.h" -extern struct undo undo_item; -#endif - -/** - * \brief Mark a row as hidden - * - * \param[in] from_row - * \param[in] arg - * - * \return none - */ - -void hide_row(int from_row, int arg) { - register int r2; - - r2 = from_row + arg - 1; - if (from_row < 0 || from_row > r2) { - sc_error("Cannot hide row: Invalid range."); - return; - } - if (r2 >= maxrows - 1) { - // error: tried to hide a row higher than maxrow. - lookat(from_row + arg + 1, curcol); //FIXME this HACK - if (! growtbl(GROWROW, arg + 1, 0)) { - sc_error("You can't hide the last row"); - return; - } - } - - if (! loading) { - modflg++; - #ifdef UNDO - create_undo_action(); - undo_hide_show(from_row, -1, 'h', arg); - end_undo_action(); - #endif - } - while ( from_row <= r2) - row_hidden[ from_row++ ] = TRUE; - return; -} - -/** - * \brief Mark a column as hidden - * - * \param[in] from_col - * \param[in] arg - * - * \return none - */ - -void hide_col(int from_col, int arg) { - int c2 = from_col + arg - 1; - if (from_col < 0 || from_col > c2) { - sc_error ("Cannot hide col: Invalid range."); - return; - } - if (c2 >= maxcols - 1) { - // sc_error: tried to hide a column higher than maxcol. - lookat(currow, from_col + arg + 1); //FIXME this HACK - if ((arg >= ABSMAXCOLS - 1) || ! growtbl(GROWCOL, 0, arg + 1)) { - sc_error("You can't hide the last col"); - return; - } - } - - if (! loading) { - modflg++; - #ifdef UNDO - create_undo_action(); - create_undo_action(); - create_undo_action(); - undo_hide_show(-1, from_col, 'h', arg); - end_undo_action(); - #endif - } - while (from_col <= c2) - col_hidden[ from_col++ ] = TRUE; - return; -} - -/** - * \brief Mark a row as not-hidden - * - * \param[in] from_row - * \param[in] arg - * - * \return none - */ - -void show_row(int from_row, int arg) { - int r2 = from_row + arg - 1; - if (from_row < 0 || from_row > r2) { - sc_error ("Cannot show row: Invalid range."); - return; - } - if (r2 > maxrows - 1) { - r2 = maxrows - 1; - } - - modflg++; - #ifdef UNDO - create_undo_action(); - #endif - while (from_row <= r2) { - #ifdef UNDO - if ( row_hidden[from_row] ) undo_hide_show(from_row, -1, 's', 1); - #endif - row_hidden[ from_row++ ] = FALSE; - } - #ifdef UNDO - end_undo_action(); - #endif - return; -} - -/** - * \brief Mark a column as not-hidden - * - * \param[in] from_col - * \param[in] arg - * - * \return none - */ - -void show_col(int from_col, int arg) { - int c2 = from_col + arg - 1; - if (from_col < 0 || from_col > c2) { - sc_error ("Cannot show col: Invalid range."); - return; - } - if (c2 > maxcols - 1) { - c2 = maxcols - 1; - } - - modflg++; - #ifdef UNDO - create_undo_action(); - #endif - while (from_col <= c2) { - #ifdef UNDO - if ( col_hidden[from_col] ) undo_hide_show(-1, from_col, 's', 1); - #endif - col_hidden[ from_col++ ] = FALSE; - } - #ifdef UNDO - end_undo_action(); - #endif - return; -} - -/** - * \brief TODO Document show_hiddenrows - * - * \return none - */ - -void show_hiddenrows() { - int r, c = 0; - for (r = 0; r < maxrow; r++) { - if (row_hidden[r]) c++; - } - char valores[12 * c + 20]; - valores[0]='\0'; - strcpy(valores, "Hidden rows:\n"); // 20 - for (r = 0; r < maxrow; r++) { - if (row_hidden[r]) sprintf(valores + strlen(valores), "- %d\n", r); // 12 - } - ui_show_text(valores); - - return; -} - -/** - * \brief TODO Document show_hiddencols - * - * \return none - */ - -void show_hiddencols() { - int c, count = 0; - for (c = 0; c < maxcol; c++) { - if (col_hidden[c]) count++; - } - char valores[8 * c + 20]; - valores[0]='\0'; - strcpy(valores, "Hidden cols:\n"); // 20 - for (c = 0; c < maxcol; c++) { - if (col_hidden[c]) sprintf(valores + strlen(valores), "- %s\n", coltoa(c)); // 8 - } - ui_show_text(valores); - - return; -} diff -Nru sc-im-0.8.2+ds/src/hide_show.h sc-im-0.8.3+ds/src/hide_show.h --- sc-im-0.8.2+ds/src/hide_show.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/hide_show.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file hide_show.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file hide_show.c - */ - -void hide_row(int from_row, int arg); -void hide_col(int from_col, int arg); -void show_row(int from_row, int arg); -void show_col(int from_col, int arg); -void show_hiddenrows(); -void show_hiddencols(); diff -Nru sc-im-0.8.2+ds/src/history.c sc-im-0.8.3+ds/src/history.c --- sc-im-0.8.2+ds/src/history.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/history.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/history.h sc-im-0.8.3+ds/src/history.h --- sc-im-0.8.2+ds/src/history.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/history.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/input.c sc-im-0.8.3+ds/src/input.c --- sc-im-0.8.2+ds/src/input.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/input.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -52,11 +52,11 @@ #include "main.h" #include "tui.h" #include "maps.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "history.h" #include "conf.h" #include "utils/string.h" -#include "cmds_visual.h" +#include "cmds/cmds_visual.h" #include "buffer.h" #include "digraphs.h" @@ -124,8 +124,9 @@ } #endif - if ( d == OKEY_ESC || d == ctl('g')) { + if ( (d == OKEY_ESC || d == ctl('g')) && curmode != EDIT_MODE) { break_waitcmd_loop(buffer); + ui_clr_header(1); ui_show_header(); return; } @@ -196,7 +197,7 @@ fix_timeout(&start_tv); // to handle map of ESC - if ( buffer->value == OKEY_ESC || buffer->value == ctl('g')) { + if ( (buffer->value == OKEY_ESC || buffer->value == ctl('g')) && curmode != EDIT_MODE) { break_waitcmd_loop(buffer); ui_print_mult_pend(); ui_refresh_pad(0); diff -Nru sc-im-0.8.2+ds/src/input.h sc-im-0.8.3+ds/src/input.h --- sc-im-0.8.2+ds/src/input.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/input.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/interp.c sc-im-0.8.3+ds/src/interp.c --- sc-im-0.8.2+ds/src/interp.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/interp.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -36,21 +36,20 @@ *******************************************************************************/ /** - * \file intrep.c + * \file interp.c * \author Andrés Martinelli - * \date 2021-04-28 - * \brief TODO Write a tbrief file description. + * \date 24/05/2021 + * \brief source file that implements the eval seval functions + * Based on SC * * \details Expression interpreter and assorted support routines - * Based on SC * \details Original by James Gosling, September 1982 * \details Modified by Mark Weiser and Bruce Israel, University of Maryland * \details More mods Robert Bond, 12/86 - * \details More mods by Alan Silverstein, 3-4/88, see list of changes. + * \details More mods by Alan Silverstein, 3-4/88. */ #include -#include #include #include #include @@ -60,903 +59,61 @@ #include #include #include - #ifdef IEEE_MATH #include #endif #include "sc.h" #include "macros.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "format.h" #include "conf.h" #include "tui.h" #include "range.h" -#include "xmalloc.h" // for scxfree -#include "lex.h" // for atocol -#include "interp.h" -#include "utils/string.h" -#include "trigger.h" - -#ifdef XLUA -#include "lua.h" -#endif - -#ifdef UNDO -#include "undo.h" -#endif - -void exit_app(); - -/* g_type can be: */ -#define G_NONE 0 /* Starting value - must be 0 */ -#define G_NUM 1 -#define G_STR 2 -#define G_NSTR 3 -#define G_XSTR 4 -#define G_CELL 5 - -/* Use this structure to save the last 'g' command */ -struct go_save gs = { .g_type = G_NONE } ; - -#define ISVALID(r,c) ((r)>=0 && (r)=0 && (c)e.o.left) - 1; - c = minc + (int) eval(NULL, val->e.o.right) - 1; - } - if (c <= maxc && c >=minc && r <= maxr && r >=minr) - p = *ATBL(tbl, r, c); - - if (p && p->label) { - pr = scxmalloc((size_t) (strlen(p->label) + 1)); - (void) strcpy(pr, p->label); - if (p->cellerror) - cellerror = CELLINVALID; - return (pr); - } else - return ((char *) 0); -} - - -/** - * \brief doascii() - * \param[in] s - * \return double - */ -double doascii(char * s) { - double v = 0.; - int i ; - if ( !s ) return ((double) 0); - - for (i = 0; s[i] != '\0' ; v = v*256 + (unsigned char)(s[i++]) ) ; - scxfree(s); - return(v); -} - - -/** - * \brief doindex() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] val - * - * \return double - */ -double doindex(int minr, int minc, int maxr, int maxc, struct enode * val) { - int r, c; - register struct ent * p; - - if (val->op == ',') { /* index by both row and column */ - r = minr + (int) eval(NULL, val->e.o.left) - 1; - c = minc + (int) eval(NULL, val->e.o.right) - 1; - } else if (minr == maxr) { /* look along the row */ - r = minr; - c = minc + (int) eval(NULL, val) - 1; - } else if (minc == maxc) { /* look down the column */ - r = minr + (int) eval(NULL, val) - 1; - c = minc; - } else { - sc_error("Improper indexing operation"); - return (double) 0; - } - - if (c <= maxc && c >=minc && r <= maxr && r >=minr && - (p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) - cellerror = CELLINVALID; - return p->v; - } else - return (double) 0; -} - -/** - * \brief dolookup() - * - * \param[in] val - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] offset - * \param[in] vflag - * - * \return double - */ -double dolookup(struct enode * val, int minr, int minc, int maxr, int maxc, int offset, int vflag) { - double v, ret = (double) 0; - int r, c; - register struct ent * p = (struct ent *) 0; - int incr, incc, fndr, fndc; - char * s; - - incr = vflag; incc = 1 - vflag; - if (etype(val) == NUM) { - cellerror = CELLOK; - v = eval(NULL, val); - for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) { - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->v <= v) { - fndr = incc ? (minr + offset) : r; - fndc = incr ? (minc + offset) : c; - if (ISVALID(fndr, fndc)) - if (p == NULL) // three lines added - cellerror = CELLINVALID; - else // useful when the lookup ends up in a cell with no value - p = *ATBL(tbl, fndr, fndc); - else { - sc_error(" range specified to @[hv]lookup"); - cellerror = CELLERROR; - } - if (p && p->flags & is_valid) { - if (p->cellerror) - cellerror = CELLINVALID; - ret = p->v; - } - } else break; - } - } - } else { - cellerror = CELLOK; - s = seval(NULL, val); - for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) { - if ((p = *ATBL(tbl, r, c)) && p->label) { - if (s && strcmp(p->label,s) == 0) { - fndr = incc ? (minr + offset) : r; - fndc = incr ? (minc + offset) : c; - if (ISVALID(fndr,fndc)) { - p = *ATBL(tbl, fndr, fndc); - if (p->cellerror) - cellerror = CELLINVALID; - } else { - sc_error(" range specified to @[hv]lookup"); - cellerror = CELLERROR; - } - break; - } - } - } - if (p && p->flags & is_valid) - ret = p->v; - if (s != NULL) scxfree(s); - } - return ret; -} - - -/** - * \brief docount() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * - * \return double - */ -double docount(int minr, int minc, int maxr, int maxc, struct enode * e) { - int v; - int r, c; - int cellerr = CELLOK; - register struct ent *p; - - v = 0; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if (!e || eval(NULL, e)) - // the following changed for #430. docount should also count cells with strings. not just numbers - // TODO: create @counta to count both, and leave @count for just numbers - if ((p = *ATBL(tbl, r, c)) && (p->flags & is_valid || p->label) ) { - if (p->cellerror) cellerr = CELLINVALID; - v++; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - return v; -} - - -/** - * \brief dosum() - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * \return double - */ -double dosum(int minr, int minc, int maxr, int maxc, struct enode * e) { - double v; - int r, c; - int cellerr = CELLOK; - register struct ent * p; - - v = (double)0; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if ( !e || eval(NULL, e)) - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) - cellerr = CELLINVALID; - v += p->v; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - return v; -} - -/** - * \brief doprod() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * - * \return double - */ -double doprod(int minr, int minc, int maxr, int maxc, struct enode * e) { - double v; - int r, c; - int cellerr = CELLOK; - register struct ent * p; - - v = 1; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if ( !e || eval(NULL, e)) - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) cellerr = CELLINVALID; - v *= p->v; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - return v; -} - - -/** - * \brief doavg() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * - * \return double - */ -double doavg(int minr, int minc, int maxr, int maxc, struct enode * e) { - double v; - int r, c; - int count; - int cellerr = CELLOK; - register struct ent * p; - - v = (double) 0; - count = 0; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if (!e || eval(NULL, e)) - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) cellerr = CELLINVALID; - v += p->v; - count++; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - - if (count == 0) return ((double)0); - - return (v / (double)count); -} - -/** - * \brief dostddev() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * - * \return double - */ -double dostddev(int minr, int minc, int maxr, int maxc, struct enode * e) { - double lp, rp, v, nd; - int r, c; - int n; - int cellerr = CELLOK; - register struct ent * p; - - n = 0; - lp = 0; - rp = 0; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if (!e || eval(NULL, e)) - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) cellerr = CELLINVALID; - v = p->v; - lp += v*v; - rp += v; - n++; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - - if ((n == 0) || (n == 1)) return ((double)0); - nd = (double) n; - return ( sqrt((nd*lp-rp*rp) / (nd*(nd-1))) ); -} - -/** - * \brief domax() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * - * \return double - */ -double domax(int minr, int minc, int maxr, int maxc, struct enode * e) { - double v = (double) 0; - int r, c; - int count; - int cellerr = CELLOK; - register struct ent * p; - - count = 0; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if (!e || eval(NULL, e)) - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) cellerr = CELLINVALID; - - if (! count) { - v = p->v; - count++; - } else if (p->v > v) - v = p->v; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - - if (count == 0) return ((double)0); - - return (v); -} - - -/** - * \brief domin() - * - * \param[in] minr - * \param[in] minc - * \param[in] maxr - * \param[in] maxc - * \param[in] e - * - * \return double - */ -double domin(int minr, int minc, int maxr, int maxc, struct enode * e) { - double v = (double)0; - int r, c; - int count; - int cellerr = CELLOK; - register struct ent * p; - - count = 0; - for (r = minr; r <= maxr; r++) - for (c = minc; c <= maxc; c++) { - if (e) { - rowoffset = r - minr; - coloffset = c - minc; - } - if (!e || eval(NULL, e)) - if ((p = *ATBL(tbl, r, c)) && p->flags & is_valid) { - if (p->cellerror) cellerr = CELLINVALID; - if (! count) { - v = p->v; - count++; - } else if (p->v < v) - v = p->v; - } - } - cellerror = cellerr; - rowoffset = coloffset = 0; - - if (count == 0) return ((double) 0); - - return (v); -} - - -int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - -/** - * \brief dodts() - * \param[in] e1 - * \param[in] e2 - * \param[in] e3 - * \return double - */ -double dodts(int e1, int e2, int e3) { - int yr, mo, day; - time_t secs; - struct tm t; - - if (e2 > 12 || e3 > 31) { - mo = e1; - day = e2; - yr = e3; - } else { - yr = e1; - mo = e2; - day = e3; - } - mdays[1] = 28 + (yr % 4 == 0) - (yr % 100 == 0) + (yr % 400 == 0); - - t.tm_hour = t.tm_min = t.tm_sec = 0; - t.tm_mon = --mo; - t.tm_mday = day; - t.tm_year = yr -= 1900; - t.tm_isdst = -1; - - if (mo < 0 || mo > 11 || day < 1 || day > mdays[mo] || (secs = mktime(&t)) == -1) { - sc_error("@dts: invalid argument or date out of range"); - cellerror = CELLERROR; - return (0.0); - } - - return ((double) secs); -} - - -/** - * \brief dotts() - * \param[in] hr - * \param[in] min - * \param[in] sec - * \return double - */ -double dotts(int hr, int min, int sec) { - if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) { - sc_error ("@tts: Invalid argument"); - cellerror = CELLERROR; - return ((double) 0); - } - return ((double) (sec + min * 60 + hr * 3600)); -} - - -/** - * \brief dorow() - * \param[in] ep - * \return double - */ -double dorow(struct enode * ep) { - return (double) ep->e.v.vp->row; -} - - -/** - * \brief docol() - * - * \param[in] ep - * - * \return double - */ -double docol(struct enode * ep) { - return (double) ep->e.v.vp->col; -} - - -/** - * \brief dotime() - * - * \param[in] which - * \param[in] when - * - * \return double - */ -double dotime(int which, double when) { - static time_t t_cache; - static struct tm tm_cache; - struct tm *tp; - time_t tloc; - - if (which == NOW) - return (double) time(NULL); - - tloc = (time_t)when; - - if (tloc != t_cache) { - tp = localtime(&tloc); - tm_cache = *tp; - tm_cache.tm_mon += 1; - tm_cache.tm_year += 1900; - t_cache = tloc; - } - - switch (which) { - case HOUR: return ((double)(tm_cache.tm_hour)); - case MINUTE: return ((double)(tm_cache.tm_min)); - case SECOND: return ((double)(tm_cache.tm_sec)); - case MONTH: return ((double)(tm_cache.tm_mon)); - case DAY: return ((double)(tm_cache.tm_mday)); - case YEAR: return ((double)(tm_cache.tm_year)); - } - /* Safety net */ - cellerror = CELLERROR; - return ((double)0); -} - - -/** - * \brief doston() - * \param[in] s - * \return double - */ -double doston(char * s) { - double v; - - if ( !s ) return ((double)0); - - v = strtod(s, NULL); - scxfree(s); - return(v); -} - - -/** - * \brief doevaluate(): take a char * with a formula and eval it - * \param[in] s - * \return double - */ -double doevaluate(char * s) { - if ( !s) return ((double)0); - wchar_t cline [BUFFERSIZE]; - swprintf(cline, BUFFERSIZE, L"eval %s", s); - send_to_interp(cline); - double d = eval_result; - scxfree(s); - return (double) d; -} - - -/** - * \brief doslen() - * \param[in] s - * \return int - */ -int doslen(char * s) { - if (!s) return 0; - - //int i = strlen(s); - int i = 0; - - wchar_t widestring[BUFFERSIZE] = { L'\0' }; - const char * mbsptr = s; - size_t result = mbsrtowcs(widestring, &mbsptr, BUFFERSIZE, NULL); - if ( result != (size_t) -1 ) i = wcslen(widestring); - scxfree(s); - return i; -} - - -/** - * \brief doeqs() - * - * \param[in] s1 - * \param[in] s2 - * - * \return double - */ -double doeqs(char * s1, char * s2) { - double v; - - if ( !s1 && !s2 ) return ((double)1.0); - - if ( !s1 || !s2 ) - v = 0.0; - else if (strcmp(s1, s2) == 0) - v = 1.0; - else - v = 0.0; - - if (s1) scxfree(s1); - - if (s2) scxfree(s2); - - return(v); -} - - -/** - * \brief getent() - * - * \details Given a string representing a column name and a value which - * is a row number, return a pointer to the selected cell's entry. - * if alloc == 0 and no cell is alloc, return NULL. - * Use only the integer part of the column number. Always - * free the string - * - * \param[in] colstr - * \param[in] rwodoub - * - * \return struct ent * - */ -struct ent * getent(char *colstr, double rowdoub, int alloc) { - int collen; /* length of string */ - int row, col; /* integer values */ - struct ent *p = (struct ent *) 0; /* selected entry */ - - if (!colstr) { - cellerror = CELLERROR; - return ((struct ent *) 0); - } - collen = strlen(colstr); - col = atocol(colstr, collen); - row = (int) floor(rowdoub); - - if (row >= 0 - && (row < maxrows) /* in range */ - && (collen <= 2) /* not too long */ - && (col >= 0) - && (col < maxcols)) { /* in range */ - if (alloc) p = lookat(row, col); - else p = *ATBL(tbl, row, col); - if ((p != NULL) && p->cellerror) cellerror = CELLINVALID; - } - scxfree(colstr); - return (p); -} - +#include "xmalloc.h" // for scxfree +#include "lex.h" // for atocol +#include "function.h" +#include "interp.h" +#include "utils/string.h" +#include "trigger.h" +#ifdef XLUA +#include "lua.h" +#endif +#ifdef UNDO +#include "undo.h" +#endif +#include "graph.h" -/** - * \brief donval() - * - * \details Given a string representing a column name and a value which is a - * column number, return the selected cell's numeric value, if any. - * - * \param[in] colstr - * \param[in] rowdoub - * - * \return double - */ -double donval(char * colstr, double rowdoub) { - struct ent * ep; - return (((ep = getent(colstr, rowdoub, 0)) && ((ep->flags) & is_valid)) ? (ep->v) : (double)0); -} +extern int find_range(char * name, int len, struct ent * lmatch, struct ent * rmatch, struct range ** rng); +extern bool decimal; /* Set if there was a decimal point in the number */ +extern struct session * session; +extern graphADT graph; +extern WINDOW * input_win; +void exit_app(); +double fn1_eval (double (* fn)(), double arg); +double fn2_eval (double (* fn)(), double arg1, double arg2); +int constant (struct enode * e); +void copydbuf (int deltar, int deltac); +void decompile (struct enode * e, int priority); +void index_arg (char * s, struct enode * e); +void list_arg (char * s, struct enode * e); +void one_arg (char * s, struct enode * e); +void range_arg (char * s, struct enode * e); +void three_arg (char * s, struct enode * e); +void two_arg (char * s, struct enode * e); +void two_arg_index (char * s, struct enode * e); -/** - * \brief dolmax() - * - * \details The list routines (e.g. dolmax) are called with an LMAX - * enode. The left pointer is a chain of ELIST nodes, the right - * pointer is a value. - * - * \param[in] e - * \param[in] ep - * - * \return double - */ -double dolmax(struct ent * e, struct enode * ep) { - register int count = 0; - register double maxval = 0; /* Assignment to shut up lint */ - register struct enode * p; - register double v; +int exprerr; /* Set by eval() and seval() if expression errors */ +double prescale = 1.0; /* Prescale for constants in let() */ +int gmyrow = -1, gmycol = -1; /* globals used to implement @myrow, @mycol cmds */ +int rowoffset = 0, coloffset = 0; /* row & col offsets for range functions */ +jmp_buf fpe_save; +int cellerror = CELLOK; /**< is there an error in this cell */ - cellerror = CELLOK; - for (p = ep; p; p = p->e.o.left) { - v = eval(e, p->e.o.right); - if ( !count || v > maxval) { - maxval = v; - count++; - } - } - if (count) return maxval; - else return (double)0; -} +struct go_save gs = { .g_type = G_NONE }; /* Use this structure to save the last 'g' command */ -/** - * \brief dolmin() - * \param[in] e - * \param[in] ep - * \return double - */ -double dolmin(struct ent * e, struct enode * ep) { - register int count = 0; - register double minval = 0; /* Assignment to shut up lint */ - register struct enode * p; - register double v; - - cellerror = CELLOK; - for (p = ep; p; p = p->e.o.left) { - v = eval(e, p->e.o.right); - if ( !count || v < minval) { - minval = v; - count++; - } - } - if (count) return minval; - else return (double)0; -} +/***********************************************************************************************/ /** * \brief eval() @@ -964,29 +121,30 @@ * \param[in] e * \return double */ -double eval(register struct ent * ent, register struct enode * e) { -// //if (cellerror == CELLERROR || (ent && ent->cellerror == CELLERROR)) { -// if (cellerror == CELLERROR) { -// return (double) 0; -// } +double eval(struct sheet * sh, struct ent * ent, struct enode * e) { + +// if (cellerror == CELLERROR || (ent && ent->cellerror == CELLERROR)) { +// if (cellerror == CELLERROR) { +// return (double) 0; +// } if (e == (struct enode *) 0) { cellerror = CELLINVALID; return (double) 0; } switch (e->op) { - case '+': return (eval(ent, e->e.o.left) + eval(ent, e->e.o.right)); + case '+': return (eval(sh, ent, e->e.o.left) + eval(sh, ent, e->e.o.right)); case '-': { double l, r; - l = eval(ent, e->e.o.left); - r = eval(ent, e->e.o.right); + l = eval(sh, ent, e->e.o.left); + r = eval(sh, ent, e->e.o.right); return l - r; } - case '*': return (eval(ent, e->e.o.left) * eval(ent, e->e.o.right)); + case '*': return (eval(sh, ent, e->e.o.left) * eval(sh, ent, e->e.o.right)); case '/': { double num, denom; - num = eval(ent, e->e.o.left); - denom = eval(ent, e->e.o.right); + num = eval(sh, ent, e->e.o.left); + denom = eval(sh, ent, e->e.o.right); if (cellerror) { cellerror = CELLINVALID; return ((double) 0); @@ -1000,8 +158,8 @@ } case '%': { double num, denom; - num = floor(eval(ent, e->e.o.left)); - denom = floor(eval(ent, e->e.o.right)); + num = floor(eval(sh, ent, e->e.o.left)); + denom = floor(eval(sh, ent, e->e.o.right)); if (denom) return (num - floor(num/denom)*denom); else { @@ -1009,35 +167,35 @@ return ((double) 0); } } - case '^': return (fn2_eval(pow,eval(ent, e->e.o.left),eval(ent, e->e.o.right))); - case '<': return (eval(ent, e->e.o.left) < eval(ent, e->e.o.right)); + case '^': return (fn2_eval(pow,eval(sh, ent, e->e.o.left),eval(sh, ent, e->e.o.right))); + case '<': return (eval(sh, ent, e->e.o.left) < eval(sh, ent, e->e.o.right)); case '=': { double l, r; - l = eval(ent, e->e.o.left); - r = eval(ent, e->e.o.right); + l = eval(sh, ent, e->e.o.left); + r = eval(sh, ent, e->e.o.right); return (l == r); } - case '>': return (eval(ent, e->e.o.left) > eval(ent, e->e.o.right)); - case '&': return (eval(ent, e->e.o.left) && eval(ent, e->e.o.right)); - case '|': return (eval(ent, e->e.o.left) || eval(ent, e->e.o.right)); + case '>': return (eval(sh, ent, e->e.o.left) > eval(sh, ent, e->e.o.right)); + case '&': return (eval(sh, ent, e->e.o.left) && eval(sh, ent, e->e.o.right)); + case '|': return (eval(sh, ent, e->e.o.left) || eval(sh, ent, e->e.o.right)); case IF: - case '?': return eval(ent, e->e.o.left) ? eval(ent, e->e.o.right->e.o.left) - : eval(ent, e->e.o.right->e.o.right); - case 'm': return (-eval(ent, e->e.o.left)); + case '?': return eval(sh, ent, e->e.o.left) ? eval(sh, ent, e->e.o.right->e.o.left) + : eval(sh, ent, e->e.o.right->e.o.right); + case 'm': return (-eval(sh, ent, e->e.o.left)); case 'f': { int rtmp = rowoffset; int ctmp = coloffset; double ret; rowoffset = coloffset = 0; - ret = eval(ent, e->e.o.left); + ret = eval(sh, ent, e->e.o.left); rowoffset = rtmp; coloffset = ctmp; return (ret); } - case 'F': return (eval(ent, e->e.o.left)); - case '!': return (eval(ent, e->e.o.left) == 0.0); - case ';': return (((int) eval(ent, e->e.o.left) & 7) + - (((int) eval(ent, e->e.o.right) & 7) << 3)); + case 'F': return (eval(sh, ent, e->e.o.left)); + case '!': return (eval(sh, ent, e->e.o.left) == 0.0); + case ';': return (((int) eval(sh, ent, e->e.o.left) & 7) + + (((int) eval(sh, ent, e->e.o.right) & 7) << 3)); case O_CONST: if (! isfinite(e->e.k)) { @@ -1046,18 +204,18 @@ cellerror = CELLERROR; } // Changed 06/03/2021 for #issue 499 - if (ent && ent->expr != NULL && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); + if (ent && ent->expr != NULL && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); return (e->e.k); case GETENT: ; - int r = eval(ent, e->e.o.left); - int c = eval(ent, e->e.o.right); + int r = eval(sh, ent, e->e.o.left); + int c = eval(sh, ent, e->e.o.right); if (r < 0 || c < 0) { sc_debug("@getent shouldnt be called with negative parameters %d %d", r, c); return (double) 0; } - struct ent * vp = *ATBL(tbl, r, c); + struct ent * vp = *ATBL(sh, sh->tbl, r, c); if (ent && vp && ent->row == vp->row && ent->col == vp->col) { sc_error("Circular reference in eval (cell %s%d)", coltoa(vp->col), vp->row); e->op = ERR_; @@ -1066,27 +224,30 @@ cellerror = CELLERROR; return (double) 0; } - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - if (ent && vp) GraphAddEdge(getVertex(graph, lookat(ent->row, ent->col), 1), getVertex(graph, lookat(vp->row, vp->col), 1)); + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + if (ent && vp) GraphAddEdge(getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), getVertex(graph, sh, lookat(sh, vp->row, vp->col), 1)); if (vp && vp->flags & is_valid) return (vp->v); return (double) 0; case O_VAR: { struct ent * vp = e->e.v.vp; + struct sheet * sh_vp = e->e.v.sheet; + if (sh_vp == NULL) sh_vp = sh; //sc_debug("var %d %d", vp->row, vp->col); - if (vp && ent && vp->row == ent->row && vp->col == ent->col && !(vp->flags & is_deleted) ) { + //if (vp && ent && vp->row == ent->row && vp->col == ent->col && !(vp->flags & is_deleted) ) { + if (vp && ent && vp == ent && !(vp->flags & is_deleted) ) { sc_error("Circular reference in eval (cell %s%d)", coltoa(vp->col), vp->row); //ERR propagates. comment to make it not to. cellerror = CELLERROR; //ent->cellerror = CELLERROR; - GraphAddEdge( getVertex(graph, lookat(ent->row, ent->col), 1), getVertex(graph, lookat(vp->row, vp->col), 1) ) ; + GraphAddEdge( getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), getVertex(graph, sh_vp, lookat(sh_vp, vp->row, vp->col), 1) ) ; return (double) 0; } if (vp && vp->cellerror == CELLERROR && !(vp->flags & is_deleted)) { // here we store the dependences in a graph - if (ent && vp) GraphAddEdge( getVertex(graph, lookat(ent->row, ent->col), 1), - getVertex(graph, lookat(vp->row, vp->col), 1) ) ; + if (ent && vp) GraphAddEdge( getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), + getVertex(graph, sh_vp, lookat(sh_vp, vp->row, vp->col), 1) ) ; //does not change reference to @err in expression //uncomment to do so @@ -1101,8 +262,8 @@ if (vp && (rowoffset || coloffset)) { row = e->e.v.vf & FIX_ROW ? vp->row : vp->row + rowoffset; col = e->e.v.vf & FIX_COL ? vp->col : vp->col + coloffset; - checkbounds(&row, &col); - vp = *ATBL(tbl, row, col); + checkbounds(sh, &row, &col); + vp = *ATBL(sh_vp, sh_vp->tbl, row, col); } @@ -1122,8 +283,8 @@ // here we store the dependences in a graph if (ent && vp) { - vertexT * v_ent = getVertex(graph, lookat(ent->row, ent->col), 0); - vertexT * v_vp = getVertex(graph, lookat(vp->row, vp->col), 0); + vertexT * v_ent = getVertex(graph, sh, lookat(sh, ent->row, ent->col), 0); + vertexT * v_vp = getVertex(graph, sh_vp, lookat(sh_vp, vp->row, vp->col), 0); if (v_ent != NULL && v_vp != NULL && GraphIsReachable(v_ent, v_vp, 1)) { sc_error("Circular reference in eval (cell %s%d)", coltoa(vp->col), vp->row); e->op = ERR_; @@ -1132,7 +293,7 @@ cellerror = CELLERROR; return (double) 0; } - GraphAddEdge( getVertex(graph, lookat(ent->row, ent->col), 1), getVertex(graph, lookat(vp->row, vp->col), 1) ) ; + GraphAddEdge( getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), getVertex(graph, sh_vp, lookat(sh_vp, vp->row, vp->col), 1) ) ; } if (vp->cellerror) { @@ -1166,44 +327,43 @@ if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - for (row=minr; row <= maxr; row++) { + for (row=minr; ent != NULL && row <= maxr; row++) { for (col=minc; col <= maxc; col++) { - if (ent == NULL) continue; if (ent->row == row && ent->col == col) { sc_error("Circular reference in eval (cell %s%d)", coltoa(col), row); e->op = ERR_; cellerror = CELLERROR; return (double) 0; } - GraphAddEdge(getVertex(graph, lookat(ent->row, ent->col), 1), getVertex(graph, lookat(row, col), 1)); + GraphAddEdge(getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), getVertex(graph, sh, lookat(sh, row, col), 1)); } } switch (e->op) { case LOOKUP: - return dolookup(e->e.o.right, minr, minc, maxr, maxc, 1, minc==maxc); + return dolookup(sh, e->e.o.right, minr, minc, maxr, maxc, 1, minc==maxc); case HLOOKUP: - return dolookup(e->e.o.right->e.o.left, minr,minc,maxr,maxc, - (int) eval(ent, e->e.o.right->e.o.right), 0); + return dolookup(sh, e->e.o.right->e.o.left, minr,minc,maxr,maxc, + (int) eval(sh, ent, e->e.o.right->e.o.right), 0); case VLOOKUP: - return dolookup(e->e.o.right->e.o.left, minr,minc,maxr,maxc, - (int) eval(ent, e->e.o.right->e.o.right), 1); + return dolookup(sh, e->e.o.right->e.o.left, minr,minc,maxr,maxc, + (int) eval(sh, ent, e->e.o.right->e.o.right), 1); case INDEX: - return doindex(minr, minc, maxr, maxc, e->e.o.right); + return doindex(sh, minr, minc, maxr, maxc, e->e.o.right); case SUM: - return dosum(minr, minc, maxr, maxc, e->e.o.right); + return dosum(sh, minr, minc, maxr, maxc, e->e.o.right); case PROD: - return doprod(minr, minc, maxr, maxc, e->e.o.right); + return doprod(sh, minr, minc, maxr, maxc, e->e.o.right); case AVG: - return doavg(minr, minc, maxr, maxc, e->e.o.right); + return doavg(sh, minr, minc, maxr, maxc, e->e.o.right); case COUNT: - return docount(minr, minc, maxr, maxc, e->e.o.right); + return docount(sh, minr, minc, maxr, maxc, e->e.o.right); case STDDEV: - return dostddev(minr, minc, maxr, maxc, e->e.o.right); + return dostddev(sh, minr, minc, maxr, maxc, e->e.o.right); case MAX: - return domax(minr, minc, maxr, maxc, e->e.o.right); + return domax(sh, minr, minc, maxr, maxc, e->e.o.right); case MIN: - return domin(minr, minc, maxr, maxc, e->e.o.right); + return domin(sh, minr, minc, maxr, maxc, e->e.o.right); } } case REDUCE | 'R': @@ -1222,42 +382,42 @@ case REDUCE | 'C': return (maxc - minc + 1); } } - case ABS: return (fn1_eval( fabs, eval(ent, e->e.o.left))); + case ABS: return (fn1_eval( fabs, eval(sh, ent, e->e.o.left))); case FROW: - eval(ent, e->e.o.left); + eval(sh, ent, e->e.o.left); return (dorow(e->e.o.left)); case FCOL: - eval(ent, e->e.o.left); + eval(sh, ent, e->e.o.left); return (docol(e->e.o.left)); - case ACOS: return (fn1_eval( acos, eval(ent, e->e.o.left))); - case ASIN: return (fn1_eval( asin, eval(ent, e->e.o.left))); - case ATAN: return (fn1_eval( atan, eval(ent, e->e.o.left))); - case ATAN2: return (fn2_eval( atan2, eval(ent, e->e.o.left), eval(ent, e->e.o.right))); - case CEIL: return (fn1_eval( ceil, eval(ent, e->e.o.left))); - case COS: return (fn1_eval( cos, eval(ent, e->e.o.left))); - case EXP: return (fn1_eval( exp, eval(ent, e->e.o.left))); - case FABS: return (fn1_eval( fabs, eval(ent, e->e.o.left))); - case FLOOR: return (fn1_eval( floor, eval(ent, e->e.o.left))); - case HYPOT: return (fn2_eval( hypot, eval(ent, e->e.o.left), eval(ent, e->e.o.right))); - case LOG: return (fn1_eval( log, eval(ent, e->e.o.left))); - case LOG10: return (fn1_eval( log10, eval(ent, e->e.o.left))); - case POW: return (fn2_eval( pow, eval(ent, e->e.o.left), eval(ent, e->e.o.right))); - case SIN: return (fn1_eval( sin, eval(ent, e->e.o.left))); - case SQRT: return (fn1_eval( sqrt, eval(ent, e->e.o.left))); - case TAN: return (fn1_eval( tan, eval(ent, e->e.o.left))); - case DTR: return (dtr(eval(ent, e->e.o.left))); - case RTD: return (rtd(eval(ent, e->e.o.left))); + case ACOS: return (fn1_eval( acos, eval(sh, ent, e->e.o.left))); + case ASIN: return (fn1_eval( asin, eval(sh, ent, e->e.o.left))); + case ATAN: return (fn1_eval( atan, eval(sh, ent, e->e.o.left))); + case ATAN2: return (fn2_eval( atan2, eval(sh, ent, e->e.o.left), eval(sh, ent, e->e.o.right))); + case CEIL: return (fn1_eval( ceil, eval(sh, ent, e->e.o.left))); + case COS: return (fn1_eval( cos, eval(sh, ent, e->e.o.left))); + case EXP: return (fn1_eval( exp, eval(sh, ent, e->e.o.left))); + case FABS: return (fn1_eval( fabs, eval(sh, ent, e->e.o.left))); + case FLOOR: return (fn1_eval( floor, eval(sh, ent, e->e.o.left))); + case HYPOT: return (fn2_eval( hypot, eval(sh, ent, e->e.o.left), eval(sh, ent, e->e.o.right))); + case LOG: return (fn1_eval( log, eval(sh, ent, e->e.o.left))); + case LOG10: return (fn1_eval( log10, eval(sh, ent, e->e.o.left))); + case POW: return (fn2_eval( pow, eval(sh, ent, e->e.o.left), eval(sh, ent, e->e.o.right))); + case SIN: return (fn1_eval( sin, eval(sh, ent, e->e.o.left))); + case SQRT: return (fn1_eval( sqrt, eval(sh, ent, e->e.o.left))); + case TAN: return (fn1_eval( tan, eval(sh, ent, e->e.o.left))); + case DTR: return (dtr(eval(sh, ent, e->e.o.left))); + case RTD: return (rtd(eval(sh, ent, e->e.o.left))); case RND: if (rndtoeven) - return rint(eval(ent, e->e.o.left)); + return rint(eval(sh, ent, e->e.o.left)); else { - double temp = eval(ent, e->e.o.left); + double temp = eval(sh, ent, e->e.o.left); return (temp - floor(temp) < 0.5 ? floor(temp) : ceil(temp)); } case ROUND: { - int precision = (int) eval(ent, e->e.o.right); + int precision = (int) eval(sh, ent, e->e.o.right); double scale = 1; if (0 < precision) do scale *= 10; while (0 < --precision); @@ -1265,9 +425,9 @@ do scale /= 10; while (++precision < 0); if (rndtoeven) - return (rint(eval(ent, e->e.o.left) * scale) / scale); + return (rint(eval(sh, ent, e->e.o.left) * scale) / scale); else { - double temp = eval(ent, e->e.o.left); + double temp = eval(sh, ent, e->e.o.left); temp *= scale; /* xxx */ /* @@ -1280,514 +440,125 @@ } case FV: case PV: - case PMT: return (finfunc(e->op, eval(ent, e->e.o.left), eval(ent, e->e.o.right->e.o.left), eval(ent, e->e.o.right->e.o.right))); - case HOUR: return (dotime(HOUR, eval(ent, e->e.o.left))); - case MINUTE: return (dotime(MINUTE, eval(ent, e->e.o.left))); - case SECOND: return (dotime(SECOND, eval(ent, e->e.o.left))); - case MONTH: return (dotime(MONTH, eval(ent, e->e.o.left))); - case DAY: return (dotime(DAY, eval(ent, e->e.o.left))); - case YEAR: return (dotime(YEAR, eval(ent, e->e.o.left))); + case PMT: return (finfunc(e->op, eval(sh, ent, e->e.o.left), eval(sh, ent, e->e.o.right->e.o.left), eval(sh, ent, e->e.o.right->e.o.right))); + case HOUR: return (dotime(HOUR, eval(sh, ent, e->e.o.left))); + case MINUTE: return (dotime(MINUTE, eval(sh, ent, e->e.o.left))); + case SECOND: return (dotime(SECOND, eval(sh, ent, e->e.o.left))); + case MONTH: return (dotime(MONTH, eval(sh, ent, e->e.o.left))); + case DAY: return (dotime(DAY, eval(sh, ent, e->e.o.left))); + case YEAR: return (dotime(YEAR, eval(sh, ent, e->e.o.left))); case NOW: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); return (dotime(NOW, (double) 0.0)); - case DTS: return (dodts((int) eval(ent, e->e.o.left), - (int)eval(ent, e->e.o.right->e.o.left), - (int)eval(ent, e->e.o.right->e.o.right))); - case TTS: return (dotts((int) eval(ent, e->e.o.left), - (int)eval(ent, e->e.o.right->e.o.left), - (int)eval(ent, e->e.o.right->e.o.right))); - - case EVALUATE: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return doevaluate(seval(ent, e->e.o.left)); - - case STON: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return (doston(seval(ent, e->e.o.left))); - - case ASCII: return (doascii(seval(ent, e->e.o.left))); - - case SLEN: return (doslen(seval(ent, e->e.o.left))); - - case EQS: return (doeqs(seval(ent, e->e.o.right), seval(ent, e->e.o.left))); - - case LMAX: return dolmax(ent, e); - - case LMIN: return dolmin(ent, e); - - case NVAL: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - char * s = seval(ent, e->e.o.left); - if (! s) { return (double) (0); } - char * sf = calloc(strlen(s)+1, sizeof(char)); - strcpy(sf, s); - double n = eval(ent, e->e.o.right); - struct ent * ep = getent(sf, n, 1); - if (! ep) { free(s); return (double) (0); } - if (ent && ep) GraphAddEdge(getVertex(graph, lookat(ent->row, ent->col), 1), getVertex(graph, ep, 1)); - return donval(s, n); - - case MYROW: - // if @myrow is called before EvallJustOneVertex - // (this might happen during startup when loading file) - // gmyrow does not happen to have valid value. handle that. - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return (gmyrow == -1 ? (ent ? ent->row + rowoffset : (double) currow + rowoffset) : (double) (gmyrow + rowoffset)); - - case MYCOL: - // if @mycol is called before EvallJustOneVertex - // (this might happen during startup when loading file) - // gmycol does not happen to have valid value. handle that. - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return (gmycol == -1 ? (ent ? ent->col + coloffset : (double) curcol + coloffset) : (double) (gmycol + coloffset)); - - case LASTROW: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return ((double) maxrow); - - case LASTCOL: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return ((double) maxcol); - - case ERR_: - cellerror = CELLERROR; - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return ((double) 0); - - case REF_: - cellerror = CELLREF; - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return ((double) 0); - - case PI_: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return ((double) M_PI); - - case BLACK: return ((double) COLOR_BLACK); - case RED: return ((double) COLOR_RED); - case GREEN: return ((double) COLOR_GREEN); - case YELLOW: return ((double) COLOR_YELLOW); - case BLUE: return ((double) COLOR_BLUE); - case MAGENTA: return ((double) COLOR_MAGENTA); - case CYAN: return ((double) COLOR_CYAN); - case WHITE: return ((double) COLOR_WHITE); - case DEFAULT_COLOR: return ((double) DEFAULT_COLOR); - case FACT: - { - double total = eval(ent, e->e.o.left); - int i; - for (i = eval(ent, e->e.o.left) - 1; i > 0; i--) { - total *= i; - } - return total > 0 ? total : 1; - } - default: sc_error ("Illegal numeric expression"); - exprerr = 1; - } - cellerror = CELLERROR; - return ((double) 0.0); -} - -/* - * \brief TODO Document eval_fpe() - * \return none - */ -void eval_fpe() { /* Trap for FPE errors in eval */ -#if defined(i386) - sc_debug("eval_fpe i386"); - asm(" fnclex"); - asm(" fwait"); -#else - #ifdef IEEE_MATH - (void)fpsetsticky((fp_except)0); /* Clear exception */ - #endif /* IEEE_MATH */ -#endif - /* re-establish signal handler for next time */ - (void) signal(SIGFPE, eval_fpe); - longjmp(fpe_save, 1); -} - -/** - * \brief fn1_eval() - * \param[in] fn - * \param[in] arg - * \return double - */ -double fn1_eval(double (*fn)(), double arg) { - double res; - errno = 0; - res = (*fn) (arg); - if (errno) cellerror = CELLERROR; - - return res; -} - - -/** - * \brief fn2_eval() - * \param[in] fn - * \param[in] arg1 - * \param[in] arg2 - * \return double - */ -double fn2_eval(double (*fn)(), double arg1, double arg2) { - double res; - errno = 0; - res = (*fn) (arg1, arg2); - if (errno) cellerror = CELLERROR; - - return res; -} - - -/** - * \brief docat() - * - * \details Tules for string functions: - * Take string arguments which they scxfree. All returned strings - * are assumed to be xalloced. - * - * \param[in] s1 - * \param[in] s2 - * - * \return char * - */ -char * docat(register char * s1, register char * s2) { - register char * p; - char * arg1, * arg2; - - if ( !s1 && !s2 ) - return ((char *) 0); - arg1 = s1 ? s1 : ""; - arg2 = s2 ? s2 : ""; - p = scxmalloc( (size_t) (strlen(arg1) + strlen(arg2) + 1)); - (void) strcpy(p, arg1); - (void) strcat(p, arg2); - if (s1) - scxfree(s1); - if (s2) - scxfree(s2); - return (p); -} - - -/** - * \brief dodate() - * \param[in] tloc - * \param[in] fmstr - * \return char * - */ -char * dodate(time_t tloc, char * fmtstr) { - char buff[FBUFLEN]; - char * p; - - if (! fmtstr) - fmtstr = "%a %b %d %H:%M:%S %Y"; - strftime(buff, FBUFLEN, fmtstr, localtime(&tloc)); - p = scxmalloc( (size_t) (strlen(buff) + 1)); - (void) strcpy(p, buff); - return (p); -} - - -/** - * \brief Conversion reverse from doascii - * \param[in] ascii - * \return char * - */ -char * dochr(double ascii) { - char * p = scxmalloc((size_t) 10); - char * q = p; - int digit ; - int nbdigits = 0; - int i = 0; - double stopnbdigits = 1; - - for (stopnbdigits = 1; ascii >= stopnbdigits && nbdigits < 9 ; stopnbdigits *= 256, ++ nbdigits) ; - for (; nbdigits > 0 ; -- nbdigits) { - for (stopnbdigits = 1, i = 0; i < nbdigits - 1 ; stopnbdigits *= 256, ++ i) ; - digit = floor (ascii / stopnbdigits) ; - ascii -= digit * stopnbdigits ; - if (ascii >= stopnbdigits && digit < 256) { digit ++ ; ascii += stopnbdigits ; } - if (ascii < 0 && digit >= 0) { digit -- ; ascii -= stopnbdigits ; } - *q++ = digit ; - } - *q = '\0'; - return p; -} - - -/** - * \brief dofmt() - * - * \param[in] fmtstr - * \param[in] v - * - * \return char * - */ -char * dofmt(char * fmtstr, double v) { - char buff[FBUFLEN]; - char * p; - - if (!fmtstr) - return ((char *) 0); - (void) snprintf(buff, FBUFLEN, fmtstr, v); - p = scxmalloc( (size_t) (strlen(buff) + 1)); - (void) strcpy(p, buff); - scxfree(fmtstr); - return (p); -} - - - -/** - * \brief doext() - * - * \details Given a command name and a value, run the command with the given - * value and read and return its first output line (only) as an allocated - * string, always a copy of se->e.o.s, whic is set appropriately first - * unless external functions are disabled, in which case the previous value - * is used. The handling of se->e.o.s. and freezing of command is tricky. - * Returning an allocated string in all cases, even if null, insures cell - * expressions are written to files, etc.. - * - * \param[in] se - * - * \return char * - */ -char * doext(struct enode *se) { - char buff[FBUFLEN]; /* command line/return, not permanently alloc */ - char * command; - double value; - - command = seval(NULL, se->e.o.left); - value = eval(NULL, se->e.o.right); - if ( ! get_conf_int("external_functions") ) { - sc_error("Warning: external functions disabled; using %s value", - (se->e.o.s && *se->e.o.s) ? "previous" : "null"); - - if (command) scxfree(command); - } else { - if (( !command ) || ( ! *command )) { - sc_error ("Warning: external function given null command name"); - cellerror = CELLERROR; - if (command) scxfree(command); - } else { - FILE *pp; - - (void) sprintf(buff, "%s %g", command, value); /* build cmd line */ - scxfree(command); - - sc_info("Running external function..."); - //(void) refresh(); - - if ((pp = popen(buff, "r")) == (FILE *) NULL) { /* run it */ - sc_error("Warning: running \"%s\" failed", buff); - cellerror = CELLERROR; - } else { - if (fgets(buff, sizeof(buff)-1, pp) == NULL) { /* one line */ - sc_error("Warning: external function returned nothing"); - } else { - char *cp; - //sc_error(""); /* erase notice */ - buff[sizeof(buff)-1] = '\0'; - - if ((cp = strchr(buff, '\n'))) /* contains newline */ - *cp = '\0'; /* end string there */ - - if (!se->e.o.s || strlen(buff) != strlen(se->e.o.s)) - se->e.o.s = scxrealloc(se->e.o.s, strlen(buff)); - (void) strcpy (se->e.o.s, buff); - /* save alloc'd copy */ - } - (void) pclose(pp); - - } /* else */ - } /* else */ - } /* else */ - if (se->e.o.s) - return (strcpy(scxmalloc((size_t) (strlen(se->e.o.s)+1)), se->e.o.s)); - else - return (strcpy(scxmalloc((size_t)1), "")); -} - - -/** - * \brief dosval() - * - * \details Given a string representing a column name and a value which - * is a column number, return the selected cell's string value, if any. - * Even if none, still allocate and return a null string, so the cell - * has a label value, so the expression is saved in a file, etc.. - * - * \param[in] colstr - * \param[in] rowdoub - * - * \return char * - */ -char * dosval(char * colstr, double rowdoub) { - struct ent * ep; - char * llabel; - - //llabel = (ep = getent(colstr, rowdoub, 0)) ? (ep -> label) : ""; - - // getent don't return NULL for a cell with no string. - llabel = ( ep = getent(colstr, rowdoub, 0) ) && ep -> label ? (ep -> label) : ""; - - return (strcpy(scxmalloc( (size_t) (strlen(llabel) + 1)), llabel)); -} - - -/** - * \brief doreplace() - * - * \param[in] source - * \param[in] old - * \param[in] new - * - * \return char * - */ -char * doreplace(char * source, char * old, char * new) { - return str_replace(source, old, new); -} + case DTS: return (dodts((int) eval(sh, ent, e->e.o.left), + (int)eval(sh, ent, e->e.o.right->e.o.left), + (int)eval(sh, ent, e->e.o.right->e.o.right))); + case TTS: return (dotts((int) eval(sh, ent, e->e.o.left), + (int)eval(sh, ent, e->e.o.right->e.o.left), + (int)eval(sh, ent, e->e.o.right->e.o.right))); + case EVALUATE: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return doevaluate(seval(sh, ent, e->e.o.left)); -/** - * \brief dosubstring() - * - * \param[in] s - * \param[in] v1 - * \param[in] v2 - * - * \return char * - */ -char * dosubstr(char * s, register int v1, register int v2) { - register char * s1, * s2; - char * p; + case STON: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (doston(seval(sh, ent, e->e.o.left))); - if ( !s ) return ((char *) 0); + case ASCII: return (doascii(seval(sh, ent, e->e.o.left))); - if (v2 >= strlen(s)) /* past end */ - v2 = strlen(s) - 1; /* to end */ + case SLEN: return (doslen(seval(sh, ent, e->e.o.left))); - if (v1 < 0 || v1 > v2) { /* out of range, return null string */ - scxfree(s); - p = scxmalloc( (size_t) 1); - p[0] = '\0'; - return (p); - } - s2 = p = scxmalloc( (size_t) (v2-v1 + 2)); - s1 = &s[v1]; - for (; v1 <= v2; s1++, s2++, v1++) - *s2 = *s1; - *s2 = '\0'; - scxfree (s); - return (p); -} + case EQS: return (doeqs(seval(sh, ent, e->e.o.right), seval(sh, ent, e->e.o.left))); + case LMAX: return dolmax(sh, ent, e); -/** - * \brief dosevaluate(): take a char * with a formula and seval it - * \param[in] s - * \return char * - */ -char * dosevaluate(char * s) { - if ( !s ) return ((char *) 0); - char * p; + case LMIN: return dolmin(sh, ent, e); + + case NVAL: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + char * s = seval(sh, ent, e->e.o.left); + if (! s) { return (double) (0); } + char * sf = calloc(strlen(s)+1, sizeof(char)); + strcpy(sf, s); + double n = eval(sh, ent, e->e.o.right); + struct ent * ep = getent(sh, sf, n, 1); + if (! ep) { free(s); return (double) (0); } + if (ent && ep) GraphAddEdge(getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), getVertex(graph, sh, ep, 1)); + return donval(sh, s, n); - wchar_t cline [BUFFERSIZE]; - swprintf(cline, BUFFERSIZE, L"seval %s", s); - send_to_interp(cline); - - p = scxmalloc(sizeof(char) * strlen(seval_result)+1); - strcpy(p, seval_result); - free(seval_result); + case MYROW: + // if @myrow is called before EvallJustOneVertex + // (this might happen during startup when loading file) + // gmyrow does not happen to have valid value. handle that. + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (gmyrow == -1 ? (ent ? ent->row + rowoffset : (double) sh->currow + rowoffset) : (double) (gmyrow + rowoffset)); - scxfree(s); - return p; -} + case MYCOL: + // if @mycol is called before EvallJustOneVertex + // (this might happen during startup when loading file) + // gmycol does not happen to have valid value. handle that. + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (gmycol == -1 ? (ent ? ent->col + coloffset : (double) sh->curcol + coloffset) : (double) (gmycol + coloffset)); + case LASTROW: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return ((double) sh->maxrow); -/** - * \brief Character casing: make upper case, make lower case, set 8th bit - * - * \param[in] acase - * \param[in] s - * - * \return char * - */ -char * docase(int acase, char * s) { - char * p = s; + case LASTCOL: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return ((double) sh->maxcol); - if (s == NULL) - return(NULL); + case ERR_: + cellerror = CELLERROR; + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return ((double) 0); - if ( acase == UPPER ) { - while( *p != '\0' ) { - if( islower(*p) ) - *p = toupper(*p); - p++; - } - } else if (acase == SET8BIT) { - while (*p != '\0') { - if (*p >= 0) - *p += 128 ; - p++; - } - } else if (acase == LOWER) { - while (*p != '\0') { - if (isupper(*p)) - *p = tolower(*p); - p++; - } - } - return (s); -} + case REF_: + cellerror = CELLREF; + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return ((double) 0); -/** - * \brief docapital - * - * \details Make proper capitals of every word in a string. If the string - * has mixed case, we say the string is lower and we will upcase only - * first letters of words. If the string is all upper, we will lower rest - * of words. - * - * \param[in] s - * - * \return char * - */ -char * docapital(char * s) { - char * p; - int skip = 1; - int AllUpper = 1; + case PI_: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return ((double) M_PI); - if (s == NULL) - return (NULL); - for (p = s; *p != '\0' && AllUpper != 0; p++) - if (isalpha(*p) && islower(*p)) AllUpper = 0; - for (p = s; *p != '\0'; p++) { - if (!isalnum(*p)) skip = 1; - else if (skip == 1) { - skip = 0; - if (islower(*p)) *p = toupper(*p); - } else /* if the string was all upper before */ - if (isupper(*p) && AllUpper != 0) - *p = tolower(*p); + case BLACK: return ((double) COLOR_BLACK); + case RED: return ((double) COLOR_RED); + case GREEN: return ((double) COLOR_GREEN); + case YELLOW: return ((double) COLOR_YELLOW); + case BLUE: return ((double) COLOR_BLUE); + case MAGENTA: return ((double) COLOR_MAGENTA); + case CYAN: return ((double) COLOR_CYAN); + case WHITE: return ((double) COLOR_WHITE); + case DEFAULT_COLOR: return ((double) DEFAULT_COLOR); + case FACT: + { + double total = eval(sh, ent, e->e.o.left); + int i; + for (i = eval(sh, ent, e->e.o.left) - 1; i > 0; i--) { + total *= i; + } + return total > 0 ? total : 1; + } + default: sc_error ("Illegal numeric expression"); + exprerr = 1; } - return (s); + cellerror = CELLERROR; + return ((double) 0.0); } + /** * \brief seval() - * * \param[in] ent * \param[in] se - * * \return char * */ -char * seval(struct ent * ent, struct enode * se) { +char * seval(struct sheet * sh, struct ent * ent, struct enode * se) { + struct sheet * sh_vp = sh; if (se == (struct enode *) 0) return (char *) 0; char * p; @@ -1797,13 +568,16 @@ p = scxmalloc( (size_t) (strlen(se->e.s) + 1)); (void) strcpy(p, se->e.s); - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); return (p); case O_VAR: { struct ent * vp = se->e.v.vp; - if (vp && ent && vp->row == ent->row && vp->col == ent->col) { + sh_vp = se->e.v.sheet; + if (sh_vp == NULL) sh_vp = sh; + + if (vp && ent && vp->row == ent->row && vp->col == ent->col && sh_vp == sh) { sc_error("Circular reference in seval"); se->op = ERR_; cellerror = CELLERROR; @@ -1814,8 +588,8 @@ if (vp && (rowoffset || coloffset)) { row = se->e.v.vf & FIX_ROW ? vp->row : vp->row + rowoffset; col = se->e.v.vf & FIX_COL ? vp->col : vp->col + coloffset; - checkbounds(&row, &col); - vp = *ATBL(tbl, row, col); + checkbounds(sh, &row, &col); + vp = *ATBL(sh, sh->tbl, row, col); } if ( !vp || !vp->label) return (NULL); @@ -1824,13 +598,13 @@ // here we store the cell dependences in a graph if (ent && vp) { - GraphAddEdge( getVertex(graph, lookat(ent->row, ent->col), 1), getVertex(graph, lookat(vp->row, vp->col), 1) ) ; + GraphAddEdge(getVertex(graph, sh, lookat(sh, ent->row, ent->col), 1), getVertex(graph, sh_vp, lookat(sh_vp, vp->row, vp->col), 1) ) ; } return (p); } case '#': - return (docat(seval(ent, se->e.o.left), seval(ent, se->e.o.right))); + return (docat(seval(sh, ent, se->e.o.left), seval(sh, ent, se->e.o.right))); case 'f': { @@ -1838,29 +612,31 @@ int ctmp = coloffset; char *ret; rowoffset = coloffset = 0; - ret = seval(ent, se->e.o.left); + ret = seval(sh, ent, se->e.o.left); rowoffset = rtmp; coloffset = ctmp; return (ret); } - case 'F': return (seval(ent, se->e.o.left)); + case 'F': return (seval(sh, ent, se->e.o.left)); case IF: - case '?': return (eval(NULL, se->e.o.left) ? seval(ent, se->e.o.right->e.o.left) : seval(ent, se->e.o.right->e.o.right)); + case '?': return (eval(sh, NULL, se->e.o.left) ? seval(sh, ent, se->e.o.right->e.o.left) : seval(sh, ent, se->e.o.right->e.o.right)); - case DATE: return (dodate( (time_t) (eval(NULL, se->e.o.left)), seval(ent, se->e.o.right))); + case DATE: return (dodate( (time_t) (eval(sh, NULL, se->e.o.left)), seval(sh, ent, se->e.o.right))); - case FMT: return (dofmt(seval(ent, se->e.o.left), eval(NULL, se->e.o.right))); + case FMT: return (dofmt(seval(sh, ent, se->e.o.left), eval(sh, NULL, se->e.o.right))); - case UPPER: return (docase(UPPER, seval(ent, se->e.o.left))); + case UPPER: return (docase(UPPER, seval(sh, ent, se->e.o.left))); - case LOWER: return (docase(LOWER, seval(ent, se->e.o.left))); + case LOWER: return (docase(LOWER, seval(sh, ent, se->e.o.left))); - case SET8BIT: return (docase(SET8BIT, seval(ent, se->e.o.left))); + case SET8BIT: return (docase(SET8BIT, seval(sh, ent, se->e.o.left))); - case CAPITAL:return (docapital(seval(ent, se->e.o.left))); + case CAPITAL: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (docapital(seval(sh, ent, se->e.o.left))); case STINDEX: { int r, c; @@ -1872,16 +648,18 @@ minc = se->e.o.left->e.r.left.vp->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - return dostindex(minr, minc, maxr, maxc, se->e.o.right); + return dostindex(sh, minr, minc, maxr, maxc, se->e.o.right); } - case EXT: return (doext(se)); + case EXT: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (doext(sh, se)); #ifdef XLUA case LUA: ; - int dg_store = eval(NULL, se->e.o.right); + int dg_store = eval(sh, NULL, se->e.o.right); // add to depgraph ONLY if second parameter to @lua is 1 - if (dg_store == 1 && ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); + if (dg_store == 1 && ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); if (ent) { ent->label = scxmalloc(sizeof(char)*4); @@ -1891,35 +669,38 @@ sc_info("Execution of LUA scripts disabled"); return NULL; } - return (doLUA(se, dg_store)); + return (doLUA(sh, se, dg_store)); #endif - case SVAL: return (dosval(seval(ent, se->e.o.left), eval(NULL, se->e.o.right))); + case SVAL: return (dosval(sh, seval(sh, ent, se->e.o.left), eval(sh, NULL, se->e.o.right))); - case REPLACE: return (doreplace(seval(ent, se->e.o.left), - seval(NULL, se->e.o.right->e.o.left), - seval(NULL, se->e.o.right->e.o.right))); - - case SUBSTR: return (dosubstr(seval(ent, se->e.o.left), - (int) eval(NULL, se->e.o.right->e.o.left) - 1, - (int) eval(NULL, se->e.o.right->e.o.right) - 1)); + case REPLACE: + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (doreplace(seval(sh, ent, se->e.o.left), + seval(sh, NULL, se->e.o.right->e.o.left), + seval(sh, NULL, se->e.o.right->e.o.right))); + + case SUBSTR: return (dosubstr(seval(sh, ent, se->e.o.left), + (int) eval(sh, NULL, se->e.o.right->e.o.left) - 1, + (int) eval(sh, NULL, se->e.o.right->e.o.right) - 1)); case COLTOA: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return (strcpy(scxmalloc( (size_t) 10), coltoa((int) eval(ent, se->e.o.left)))); + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (strcpy(scxmalloc( (size_t) 10), coltoa((int) eval(sh, ent, se->e.o.left)))); case CHR: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return (strcpy(scxmalloc( (size_t) 10), dochr(eval(NULL, se->e.o.left)))); + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return (strcpy(scxmalloc( (size_t) 10), dochr(eval(sh, NULL, se->e.o.left)))); case SEVALUATE: - if (ent && getVertex(graph, ent, 0) == NULL) GraphAddVertex(graph, ent); - return dosevaluate(seval(ent, se->e.o.left)); + if (ent && getVertex(graph, sh, ent, 0) == NULL) GraphAddVertex(graph, sh, ent); + return dosevaluate(seval(sh, ent, se->e.o.left)); case FILENAME: { - int n = eval(NULL, se->e.o.left); + char * curfile = session->cur_doc->name; + if (curfile == NULL) return curfile; + int n = eval(sh, NULL, se->e.o.left); char *s = strrchr(curfile, '/'); - if (n || s++ == NULL) s = curfile; p = scxmalloc( (size_t) (strlen(s) + 1)); (void) strcpy(p, s); @@ -1934,15 +715,107 @@ /** - * \brief new() + * \brief getent() + * + * \details Given a string representing a column name and a value which + * is a row number, return a pointer to the selected cell's entry. + * if alloc == 0 and no cell is alloc, return NULL. + * Use only the integer part of the column number. Always + * free the string + * + * \param[in] struct sheet * sh + * \param[in] colstr + * \param[in] rwodoub * + * \return struct ent * + */ +struct ent * getent(struct sheet * sh, char * colstr, double rowdoub, int alloc) { + int collen; /* length of string */ + int row, col; /* integer values */ + struct ent *p = (struct ent *) 0; /* selected entry */ + + if (!colstr) { + cellerror = CELLERROR; + return ((struct ent *) 0); + } + collen = strlen(colstr); + col = atocol(colstr, collen); + row = (int) floor(rowdoub); + + if (row >= 0 + && (row < sh->maxrows) /* in range */ + && (collen <= 2) /* not too long */ + && (col >= 0) + && (col < sh->maxcols)) { /* in range */ + if (alloc) p = lookat(sh, row, col); + else p = *ATBL(sh, sh->tbl, row, col); + if ((p != NULL) && p->cellerror) cellerror = CELLINVALID; + } + scxfree(colstr); + return (p); +} + + +/* + * \brief eval_fpe() + * \return none + */ +void eval_fpe() { /* Trap for FPE errors in eval */ +#if defined(i386) + sc_debug("eval_fpe i386"); + asm(" fnclex"); + asm(" fwait"); +#else + #ifdef IEEE_MATH + (void)fpsetsticky((fp_except)0); /* Clear exception */ + #endif /* IEEE_MATH */ +#endif + /* re-establish signal handler for next time */ + (void) signal(SIGFPE, eval_fpe); + longjmp(fpe_save, 1); +} + +/** + * \brief fn1_eval() + * \param[in] fn + * \param[in] arg + * \return double + */ +double fn1_eval(double (*fn)(), double arg) { + double res; + errno = 0; + res = (*fn) (arg); + if (errno) cellerror = CELLERROR; + + return res; +} + + +/** + * \brief fn2_eval() + * \param[in] fn + * \param[in] arg1 + * \param[in] arg2 + * \return double + */ +double fn2_eval(double (*fn)(), double arg1, double arg2) { + double res; + errno = 0; + res = (*fn) (arg1, arg2); + if (errno) cellerror = CELLERROR; + return res; +} + + +/** + * \brief new() * \param[in] op * \param[in] a1 * \param[in] a2 * \return struct enode * */ struct enode * new(int op, struct enode * a1, struct enode * a2) { - register struct enode * p; + struct enode * p; //if (freeenodes) { // p = freeenodes; // freeenodes = p->e.o.left; @@ -1952,6 +825,8 @@ p->e.r.left.expr = NULL; // important to initialize p->e.r.right.vp = NULL; // important to initialize p->e.r.right.expr = NULL; // important to initialize + p->e.r.left.sheet = NULL; // important to initialize + p->e.r.right.sheet = NULL;// important to initialize p->op = op; p->e.o.left = a1; p->e.o.right = a2; @@ -1967,7 +842,7 @@ * \return struct enotde * */ struct enode * new_var(int op, struct ent_ptr a1) { - register struct enode * p; + struct enode * p; //if (freeenodes) { // p = freeenodes; // freeenodes = p->e.o.left; @@ -1977,6 +852,8 @@ p->e.r.left.expr = NULL; // important to initialize p->e.r.right.vp = NULL; // important to initialize p->e.r.right.expr = NULL; // important to initialize + p->e.r.left.sheet = NULL; // important to initialize + p->e.r.right.sheet = NULL;// important to initialize p->op = op; p->e.v = a1; // ref to cell needed for this expr return p; @@ -1984,15 +861,14 @@ /** - * \brief TODO Document new_range() - * + * \brief new_range() * \param[in] op * \param[in] a1 * * \return none */ struct enode * new_range(int op, struct range_s a1) { - register struct enode * p; + struct enode * p; //if (freeenodes) //{ p = freeenodes; // freeenodes = p->e.o.left; @@ -2003,6 +879,8 @@ p->e.r.left.expr = NULL; // important to initialize p->e.r.right.vp = NULL; // important to initialize p->e.r.right.expr = NULL; // important to initialize + p->e.r.left.sheet = NULL; // important to initialize + p->e.r.right.sheet = NULL;// important to initialize p->op = op; p->e.r = a1; return p; @@ -2016,7 +894,7 @@ * \return struct enotde * */ struct enode * new_const(int op, double a1) { - register struct enode * p; + struct enode * p; //if (freeenodes) { /* reuse an already free'd enode */ // p = freeenodes; // freeenodes = p->e.o.left; @@ -2026,6 +904,8 @@ p->e.r.left.expr = NULL; // important to initialize p->e.r.right.vp = NULL; // important to initialize p->e.r.right.expr = NULL; // important to initialize + p->e.r.left.sheet = NULL; // important to initialize + p->e.r.right.sheet = NULL;// important to initialize p->op = op; p->e.k = a1; return p; @@ -2038,7 +918,7 @@ * \return struct enode * */ struct enode * new_str(char * s) { - register struct enode * p; + struct enode * p; //if (freeenodes) { /* reuse an already free'd enode */ // p = freeenodes; // freeenodes = p->e.o.left; @@ -2048,6 +928,8 @@ p->e.r.left.expr = NULL; // important to initialize p->e.r.right.vp = NULL; // important to initialize p->e.r.right.expr = NULL; // important to initialize + p->e.r.left.sheet = NULL; // important to initialize + p->e.r.right.sheet = NULL;// important to initialize p->op = O_SCONST; p->e.s = s; return (p); @@ -2084,11 +966,11 @@ sc_error("Nothing to repeat"); break; case G_NUM: - num_search(gs.g_n, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, gs.errsearch, 0); + num_search(gs.g_sheet, gs.g_n, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, gs.errsearch, 0); break; case G_STR: gs.g_type = G_NONE; /* Don't free the string */ - str_search(gs.g_s, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, num, 0); + str_search(gs.g_sheet, gs.g_s, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, num, 0); break; default: sc_error("go_previous: internal error"); @@ -2108,17 +990,17 @@ sc_error("Nothing to repeat"); break; case G_NUM: - num_search(gs.g_n, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, gs.errsearch, 1); + num_search(gs.g_sheet, gs.g_n, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, gs.errsearch, 1); break; case G_CELL: - moveto(gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, gs.strow, gs.stcol); + moveto(gs.g_sheet, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, gs.strow, gs.stcol); break; case G_XSTR: case G_NSTR: num++; case G_STR: gs.g_type = G_NONE; /* Don't free the string */ - str_search(gs.g_s, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, num, 1); + str_search(gs.g_sheet, gs.g_s, gs.g_row, gs.g_col, gs.g_lastrow, gs.g_lastcol, num, 1); break; default: @@ -2129,31 +1011,29 @@ /** * \brief Place the cursor on a given cell. - * * \details Place the cursor on a given cell. If cornerrow >= 0, place * the cell at row cornerrow and column cornercol in the upper corner * of the screen possible. - * + * \param[in] struct sheet * sh * \param[in] row * \param[in] col * \param[in] lastrow_ * \param[in] lastcol_ * \param[in] cornerrow * \param[in] cornercol - * * \return none */ -void moveto(int row, int col, int lastrow_, int lastcol_, int cornerrow, int cornercol) { - register int i; - - lastrow = currow; - lastcol = curcol; - currow = row; - curcol = col; +void moveto(struct sheet * sh, int row, int col, int lastrow_, int lastcol_, int cornerrow, int cornercol) { + int i; + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->currow = row; + sh->curcol = col; g_free(); + gs.g_sheet = sh; gs.g_type = G_CELL; - gs.g_row = currow; - gs.g_col = curcol; + gs.g_row = sh->currow; + gs.g_col = sh->curcol; gs.g_lastrow = lastrow_; gs.g_lastcol = lastcol_; if (cornerrow >= 0) { @@ -2162,19 +1042,19 @@ gs.stflag = 0; for (rowsinrange = 0, i = row; i <= lastrow_; i++) { - if (row_hidden[i]) { + if (sh->row_hidden[i]) { sc_info("Cell's row is hidden"); continue; } rowsinrange++; } for (colsinrange = 0, i = col; i <= lastcol_; i++) { - if (col_hidden[i]) { + if (sh->col_hidden[i]) { colsinrange = 0; sc_info("Cell's col is hidden"); continue; } - colsinrange += fwidth[i]; + colsinrange += sh->fwidth[i]; } //if (loading) changed = 0; } @@ -2188,6 +1068,7 @@ * \details flow = 1, look forward * \details flow = 0, look backwards * + * \param[in] struct sheet * sh * \param[in] n * \param[in] firstrow * \param[in] firstcol @@ -2198,24 +1079,25 @@ * * \return none */ -void num_search(double n, int firstrow, int firstcol, int lastrow_, int lastcol_, int errsearch, int flow) { - register struct ent * p; - register int r, c; +void num_search(struct sheet * sh, double n, int firstrow, int firstcol, int lastrow_, int lastcol_, int errsearch, int flow) { + struct ent * p; + int r, c; int endr, endc; //if (!loading) remember(0); g_free(); + gs.g_sheet = sh; gs.g_type = G_NUM; gs.g_n = n; gs.g_row = firstrow; - gs.g_col = firstcol; gs.g_lastrow = lastrow_; gs.g_lastcol = lastcol_; gs.errsearch = errsearch; - if (currow >= firstrow && currow <= lastrow_ && curcol >= firstcol && curcol <= lastcol_) { - endr = currow; - endc = curcol; + gs.g_flow = flow; + if (sh->currow >= firstrow && sh->currow <= lastrow_ && sh->curcol >= firstcol && sh->curcol <= lastcol_) { + endr = sh->currow; + endc = sh->curcol; } else { endr = lastrow_; endc = lastcol_; @@ -2229,7 +1111,7 @@ c++; else { if (r < lastrow_) { - while (++r < lastrow_ && row_hidden[r]) /* */; + while (++r < lastrow_ && sh->row_hidden[r]) /* */; c = firstcol; } else { r = firstrow; @@ -2241,7 +1123,7 @@ c--; else { if (r > firstrow) { - while (--r > firstrow && row_hidden[r]) /* */; + while (--r > firstrow && sh->row_hidden[r]) /* */; c = lastcol_; } else { r = lastrow_; @@ -2250,8 +1132,8 @@ } } - p = *ATBL(tbl, r, c); - if (! col_hidden[c] && p && (p->flags & is_valid) && (errsearch || (p->v == n)) && (! errsearch || (p->cellerror == errsearch))) /* CELLERROR vs CELLINVALID */ + p = *ATBL(sh, sh->tbl, r, c); + if (! sh->col_hidden[c] && p && (p->flags & is_valid) && (errsearch || (p->v == n)) && (! errsearch || (p->cellerror == errsearch))) /* CELLERROR vs CELLINVALID */ break; if (r == endr && c == endc) { if (errsearch) { @@ -2263,22 +1145,21 @@ } } - lastrow = currow; - lastcol = curcol; - currow = r; - curcol = c; + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->currow = r; + sh->curcol = c; rowsinrange = 1; - colsinrange = fwidth[curcol]; + colsinrange = sh->fwidth[sh->curcol]; } /** * \brief 'goto' a cell containing a matching string - * * \details 'goto' a cell containing a matching string. * \details flow = 1, look forward * \details flow = 0, look backwards - * + * \param[in] struct sheet * sh * \param[in] s * \param[in] firstrow * \param[in] firstcol @@ -2286,10 +1167,9 @@ * \param[in] lastcol_ * \param[in] num * \param[in] flow - * * \return none */ -void str_search(char *s, int firstrow, int firstcol, int lastrow_, int lastcol_, int num, int flow) { +void str_search(struct sheet * sh, char * s, int firstrow, int firstcol, int lastrow_, int lastcol_, int num, int flow) { struct ent * p; int r, c; int endr, endc; @@ -2297,7 +1177,8 @@ regex_t preg; int errcode; - if ( get_conf_int("ignorecase")) + sc_info(""); + if (get_conf_int("ignorecase")) errcode = regcomp(&preg, s, REG_EXTENDED | REG_ICASE); else errcode = regcomp(&preg, s, REG_EXTENDED); @@ -2312,16 +1193,18 @@ } g_free(); + gs.g_sheet = sh; gs.g_type = G_STR + num; gs.g_s = s; gs.g_row = firstrow; gs.g_col = firstcol; gs.g_lastrow = lastrow_; gs.g_lastcol = lastcol_; + gs.g_flow = flow; - if (currow >= firstrow && currow <= lastrow_ && curcol >= firstcol && curcol <= lastcol_) { - endr = currow; - endc = curcol; + if (sh->currow >= firstrow && sh->currow <= lastrow_ && sh->curcol >= firstcol && sh->curcol <= lastcol_) { + endr = sh->currow; + endc = sh->curcol; } else { endr = lastrow_; endc = lastcol_; @@ -2335,7 +1218,7 @@ c++; else { if (r < lastrow_) { - while (++r < lastrow_ && row_hidden[r]) /* */; + while (++r < lastrow_ && sh->row_hidden[r]) /* */; c = firstcol; } else { r = endr; @@ -2348,7 +1231,7 @@ c--; else { if (r > firstrow) { - while (--r > firstrow && row_hidden[r]) /* */; + while (--r > firstrow && sh->row_hidden[r]) /* */; c = lastcol_; } else { r = endr; @@ -2358,7 +1241,7 @@ } } - p = *ATBL(tbl, r, c); + p = *ATBL(sh, sh->tbl, r, c); if (gs.g_type == G_NSTR) { *line = '\0'; if (p) { @@ -2371,9 +1254,9 @@ strftime(line, sizeof(line), (p->format)+1, localtime(&i)); } else - format(p->format, precision[c], p->v, line, sizeof(line)); + format(p->format, sh->precision[c], p->v, line, sizeof(line)); } else - engformat(realfmt[c], fwidth[c], precision[c], p->v, line, sizeof(line)); + engformat(sh->realfmt[c], sh->fwidth[c], sh->precision[c], p->v, line, sizeof(line)); } } } else if (gs.g_type == G_XSTR) { @@ -2386,7 +1269,7 @@ *line = '\0'; } } - if (! col_hidden[c]) { + if (! sh->col_hidden[c]) { if (gs.g_type == G_STR && p && p->label && regexec(&preg, p->label, 0, NULL, 0) == 0) break; } else /* gs.g_type != G_STR */ @@ -2400,29 +1283,28 @@ return; } linelim = -1; - lastrow = currow; - lastcol = curcol; - currow = r; - curcol = c; + sh->lastrow = sh->currow; + sh->lastcol = sh->curcol; + sh->currow = r; + sh->curcol = c; rowsinrange = 1; - colsinrange = fwidth[curcol]; + colsinrange = sh->fwidth[sh->curcol]; regfree(&preg); } /** * \brief Fill a range with constants - * + * \param[in] struct sheet * sh * \param[in] v1 * \param[in] v2 * \param[in] start * \param[in] inc - * * \return none */ -void fill(struct ent *v1, struct ent *v2, double start, double inc) { +void fill(struct sheet * sh, struct ent * v1, struct ent * v2, double start, double inc) { int r, c; - register struct ent *n; + struct ent *n; int maxr, maxc; int minr, minc; @@ -2432,44 +1314,44 @@ minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - checkbounds(&maxr, &maxc); + checkbounds(sh, &maxr, &maxc); if (minr < 0) minr = 0; if (minc < 0) minc = 0; #ifdef UNDO create_undo_action(); - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); #endif if (calc_order == BYROWS) { - for (r = minr; r<=maxr; r++) - for (c = minc; c<=maxc; c++) { - n = lookat(r, c); - if (n->flags&is_locked) continue; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + n = lookat(sh, r, c); + if (n->flags & is_locked) continue; (void) clearent(n); n->v = start; start += inc; - n->flags |= (is_changed|is_valid); + n->flags |= (is_changed | is_valid); n->flags &= ~(iscleared); } } else if (calc_order == BYCOLS) { - for (c = minc; c<=maxc; c++) - for (r = minr; r<=maxr; r++) { - n = lookat(r, c); + for (c = minc; c <= maxc; c++) + for (r = minr; r <= maxr; r++) { + n = lookat(sh, r, c); (void) clearent(n); n->v = start; start += inc; - n->flags |= (is_changed|is_valid); + n->flags |= (is_changed | is_valid); n->flags &= ~(iscleared); } } else { sc_error(" Internal error calc_order"); } - EvalRange(minr, minc, maxr, maxc); + EvalRange(sh, minr, minc, maxr, maxc); #ifdef UNDO - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); end_undo_action(); #endif } @@ -2477,15 +1359,14 @@ /** * \brief Lock a range of cells - * + * \param[in] struct sheet * sh * \param[in] v1 * \param[in] v2 - * * \return none */ -void lock_cells(struct ent * v1, struct ent * v2) { +void lock_cells(struct sheet * sh, struct ent * v1, struct ent * v2) { int r, c; - register struct ent * n; + struct ent * n; int maxr, maxc; int minr, minc; @@ -2495,21 +1376,21 @@ minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - checkbounds(&maxr, &maxc); + checkbounds(sh, &maxr, &maxc); if (minr < 0) minr = 0; if (minc < 0) minc = 0; #ifdef UNDO create_undo_action(); - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); #endif for (r = minr; r <= maxr; r++) for (c = minc; c <= maxc; c++) { - n = lookat(r, c); + n = lookat(sh, r, c); n->flags |= is_locked; } #ifdef UNDO - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); end_undo_action(); #endif sc_info("Cells were locked"); @@ -2518,15 +1399,14 @@ /** * \brief Unlock a range of cells - * + * \param[in] struct sheet * sh * \param[in] v1 * \param[in] v2 - * * \return none */ -void unlock_cells(struct ent * v1, struct ent * v2) { +void unlock_cells(struct sheet * sh, struct ent * v1, struct ent * v2) { int r, c; - register struct ent * n; + struct ent * n; int maxr, maxc; int minr, minc; @@ -2536,21 +1416,21 @@ minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - checkbounds(&maxr, &maxc); + checkbounds(sh, &maxr, &maxc); if (minr < 0) minr = 0; if (minc < 0) minc = 0; #ifdef UNDO create_undo_action(); - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); #endif for (r = minr; r <= maxr; r++) for (c = minc; c <= maxc; c++) { - n = lookat(r, c); + n = lookat(sh, r, c); n->flags &= ~is_locked; } #ifdef UNDO - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); end_undo_action(); #endif sc_info("Cells were unlocked"); @@ -2559,32 +1439,29 @@ /** * \brief Set the numeric part of a cell - * * \param[in] v * \param[in] e - * * \return none */ -void let(struct ent * v, struct enode * e) { - if (locked_cell(v->row, v->col)) return; - +void let(struct roman * roman, struct sheet * sh, struct ent * v, struct enode * e) { + if (locked_cell(sh, v->row, v->col)) return; #ifdef UNDO extern struct ent_ptr * deps; - if (!loading) { + if (! roman->loading) { create_undo_action(); // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range(v->row, v->col, v->row, v->col); - copy_to_undostruct(v->row, v->col, v->row, v->col, UNDO_DEL, HANDLE_DEPS, NULL); + ents_that_depends_on_range(sh, v->row, v->col, v->row, v->col); + copy_to_undostruct(sh, v->row, v->col, v->row, v->col, UNDO_DEL, HANDLE_DEPS, NULL); } #endif double val; unsigned isconstant = constant(e); - if (v->row == currow && v->col == curcol) cellassign = 1; + if (v->row == sh->currow && v->col == sh->curcol) cellassign = 1; - if (loading && ! isconstant) + if (roman->loading && ! isconstant) val = (double) 0.0; else { exprerr = 0; @@ -2595,18 +1472,18 @@ cellerror = CELLERROR; } else { cellerror = CELLOK; - val = eval(v, e); // JUST NUMERIC VALUE + val = eval(sh, v, e); // JUST NUMERIC VALUE } if (v->cellerror != cellerror) { v->flags |= is_changed; - modflg++; + roman->modflg++; v->cellerror = cellerror; } (void) signal(SIGFPE, exit_app); if (exprerr) { efree(e); #ifdef UNDO - if (!loading) dismiss_undo_item(NULL); + if (! roman->loading) dismiss_undo_item(NULL); #endif return; } @@ -2614,7 +1491,7 @@ if (isconstant) { /* prescale input unless it has a decimal */ - if ( !loading && !decimal && (prescale < (double) 0.9999999)) + if ( ! roman->loading && !decimal && (prescale < (double) 0.9999999)) val *= prescale; decimal = FALSE; @@ -2630,22 +1507,22 @@ v->expr = e; v->flags &= ~is_strexpr; - eval(v, e); // ADDED - here we store the cell dependences in a graph + eval(sh, v, e); // ADDED - here we store the cell dependences in a graph } if (v->cellerror == CELLOK) v->flags |= ( is_changed | is_valid ); - modflg++; + roman->modflg++; if (( v->trigger ) && ((v->trigger->flag & TRG_WRITE) == TRG_WRITE)) do_trigger(v,TRG_WRITE); - if (!loading && cellerror == CELLERROR) { /* issue #201 */ + if (! roman->loading && cellerror == CELLERROR) { /* issue #201 */ if (v->expr) efree(v->expr); v->expr = NULL; } #ifdef UNDO - if (!loading) { + if (! roman->loading) { // here we also save in undostruct, all the ents that depends on the deleted ones (after change) - copy_to_undostruct(v->row, v->col, v->row, v->col, UNDO_ADD, HANDLE_DEPS, NULL); + copy_to_undostruct(sh, v->row, v->col, v->row, v->col, UNDO_ADD, HANDLE_DEPS, NULL); if (deps != NULL) { free(deps); deps = NULL; @@ -2660,31 +1537,29 @@ /** * \brief slet() - * * \param[in] v * \param[in] se * \param[in] flushdir - * * \return none */ -void slet(struct ent * v, struct enode * se, int flushdir) { - if (locked_cell(v->row, v->col)) return; +void slet(struct roman * roman, struct sheet * sh, struct ent * v, struct enode * se, int flushdir) { + if (locked_cell(sh, v->row, v->col)) return; #ifdef UNDO extern struct ent_ptr * deps; - if (!loading) { + if (! roman->loading) { // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range(v->row, v->col, v->row, v->col); + ents_that_depends_on_range(sh, v->row, v->col, v->row, v->col); create_undo_action(); - copy_to_undostruct(v->row, v->col, v->row, v->col, UNDO_DEL, HANDLE_DEPS, NULL); - add_undo_row_format(v->row, 'R', row_format[v->row]); + copy_to_undostruct(sh, v->row, v->col, v->row, v->col, UNDO_DEL, HANDLE_DEPS, NULL); + add_undo_row_format(v->row, 'R', sh->row_format[v->row]); } #endif // No debe borrarse el vertex. Ver comentario en LET //if (getVertex(graph, lookat(v->row, v->col), 0) != NULL) destroy_vertex(lookat(v->row, v->col)); char * p; - if (v->row == currow && v->col == curcol) cellassign = 1; + if (v->row == sh->currow && v->col == sh->curcol) cellassign = 1; exprerr = 0; (void) signal(SIGFPE, eval_fpe); @@ -2694,14 +1569,14 @@ p = ""; } else if (v->flags & is_strexpr || v->expr) { cellerror = CELLOK; - p = seval(v, se); + p = seval(sh, v, se); } else { cellerror = CELLOK; - p = seval(NULL, se); + p = seval(sh, NULL, se); } if (v->cellerror != cellerror) { v->flags |= is_changed; - modflg++; + roman->modflg++; v->cellerror = cellerror; } (void) signal(SIGFPE, exit_app); @@ -2735,8 +1610,8 @@ efree(v->expr); v->expr = se; - //p = seval(v, se); // ADDED - here we store the cell dependences in a graph - //if (p) scxfree(p); // ADDED + p = seval(sh, v, se); /* ADDED for #652 - here we store the cell dependences in a graph */ + if (p) scxfree(p); /***/ v->flags |= (is_changed | is_strexpr); if (flushdir < 0) v->flags |= is_leftflush; @@ -2746,13 +1621,13 @@ else v->flags &= ~is_label; } - modflg++; + roman->modflg++; if (( v->trigger ) && ((v->trigger->flag & TRG_WRITE) == TRG_WRITE)) do_trigger(v,TRG_WRITE); #ifdef UNDO - if (!loading) { + if (! roman->loading) { // here we also save in undostruct, all the ents that depends on the deleted ones (after change) - copy_to_undostruct(v->row, v->col, v->row, v->col, UNDO_ADD, HANDLE_DEPS, NULL); + copy_to_undostruct(sh, v->row, v->col, v->row, v->col, UNDO_ADD, HANDLE_DEPS, NULL); if (deps != NULL) { free(deps); deps = NULL; @@ -2766,16 +1641,15 @@ /** * \brief format_cell() - * + * \param[in] struct sheet * sh * \param[in] v1 * \param[in] v2 * \param[in] s - * * \return none */ -void format_cell(struct ent *v1, struct ent *v2, char *s) { +void format_cell(struct sheet * sh, struct ent * v1, struct ent * v2, char *s) { int r, c; - register struct ent *n; + struct ent *n; int maxr, maxc; int minr, minc; @@ -2785,16 +1659,16 @@ minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - checkbounds(&maxr, &maxc); + checkbounds(sh, &maxr, &maxc); if (minr < 0) minr = 0; if (minc < 0) minc = 0; - modflg++; + session->cur_doc->modflg++; for (r = minr; r <= maxr; r++) for (c = minc; c <= maxc; c++) { - n = lookat(r, c); - if (locked_cell(n->row, n->col)) + n = lookat(sh, r, c); + if (locked_cell(sh, n->row, n->col)) continue; if (n->format) scxfree(n->format); @@ -2803,18 +1677,17 @@ n->format = strcpy(scxmalloc( (unsigned) (strlen(s) + 1)), s); n->flags |= is_changed; } + return; } /** * \brief Say if an expression is a constant or not - * * \param[in] e - * * \return 1 function is an expression * \return 0 function is not an expression */ -int constant(register struct enode *e) { +int constant(struct enode *e) { return e == NULL || e->op == O_CONST || e->op == O_SCONST @@ -2848,11 +1721,11 @@ void efree(struct enode * e) { if (e) { /* for get ent ---> */ - if (e->e.r.left.vp && e->e.r.left.vf & GETENT) { + if (e->e.r.left.vp && e->e.r.left.vf & GET_ENT) { efree(e->e.r.left.expr); e->e.r.left.expr = NULL; } - if (e->e.r.right.vp && e->e.r.right.vf & GETENT) { + if (e->e.r.right.vp && e->e.r.right.vf & GET_ENT) { efree(e->e.r.right.expr); e->e.r.right.expr = NULL; } /* <-- for get ent */ @@ -2869,6 +1742,10 @@ } else if (e->op == EXT && e->e.o.s) { scxfree(e->e.o.s); e->e.o.s = NULL; + if (e->e.o.left) efree(e->e.o.left); + e->e.o.left = NULL; + if (e->e.o.right) efree(e->e.o.right); + e->e.o.right = NULL; } scxfree((char *) e); e = (struct enode *) 0; @@ -2878,17 +1755,16 @@ /** * \brief label() - * * \param[in] v * \param[in] s * \param[in] flushdir - * * \return none */ -void label(register struct ent * v, register char * s, int flushdir) { +void label(struct ent * v, char * s, int flushdir) { + struct roman * roman = session->cur_doc; if (v) { /*if (flushdir == 0 && v->flags & is_valid) { - register struct ent * tv; + struct ent * tv; if (v->col > 0 && ((tv=lookat(v->row, v->col-1))->flags & is_valid) == 0) v = tv, flushdir = 1; else if (((tv=lookat(v->row, v->col+1))->flags & is_valid) == 0) @@ -2907,7 +1783,7 @@ else v->flags &= ~is_leftflush; if (flushdir==0) v->flags |= is_label; else v->flags &= ~is_label; - modflg++; + roman->modflg++; } } @@ -2919,13 +1795,17 @@ */ void decodev(struct ent_ptr v) { struct range * r; + if (v.sheet != NULL) { + (void) sprintf(line + linelim, "{\"%s\"}!", v.sheet->name); + linelim += strlen(line + linelim); + } //if ( ! v.vp || v.vp->flags & is_deleted) // (void) sprintf(line + linelim, "@ERR"); //else if ( !find_range( (char *) 0, 0, v.vp, v.vp, &r) && !r->r_is_range) { (void) sprintf(line+linelim, "%s", r->r_name); linelim += strlen(line + linelim); - } else if (v.vf == GETENT) { + } else if (v.vf == GET_ENT) { sprintf(line + linelim, "@getent("); linelim += strlen(line + linelim); if (v.expr && v.expr->e.o.left) decompile(v.expr->e.o.left, 0); @@ -2949,7 +1829,7 @@ */ char * coltoa(int col) { static char rname[3]; - register char *p = rname; + char *p = rname; if (col > 25) { *p++ = col/26 + 'A' - 1; @@ -2963,13 +1843,10 @@ /** * \brief decompile_list() - * * \details To make list elements come out in the same order * they were entered, we must do a depth-first eval of the * ELIST tree. - * * \param[in] p - * * \return none */ void decompile_list(struct enode *p) { @@ -2982,14 +1859,12 @@ /** * \brief decompile() - * * \param[in] e * \param[in] priority - * * \return none */ -void decompile(register struct enode *e, int priority) { - register char *s; +void decompile(struct enode *e, int priority) { + char *s; if (e) { int mypriority; switch (e->op) { @@ -3205,10 +2080,8 @@ /** * \brief index_arg() - * * \param[in] s * \param[in] e - * * \return none */ void index_arg(char *s, struct enode *e) { @@ -3230,10 +2103,8 @@ /** * \brief two_arg_index() - * * \param[in] s * \param[in] e - * * \return none */ void two_arg_index(char *s, struct enode *e) { @@ -3251,10 +2122,8 @@ /** * \brief list_arg() - * * \param[in] s * \param[in] e - * * \return none */ void list_arg(char *s, struct enode *e) { @@ -3270,10 +2139,8 @@ /** * \brief one_arg() - * * \param[in] s * \param[in] e - * * \return none */ void one_arg(char *s, struct enode *e) { @@ -3286,10 +2153,8 @@ /** * \brief two_arg() - * * \param[in] s * \param[in] e - * * \return none */ void two_arg(char *s, struct enode *e) { @@ -3304,10 +2169,8 @@ /** * \brief three_arg() - * * \param[in] s * \param[in] e - * * \return none */ void three_arg(char *s, struct enode *e) { @@ -3324,10 +2187,8 @@ /** * \brief range_arg() - * * \param[in] s * \param[in] e - * * \return none */ void range_arg(char *s, struct enode *e) { @@ -3349,16 +2210,13 @@ /** * \brief editfmt() - * + * \param[in] struct sheet * sh * \param[in] row * \param[in] col - * * \return none */ -void editfmt(int row, int col) { - register struct ent *p; - - p = lookat(row, col); +void editfmt(struct sheet * sh, int row, int col) { + struct ent * p = lookat(sh, row, col); if (p->format) { (void) sprintf(line, "fmt %s \"%s\"", v_name(row, col), p->format); linelim = strlen(line); @@ -3368,16 +2226,15 @@ /** * \brief editv() - * + * \param[in] struct sheet * sh * \param[in] row * \param[in] col - * * \return none */ -void editv(int row, int col) { - register struct ent *p; +void editv(struct sheet * sh, int row, int col) { + struct ent *p; - p = lookat(row, col); + p = lookat(sh, row, col); (void) sprintf(line, "let %s = ", v_name(row, col)); linelim = strlen(line); if (p->flags & is_valid || p->expr) { @@ -3385,23 +2242,21 @@ (void) sprintf(line+linelim, "%.15g", p->v); linelim = strlen(line); } else - editexp(row, col); + editexp(sh, row, col); } } /** * \brief editexp() - * + * \param[in] struct sheet * sh * \param[in] row * \param[in] col - * * \return none */ -void editexp(int row, int col) { - register struct ent *p; - - p = lookat(row, col); +void editexp(struct sheet * sh, int row, int col) { + struct ent * p; + p = lookat(sh, row, col); //if ( !p || !p->expr ) return; 21/06/2014 decompile(p->expr, 0); line[linelim] = '\0'; @@ -3410,17 +2265,15 @@ /** * \brief edits() - * + * \param[in] struct sheet * sh * \param[in] row * \param[in] col * \param[in] saveinfile - * * \return none */ -void edits(int row, int col, int saveinfile) { - register struct ent *p; - - p = lookat(row, col); +void edits(struct sheet * sh, int row, int col, int saveinfile) { + struct ent *p; + p = lookat(sh, row, col); if (saveinfile) { if (p->flags & is_label) @@ -3431,7 +2284,7 @@ linelim = strlen(line); if (p->flags & is_strexpr && p->expr) { - editexp(row, col); + editexp(sh, row, col); } else if (p->label) { if (saveinfile) { (void) sprintf(line+linelim, "\"%s\"", p->label); @@ -3448,14 +2301,13 @@ /** * \brief dateformat() - * + * \param[in] struct sheet * sh * \param[in] v1 * \param[in] v2 * \param[in] fmt - * * \return none */ -int dateformat(struct ent *v1, struct ent *v2, char * fmt) { +int dateformat(struct sheet * sh, struct ent *v1, struct ent *v2, char * fmt) { if ( ! fmt || *fmt == '\0') return -1; int r, c; @@ -3470,18 +2322,18 @@ minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; - checkbounds(&maxr, &maxc); + checkbounds(sh, &maxr, &maxc); if (minr < 0) minr = 0; if (minc < 0) minc = 0; #ifdef UNDO create_undo_action(); - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_DEL, IGNORE_DEPS, NULL); #endif for (r = minr; r <= maxr; r++) { for (c = minc; c <= maxc; c++) { - n = lookat(r, c); - if ( locked_cell(n->row, n->col) || ! (n)->label ) continue; + n = lookat(sh, r, c); + if (locked_cell(sh, n->row, n->col) || ! (n)->label) continue; // free all ent content but its label n->v = (double) 0; @@ -3504,36 +2356,9 @@ } } #ifdef UNDO - copy_to_undostruct(minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, minr, minc, maxr, maxc, UNDO_ADD, IGNORE_DEPS, NULL); end_undo_action(); #endif - modflg++; // increase just one time + session->cur_doc->modflg++; // increase just one time return 0; } - - -#ifdef RINT -/** - * \brief Round-to-even - * - * \details Round-to-even, also known as "banker's rounding". With - * round-to-even, a number exactly halfway between two values is - * rounded to whichever is even; e.g. rnd(0.5)=0, rnd(1.5)=2, - * rnd(3.5)=4. This is the default rounding mode for IEEE floating - * point. for good reason: it has better njmeric properties. For example, - * if X+Y is an integer, then X+Y = rnd(X)+rnd(Y) will round-to-even, but - * not always with sc's rounding (which is round-to-positive-infinity). I - * ran into this problem when trying to split interest in an account to - * two people fairly. - * - * \param[in] d - * - * \return none - */ -double rint(double d) { - /* as sent */ - double fl = floor(d), fr = d-fl; - return - fr<0.5 || fr==0.5 && fl==floor(fl/2)*2 ? fl : ceil(d); -} -#endif diff -Nru sc-im-0.8.2+ds/src/interp.h sc-im-0.8.3+ds/src/interp.h --- sc-im-0.8.2+ds/src/interp.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/interp.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -42,43 +42,11 @@ * \brief Header file for interp.c */ -#include -double finfunc(int fun, double v1, double v2, double v3); -char * dostindex(int minr, int minc, int maxr, int maxc, struct enode * val); -double doindex(int minr, int minc, int maxr, int maxc, struct enode * val); -double dolookup(struct enode * val, int minr, int minc, int maxr, int maxc, int offset, int vflag); -double docount(int minr, int minc, int maxr, int maxc, struct enode * e); -double dosum(int minr, int minc, int maxr, int maxc, struct enode * e); -double doprod(int minr, int minc, int maxr, int maxc, struct enode * e); -double doavg(int minr, int minc, int maxr, int maxc, struct enode * e); -double dostddev(int minr, int minc, int maxr, int maxc, struct enode * e); -double domax(int minr, int minc, int maxr, int maxc, struct enode * e); -double domin(int minr, int minc, int maxr, int maxc, struct enode * e); -double dodts(int e1, int e2, int e3); -double dotts(int hr, int min, int sec); -double dotime(int which, double when); -double doston(char * s); -int doslen(char * s); -double doeqs(char * s1, char * s2); -struct ent * getent(char * colstr, double rowdoub, int alloc); -struct ent * dogetent(int r, int c); -double donval(char * colstr, double rowdoub); -double dolmax(struct ent * e, struct enode * ep); -double dolmin(struct ent * e, struct enode * ep); -//double eval(register struct enode *e); -double eval(register struct ent * ent, register struct enode * e); +struct ent * getent(struct sheet * sh, char * colstr, double rowdoub, int alloc); +double eval(struct sheet * sh, struct ent * ent, struct enode * e); double fn1_eval(double (* fn)(), double arg); double fn2_eval(double (* fn)(), double arg1, double arg2); -char * docat(register char * s1, register char * s2); -char * dodate(time_t tloc, char * fmtstr); -char * dofmt(char * fmtstr, double v); -char * doext(struct enode * se); -char * doext(struct enode * se); -char * dosval(char * colstr, double rowdoub); -char * dosubstr(char * s, register int v1, register int v2); -char * docase(int acase, char * s); -char * docapital(char * s); -char * seval(register struct ent * ent, register struct enode * se); +char * seval(struct sheet * sh, struct ent * ent, struct enode * se); void setiterations(int i); void EvalAll(); struct enode * new(int op, struct enode * a1, struct enode * a2); @@ -94,22 +62,22 @@ void g_free(); void go_last(); void go_previous(); -void moveto(int row, int col, int lastrow, int lastcol, int cornerrow, int cornercol); -void num_search(double n, int firstrow, int firstcol, int lastrow, int lastcol, int errsearch, int flow); -void str_search(char * s, int firstrow, int firstcol, int lastrow, int lastcol, int num, int flow); -void fill(struct ent * v1, struct ent * v2, double start, double inc); -void lock_cells(struct ent * v1, struct ent * v2); -void unlock_cells(struct ent * v1, struct ent * v2); -void let(struct ent * v, struct enode * e); -void slet(struct ent * v, struct enode * se, int flushdir); -void format_cell(struct ent * v1, struct ent * v2, char * s); -int constant(register struct enode * e); +void moveto(struct sheet * sh, int row, int col, int lastrow_, int lastcol_, int cornerrow, int cornercol); +void num_search(struct sheet * sh, double n, int firstrow, int firstcol, int lastrow, int lastcol, int errsearch, int flow); +void str_search(struct sheet * sh, char * s, int firstrow, int firstcol, int lastrow, int lastcol, int num, int flow); +void fill(struct sheet * sh, struct ent * v1, struct ent * v2, double start, double inc); +void lock_cells(struct sheet * sh, struct ent * v1, struct ent * v2); +void unlock_cells(struct sheet * sh, struct ent * v1, struct ent * v2); +void let(struct roman * roman, struct sheet * sh, struct ent * v, struct enode * e); +void slet(struct roman * roman, struct sheet * sh, struct ent * v, struct enode * se, int flushdir); +void format_cell(struct sheet * sh, struct ent * v1, struct ent * v2, char *s); +int constant(struct enode * e); void efree(struct enode * e); -void label(register struct ent * v, register char * s, int flushdir); +void label(struct ent * v, char * s, int flushdir); void decodev(struct ent_ptr v); char * coltoa(int col); void decompile_list(struct enode * p); -void decompile(register struct enode * e, int priority); +void decompile(struct enode * e, int priority); void index_arg(char * s, struct enode * e); void two_arg_index(char * s, struct enode * e); void list_arg(char * s, struct enode * e); @@ -117,14 +85,19 @@ void two_arg(char * s, struct enode * e); void three_arg(char * s, struct enode * e); void range_arg(char * s, struct enode * e); -void editfmt(int row, int col); -void editv(int row, int col); -void editexp(int row, int col); -void edits(int row, int col, int saveinfile); -int dateformat(struct ent * v1, struct ent * v2, char * fmt); -double rint(double d); +void editfmt(struct sheet * sh, int row, int col); +void editv(struct sheet * sh, int row, int col); +void editexp(struct sheet * sh, int row, int col); +void edits(struct sheet * sh, int row, int col, int saveinfile); +int dateformat(struct sheet * sh, struct ent *v1, struct ent *v2, char * fmt); -void EvalAllVertexs(); -void EvalJustOneVertex(register struct ent * p, int rebuild_graph); -double doevaluate(char * s); -char * dosevaluate(char * s); +extern void EvalAllVertexs(); +extern void EvalJustOneVertex(struct sheet * sh, struct ent * p, int rebuild_graph); + +/* g_type can be: */ +#define G_NONE 0 /* Starting value - must be 0 */ +#define G_NUM 1 +#define G_STR 2 +#define G_NSTR 3 +#define G_XSTR 4 +#define G_CELL 5 diff -Nru sc-im-0.8.2+ds/src/lex.c sc-im-0.8.3+ds/src/lex.c --- sc-im-0.8.2+ds/src/lex.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/lex.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/lex.h sc-im-0.8.3+ds/src/lex.h --- sc-im-0.8.2+ds/src/lex.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/lex.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/lua.c sc-im-0.8.3+ds/src/lua.c --- sc-im-0.8.2+ds/src/lua.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/lua.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -64,7 +64,7 @@ #include #include "sc.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "trigger.h" #include "utils/string.h" #include "main.h" @@ -72,6 +72,7 @@ #include "conf.h" #include "file.h" +extern struct session * session; extern FILE * fdoutput; #define LC_NUMBER2(n,v) \ @@ -92,13 +93,15 @@ */ static int l_getnum (lua_State *L) { - int r,c; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r, c; struct ent **pp; struct ent *p; c = lua_tointeger(L, 1); /* get argument */ r = lua_tointeger(L, 2); // sc_debug("getnum !!"); - pp = ATBL(tbl,r,c); + pp = ATBL(sh, sh->tbl, r, c); p = *pp; if (p == 0) return 0; @@ -117,20 +120,22 @@ */ static int l_setnum (lua_State *L) { - int r,c; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r, c; double val; //struct ent ** pp; struct ent *p; c = lua_tointeger(L, 1); /* get argument */ r = lua_tointeger(L, 2); - val=lua_tonumber(L,3); + val=lua_tonumber(L, 3); //sc_debug("getnum !!"); - p=lookat(r,c); + p=lookat(sh, r,c); p->v=val; p->flags |= is_changed |is_valid; p->flags &= ~iscleared; - modflg++; + roman->modflg++; p->cellerror =CELLOK; return 0; @@ -145,16 +150,18 @@ */ static int l_setstr (lua_State *L) { - int r,c; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r, c; char * val; //struct ent ** pp; - struct ent *p; + struct ent * p; c = lua_tointeger(L, 1); /* get argument */ r = lua_tointeger(L, 2); - val=(char *) lua_tostring(L,3); + val=(char *) lua_tostring(L, 3); //sc_debug("setstr !!"); - p=lookat(r,c); + p=lookat(sh, r,c); label(p,val,-1); return 0; @@ -168,7 +175,9 @@ */ static int l_getstr (lua_State *L) { - int r,c; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + int r, c; //struct ent ** pp; struct ent *p; @@ -177,10 +186,10 @@ //sc_debug("setstr !!"); - p=lookat(r,c); - if(p == 0) return 0; - if(p->label !=0) { - lua_pushstring(L,p->label); + p = lookat(sh, r, c); + if (p == 0) return 0; + if (p->label !=0) { + lua_pushstring(L, p->label); return 1; } @@ -194,11 +203,11 @@ */ static int l_setform (lua_State *L) { - int r,c; + int r, c; char * val; wchar_t buf[BUFFERSIZE]; - r = lua_tointeger(L, 1); /* get argument */ - c = lua_tointeger(L, 2); + r = lua_tointeger(L, 2); /* get argument */ + c = lua_tointeger(L, 1); val = (char *) lua_tostring(L,3); swprintf(buf, FBUFLEN, L"LET %s%d=%s", coltoa(c), r, val); send_to_interp(buf); @@ -232,8 +241,8 @@ int c, r; char buf[16]; - r = lua_tointeger(L, 1); /* get argument */ - c = lua_tointeger(L, 2); + r = lua_tointeger(L, 2); /* get argument */ + c = lua_tointeger(L, 1); sprintf(buf,"%s%d", coltoa(c),r); lua_pushstring(L,buf); return 1; @@ -290,10 +299,11 @@ return 1; } -LC_NUMBER2(currow,currow) -LC_NUMBER2(curcol,curcol) -LC_NUMBER2(maxcols,maxcols) -LC_NUMBER2(maxrows,maxrows) + +LC_NUMBER2(currow, session->cur_doc->cur_sh->currow) +LC_NUMBER2(curcol, session->cur_doc->cur_sh->curcol) +LC_NUMBER2(maxcols, session->cur_doc->cur_sh->maxcols) +LC_NUMBER2(maxrows, session->cur_doc->cur_sh->maxrows) static const luaL_Reg sclib[] = { { "lgetnum", l_getnum }, @@ -372,12 +382,12 @@ * \return none */ -char * doLUA( struct enode * se, int type) { +char * doLUA(struct sheet * sh, struct enode * se, int type) { if ( ! get_conf_int("exec_lua")) return 0; char * cmd; char buffer[PATHLEN]; char buffer1[PATHLEN]; - cmd = seval(NULL, se->e.o.left); + cmd = seval(sh, NULL, se->e.o.left); sprintf(buffer, "lua/%s", cmd); if (plugin_exists(buffer, strlen(buffer), buffer1)) { diff -Nru sc-im-0.8.2+ds/src/lua.h sc-im-0.8.3+ds/src/lua.h --- sc-im-0.8.2+ds/src/lua.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/lua.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -43,7 +43,7 @@ */ #ifdef XLUA -char * doLUA(struct enode * se, int type); +char * doLUA(struct sheet * sh, struct enode * se, int type); void doLuainit(); void doLuaTrigger_cell(struct ent * p, int rw); void doLuaclose(); diff -Nru sc-im-0.8.2+ds/src/macros.h sc-im-0.8.3+ds/src/macros.h --- sc-im-0.8.2+ds/src/macros.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/macros.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -39,7 +39,7 @@ * \file macros.h * \author Andrés Martinelli * \date 2017-07-18 - * \brief Header file for cros.c + * \brief Header file for macros.c */ #define BUFFERSIZE 1024 // must be higher than MAX_IB_LEN @@ -52,9 +52,11 @@ #define TIMEOUT_CURSES 300 // ms curses input timeout #define COMPLETECMDTIMEOUT (get_conf_int("command_timeout")/4) // used for goto cell #define ESC_DELAY 25 // Escape timeout -#define RESCOL 4 // columns reserved for row numbers + #define RESROW 2 // rows reserved for prompt, error, and column numbers #define RESCOLHEADER 1 // number of row to show column header. always 1. just to make code cleaner +#define SC_DISPLAY_ROWS (LINES - RESROW - RESCOLHEADER) +#define SC_DISPLAY_COLS (COLS - session->cur_doc->cur_sh->rescol) #define NORMAL_MODE 0x01 #define INSERT_MODE 0x02 @@ -90,32 +92,6 @@ #define EDITION_CMD 1 #define MOVEMENT_CMD 2 -#define HEADINGS 0 -#define WELCOME 1 -#define CELL_SELECTION 2 -#define CELL_SELECTION_SC 3 -#define NUMB 4 -#define STRG 5 -#define DATEF 6 -#define EXPRESSION 7 -#define INFO_MSG 8 -#define ERROR_MSG 9 -#define MODE 10 -#define CELL_ID 11 -#define CELL_FORMAT 12 -#define CELL_CONTENT 13 -#define INPUT 14 -#define NORMAL 15 -#define CELL_ERROR 16 -#define CELL_NEGATIVE 17 -#define DEFAULT 18 -#define DEBUG_MSG 19 -#define VALUE_MSG 20 -#define GRID_EVEN 21 -#define GRID_ODD 22 -#define HEADINGS_ODD 23 -#define HELP_HIGHLIGHT 24 - void ui_sc_msg(char * s, int type, ...); #define sc_error(x, ...) ui_sc_msg(x, ERROR_MSG, ##__VA_ARGS__) #define sc_debug(x, ...) ui_sc_msg(x, DEBUG_MSG, ##__VA_ARGS__) diff -Nru sc-im-0.8.2+ds/src/main.c sc-im-0.8.3+ds/src/main.c --- sc-im-0.8.2+ds/src/main.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/main.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -38,18 +38,10 @@ /** * \file main.c * \author Andrés Martinelli - * \date 2017-07-18 + * \date 2021-05-22 * \brief The main file of sc-im - * * \details This is the main file for sc-im. - * * \see Homepage: https://github.com/andmarti1424/sc-im - * - * \bug It has been detected that libxls can produce memory leaks. One example - * is when you try to read a non xls file (e.g. xlsx file). - * - * \bug Extended ascii characters are not showing correctly. Compile sc-im - * against -lncursesw and not -lncurses. */ #include @@ -67,11 +59,12 @@ #endif #include "main.h" -#include "shift.h" +#include "actions/shift.h" #include "macros.h" #include "tui.h" #include "input.h" #include "marks.h" +#include "format.h" #include "maps.h" #include "yank.h" #include "file.h" @@ -80,10 +73,11 @@ #include "history.h" #include "conf.h" #include "buffer.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "vmtbl.h" // for growtbl -#include "filter.h" -#include "dep_graph.h" +#include "actions/filter.h" +#include "graph.h" +#include "sheet.h" #ifdef UNDO #include "undo.h" @@ -93,74 +87,67 @@ #include "lua.h" #endif -int currow = 0; /**< Current row of the selected cell. */ -int curcol = 0; /**< Current column of the selected cell. */ -int lastrow = 0; -int lastcol = 0; -int maxrows; -int maxcols; -unsigned char * col_hidden; -unsigned char * col_frozen; -int * fwidth; -int * precision; -int * realfmt; -unsigned char * row_hidden; -unsigned char * row_frozen; -unsigned char * row_format; -char line[FBUFLEN]; -int modflg; /**< Indicates a change was made since last save */ -struct ent *** tbl; -int shall_quit = 0; -unsigned int curmode; -unsigned int lastmode; -int maxrow, maxcol; -char curfile[PATHLEN]; +// global variable to store a session +struct session * session; + +// this variable stores the filename passed to sc-im via argv +// by design, if more than one is passed, we keep the last one. char loadingfile[PATHLEN] = { '\0' }; -char * exepath; +// app attributes. TODO: should be later added to conf +int calc_order = BYROWS; +char dpoint = '.'; /* Default decimal point character */ +char thsep = ','; /* Default thousands separator character */ + +// check +char * exepath; int changed; int cellassign; int arg = 1; -int brokenpipe = FALSE; /**< Set to true if SIGPIPE is received */ -char * ascext; -char * tbl0ext; -char * tblext; -char * latexext; -char * slatexext; -char * texext; -char dpoint = '.'; /**< Default decimal point character */ -char thsep = ','; /**< Default thousands separator character */ -int linelim = -1; -int calc_order = BYROWS; -int optimize = 0; /**< Causes numeric expressions to be optimizedv */ -int tbl_style = 0; /**< Headers for T command output */ +int brokenpipe = FALSE; /* Set to true if SIGPIPE is received */ +int optimize = 0; /* Causes numeric expressions to be optimizedv */ int rndtoeven = 0; int rowsinrange = 1; int colsinrange = DEFWIDTH; +FILE * fdoutput; /* Output file descriptor (stdout or file) */ + +// used by interp +char line[FBUFLEN]; +int linelim = -1; double eval_result; char * seval_result; -FILE * fdoutput; /**< Output file descriptor (stdout or file) */ -int rescol = RESCOL; /**< Columns reserved for row numbers */ + + +/* shall_quit is a variable to determinate if sc-im must be closed + * shall_quit=0 means normal operation of app + * shall_quit=1 means :q + * shall_quit=-1 means ERROR or SIGABRT signal + * shall_quit=2 means :q! + * TODO: add macros here + */ +int shall_quit = 0; + +unsigned int curmode; +unsigned int lastmode; struct block * buffer; struct block * lastcmd_buffer; -struct dictionary * user_conf_d; /**< User's configuration dictionary */ +struct dictionary * user_conf_d; /* User's configuration dictionary */ struct history * commandline_history; struct history * insert_history; char stderr_buffer[1024] = ""; -struct timeval startup_tv, current_tv; /**< Runtime timer */ +struct timeval startup_tv, current_tv; /* Runtime timer */ #ifdef AUTOBACKUP -struct timeval lastbackup_tv; /**< Last backup timer */ +struct timeval lastbackup_tv; /* Last backup timer */ #ifdef HAVE_PTHREAD #include -int pthread_exists = 0; /**< Return status of pthread_create */ +int pthread_exists = 0; /* Return status of pthread_create */ pthread_t fthread; #endif #endif -void read_stdin(); -extern char * rev; +extern graphADT graph; /** * \brief The main() function @@ -176,12 +163,8 @@ * first string is the executable's name. This is passed to main() by * the system. * - * \return 0 on success; 1 on some errors; -1 on error + * \return 0 on success; -1 on errors */ - -// TODO Document the possible errors. Why are some things -1 while others -// are 1? Look for instances of exit_app(). - int main (int argc, char ** argv) { // Define how the file stream should be buffered. Error if unsuccessful. if (setvbuf(stderr, stderr_buffer, _IOFBF, STDERRBUF) != 0) { @@ -206,15 +189,14 @@ read_argv(argc, argv); // check if help is in argv. if so, show usage and quit - if (get_conf_int("help")) - show_usage_and_quit(); + if (get_conf_int("help")) show_usage_and_quit(); // check if version is in argv. if so, show version and quit - if (get_conf_int("version")) - show_version_and_quit(); + if (get_conf_int("version")) show_version_and_quit(); - // create command line history structure + // if starting tui.. if (! get_conf_int("nocurses")) { + // create command line history structure #ifdef HISTORY_FILE commandline_history = (struct history *) create_history(':'); load_history(commandline_history, ':'); // load the command history file @@ -223,16 +205,8 @@ insert_history = (struct history *) create_history('='); load_history(insert_history, '='); // load the insert history file #endif - } - - // create basic structures that will depend on the loaded file - create_structures(); - - // setup the spreadsheet arrays (tbl) - if (! growtbl(GROWNEW, 0, 0)) return exit_app(1); - // initiate NCURSES if that is what is wanted - if (! get_conf_int("nocurses")) { + // and initiate NCURSES ui_start_screen(); #ifdef USECOLORS @@ -250,9 +224,9 @@ } /* - * If the 'output' parameter is defined, SC-IM saves its output to that file. + * If the 'output' parameter is defined, sc-im saves its output to that file. * To achieve that, we open the output file and keep it open until exit. - * otherwise, SC-IM will output to stdout. + * otherwise, sc-im will output to stdout. */ if (get_conf_value("output") != NULL) { fdoutput = fopen(get_conf_value("output"), "w+"); @@ -275,30 +249,55 @@ wchar_t stdin_buffer[BUFFERSIZE] = { L'\0' }; - // if there was no file passed to scim executable - // 1. erase db ! - if (! loadingfile[0]) erasedb(); + // take this out of here --> + calc_order = BYROWS; + prescale = 1.0; + optimize = 0; // <---- + + // create basic structures that will depend on the loaded file + create_structures(); + + // create main session + session = (struct session *) calloc(1, sizeof(struct session)); + + /* + * create a new roman struct for each file passed as argv + * and attach it to main session + * DISABLED BY DESIGN + * readfile_argv(argc, argv); + */ + + /* load file passed as argv to sc-im. + * if more than one file is passed, consider the last one. + */ + load_file(strlen(loadingfile) ? loadingfile : NULL); - // 2. loadrc - loadrc(); + /* + * check if session->cur_doc is NULL (no file passed as argv). + * if so, create an empty doc with just one sheet + */ + if (session->cur_doc == NULL) create_empty_wb(); - // 3. read sc file passed as argv - load_sc(); + /* + * load_rc. Since we are not sure what people put it their scimrc file, + * other than configuration variables and mappings, + * we call the load_rc() routine after session / roman / sheet are alloc'ed. + */ + load_rc(); - // 4. check input from stdin (pipeline) + // check input from stdin (pipeline) // and send it to interp read_stdin(); - // change curmode to NORMAL_MODE chg_mode('.'); // initiate ui FILE * f; if ( ! get_conf_int("nocurses")) { - // we show welcome screen if no spreadsheet was passed to SC-IM + // we show welcome screen if no spreadsheet was passed to sc-im // and no input was sent throw pipeline - if ( ! curfile[0] && ! wcslen(stdin_buffer)) { + if ( ! session->cur_doc->name && ! wcslen(stdin_buffer)) { ui_do_welcome(); // show mode and cell's details in status bar ui_print_mode(); @@ -313,8 +312,8 @@ } // handle input from keyboard - if (! get_conf_int("nocurses")) - buffer = (struct block *) create_buf(); // this should only take place if curses ui + // this should only take place if curses ui + if (! get_conf_int("nocurses")) buffer = (struct block *) create_buf(); wchar_t nocurses_buffer[BUFFERSIZE]; @@ -326,22 +325,8 @@ lastbackup_tv = (struct timeval) {0}; #endif - if (get_conf_value("export_csv")) { - export_delim(NULL, ',', 0, 0, maxrow, maxcol, 0); - } - - if (get_conf_value("export_tab")) { - export_delim(NULL, '\t', 0, 0, maxrow, maxcol, 0); - } - - if (get_conf_value("export_mkd")) { - export_markdown(NULL, 0, 0, maxrow, maxcol); - } - - if (get_conf_value("export") || get_conf_value("export_txt")) { - export_plain(NULL, 0, 0, maxrow, maxcol); - } - + // handle --exports passed as argv + handle_argv_exports(); while ( ! shall_quit && ! get_conf_int("quit_afterload")) { // save current time for runtime timer @@ -360,8 +345,12 @@ send_to_interp(nocurses_buffer); } - /* shall_quit=1 means :q - shall_quit=2 means :q! */ + /* + * shall_quit=0 means normal operation of app + * shall_quit=1 means :q + * shall_quit=-1 means ERROR or ABRT signal + * shall_quit=2 means :q! + */ if (shall_quit == 1 && modcheck()) shall_quit = 0; } if (get_conf_int("nocurses") && f != NULL) fclose(f); @@ -369,15 +358,13 @@ return shall_quit == -1 ? exit_app(-1) : exit_app(0); } -extern graphADT graph; /** - * \brief Creates the structures used by the program. - * + * \brief Creates the basic structures used by sc-im * \return none */ - void create_structures() { + // initiate mark array create_mark_array(); @@ -397,12 +384,11 @@ graph = GraphCreate(); } + /** - * \brief TODO Document read_stdin() - * + * \brief read_stdin() * \return none */ - void read_stdin() { //sc_debug("reading stdin from pipeline"); fd_set readfds; @@ -436,9 +422,9 @@ //sc_debug("finish reading"); } + /** * \brief Delete basic structures that depend on the loaded files. - * * \return none */ void delete_structures() { @@ -449,6 +435,9 @@ // Free yanklist free_yanklist(); + // free custom col formats + free_formats(); + // Erase last_command buffer erase_buf(lastcmd_buffer); @@ -463,35 +452,36 @@ clear_undo_list(); #endif - // Free lua stuff -#ifdef XLUA - doLuaclose(); -#endif - // free deleted ents flush_saved(); // free calc chain graph destroy_graph(graph); - // Free ents of tbl - erasedb(); + // Free tbl / sheet / roman / session + free_session(session); // free custom_colors free_custom_colors(); + + // Free lua stuff +#ifdef XLUA + doLuaclose(); +#endif } + /** * \brief Cleans things up just before exiting the program. * * \param[in] status * \param[out] status * - * \return status is returned unchanged + * \return status is returned unchanged: + * return 0 on normal exit. + * return -1 on error. */ - int exit_app(int status) { - // free history if (! get_conf_int("nocurses")) { @@ -513,7 +503,8 @@ // remove backup file #ifdef AUTOBACKUP - if (strlen(curfile) && backup_exists(curfile)) remove_backup(curfile); + char * filename = session->cur_doc->name; + if (filename != NULL && strlen(filename) && backup_exists(filename)) remove_backup(filename); #endif // erase structures @@ -540,10 +531,11 @@ return status; } + /** - * \brief Read command line parameters and store them in a dictionary + * \brief Read command line parameters and store them in a dictionary * - * \details Read parameters passed to SC-IM executable and + * \details Read parameters passed to sc-im executable and * store them in user_conf dictionary. * * \param[in] argc (argument count) is the number of strings pointed to by @@ -554,13 +546,13 @@ * * \return none */ - void read_argv(int argc, char ** argv) { int i; for (i = 1; i < argc; i++) { if ( ! strncmp(argv[i], "--", 2) ) { // it was passed a parameter parse_str(user_conf_d, argv[i] + 2, 0); } else { // it was passed a file + //printf("%s-\n", argv[i]); strncpy(loadingfile, argv[i], PATHLEN-1); } } @@ -568,72 +560,41 @@ return; } + /** - * \brief Attempt to load a file - * + * \brief handle_argv_exports() + * TODO: move to a new offline.c * \return none */ - -void load_sc() { - char name[PATHLEN]; - strcpy(name, ""); //force name to be empty - #ifdef NO_WORDEXP - size_t len; - #else - int c; - wordexp_t p; - #endif - - #ifdef NO_WORDEXP - if ((len = strlen(loadingfile)) >= sizeof(name)) { - sc_info("File path too long: '%s'", loadingfile); - return; - } - memcpy(name, loadingfile, len+1); - #else - wordexp(loadingfile, &p, 0); - for (c=0; c < p.we_wordc; c++) { - if (c) sprintf(name + strlen(name), " "); - sprintf(name + strlen(name), "%s", p.we_wordv[c]); +void handle_argv_exports() { + if (get_conf_value("export_csv") && session->cur_doc != NULL) { + export_delim(NULL, ',', 0, 0, session->cur_doc->cur_sh->maxrow, session->cur_doc->cur_sh->maxcol, 0); } - wordfree(&p); - #endif - if (strlen(name) != 0) { - sc_readfile_result result = readfile(name, 0); - if (!get_conf_int("nocurses")) { - if (result == SC_READFILE_DOESNTEXIST) { - // It's a new record! - sc_info("New file: \"%s\"", name); - } else if (result == SC_READFILE_ERROR) { - sc_info("\"%s\" is not a SC-IM compatible file", name); - } - } + if (get_conf_value("export_tab") && session->cur_doc != NULL) { + export_delim(NULL, '\t', 0, 0, session->cur_doc->cur_sh->maxrow, session->cur_doc->cur_sh->maxcol, 0); } -} -/** - * \brief Set the calculation order - * - * \return none - */ + if (get_conf_value("export_mkd") && session->cur_doc != NULL) { + export_markdown(NULL, 0, 0, session->cur_doc->cur_sh->maxrow, session->cur_doc->cur_sh->maxcol); + } -void setorder(int i) { - if ((i == BYROWS) || (i == BYCOLS)) calc_order = i; + if ((get_conf_value("export") || get_conf_value("export_txt")) && session->cur_doc != NULL) { + export_plain(NULL, 0, 0, session->cur_doc->cur_sh->maxrow, session->cur_doc->cur_sh->maxcol); + } return; } + /** - * \brief Set signals catched by sc-im - * + * \brief Set up signals catched by sc-im * \return none */ - void signals() { void sig_int(); void sig_abrt(); void sig_term(); - void nopipe(); + void sig_nopipe(); void sig_winchg(); void sig_tstp(); void sig_cont(); @@ -641,7 +602,7 @@ signal(SIGINT, sig_int); signal(SIGABRT, sig_abrt); signal(SIGTERM, sig_term); // kill - signal(SIGPIPE, nopipe); + signal(SIGPIPE, sig_nopipe); //(void) signal(SIGALRM, time_out); signal(SIGWINCH, sig_winchg); //(void) signal(SIGBUS, doquit); @@ -651,27 +612,22 @@ return; } + /** * \brief Handles the SIGPIPE signal - * * \return none */ - -// TODO Possibly rename this function to sig_nopipe() for consistency -// with the other signal functions. - -void nopipe() { +void sig_nopipe() { sc_error("brokenpipe!"); brokenpipe = TRUE; return; } + /** * \brief Handles the SIGTSTP signal - * * \return none */ - void sig_tstp() { //sc_info("Got SIGTSTP."); def_prog_mode(); @@ -683,10 +639,8 @@ /** * \brief Handles the SIGCONT signal - * * \return none */ - void sig_cont() { signal(SIGTSTP, sig_tstp); /* set handler back to this */ sig_winchg(); @@ -696,189 +650,40 @@ //sc_info("Got SIGCONT."); } + /** * \brief Handles the SIGINT signal - * * \return none */ - void sig_int() { - if ( ! get_conf_int("debug")) - sc_error("Got SIGINT. Press «:q» to quit SC-IM"); - else + if ( ! get_conf_int("debug")) { + sc_error("Got SIGINT. Press «:q» to quit sc-im"); + } else if (get_bufsize(buffer)) { + break_waitcmd_loop(buffer); + } else { shall_quit = 2; + } return; } + /** * \brief Handles the SIGABRT signal - * * \return none */ - void sig_abrt() { - sc_error("Error !!! Quitting SC-IM."); + sc_error("Error !!! Quitting sc-im."); shall_quit = -1; // error ! return; } + /** * \brief Handles the SIGABRT signal - * * \return none */ - void sig_term() { - sc_error("Got SIGTERM signal. Quitting SC-IM."); + sc_error("Got SIGTERM signal. Quitting sc-im."); shall_quit = 2; return; } - -/** - * \brief Send the version number to standard output and quit. - * - * \return none - */ - -// TODO Split this into two commands. One prints the version number -// the other prints the version number along with the other information. - -void show_version_and_quit() { - put(user_conf_d, "nocurses", "1"); - sc_info("SC-IM - %s", rev); -#ifdef NCURSES - sc_info("-DNCURSES"); -#endif -#ifdef MAXROWS - sc_info("-DMAXROWS %d", MAXROWS); -#endif -#ifdef UNDO - sc_info("-DUNDO"); -#endif -#ifdef XLS - sc_info("-DXLS"); -#endif -#ifdef XLSX - sc_info("-DXLSX"); -#endif -#ifdef XLSX_EXPORT - sc_info("-DXLSX_EXPORT"); -#endif -#ifdef XLUA - sc_info("-DXLUA"); -#endif -#ifdef DEFAULT_COPY_TO_CLIPBOARD_CMD - sc_info("-DDEFAULT_COPY_TO_CLIPBOARD_CMD=\"%s\"", DEFAULT_COPY_TO_CLIPBOARD_CMD); -#endif -#ifdef DEFAULT_PASTE_FROM_CLIPBOARD_CMD - sc_info("-DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\"%s\"", DEFAULT_PASTE_FROM_CLIPBOARD_CMD); -#endif -#ifdef DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD - sc_info("-DDEFAULT_OPEN_FILE_UNDER_CURSOR_CMD=\"%s\"", DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD); -#endif -#ifdef USELOCALE - sc_info("-DUSELOCALE"); -#endif -#ifdef MOUSE - sc_info("-DMOUSE"); -#endif -#ifdef USECOLORS - sc_info("-DUSECOLORS"); -#endif -#ifdef _XOPEN_SOURCE_EXTENDED - sc_info("-D_XOPEN_SOURCE_EXTENDED"); -#endif -#ifdef _GNU_SOURCE - sc_info("-D_GNU_SOURCE"); -#endif -#ifdef SNAME - sc_info("-DSNAME=\"%s\"", SNAME); -#endif -#ifdef HELP_PATH - sc_info("-DHELP_PATH=\"%s\"", HELP_PATH); -#endif -#ifdef LIBDIR - sc_info("-DLIBDIR=\"%s\"", LIBDIR); -#endif -#ifdef DFLT_PAGER - sc_info("-DDFLT_PAGER=\"%s\"", DFLT_PAGER); -#endif -#ifdef DFLT_EDITOR - sc_info("-DDFLT_EDITOR=\"%s\"", DFLT_EDITOR); -#endif -#ifdef CONFIG_DIR - sc_info("-DCONFIG_DIR=\"%s\"", CONFIG_DIR); -#endif -#ifdef CONFIG_FILE - sc_info("-DCONFIG_FILE=\"%s\"", CONFIG_FILE); -#endif -#ifdef HISTORY_DIR - sc_info("-DHISTORY_DIR=\"%s\"", HISTORY_DIR); -#endif -#ifdef HISTORY_FILE - sc_info("-DHISTORY_FILE=\"%s\"", HISTORY_FILE); -#endif -#ifdef INS_HISTORY_FILE - sc_info("-DINS_HISTORY_FILE=\"%s\"", INS_HISTORY_FILE); -#endif -#ifdef HAVE_PTHREAD - sc_info("-DHAVE_PTHREAD"); -#endif -#ifdef AUTOBACKUP - sc_info("-DAUTOBACKUP"); -#endif - put(user_conf_d, "quit_afterload", "1"); -} - -/** - * \brief Print usage message to stdout text and quit - * - * \return none - */ - -// NOTE this is a quick and dirty command to search for arguments used in the sources (macOS 10.14) -// grep "get_conf_value(\"" -r ./src/*.c | grep get_conf_value |sed 's/"//g' |sed 's/.*get_conf_value(//g'|cut -d ')' -f1 |sort|uniq|sed 's/^/--/g' -void show_usage_and_quit(){ - put(user_conf_d, "nocurses", "1"); - printf("\ -\nSC-IM - SC Improved\ -\n\ -\nUsage: sc-im [arguments] [file] specified file\ -\n or: sc-im [arguments] - read text from stdin\ -\n\ -\nArguments:\ -\n\ -\n --autocalc Set variable 'autocalc'.\ -\n --copy_to_clipboard_delimited_tab Set variable 'copy_to_clipboard_delimited_tab'\ -\n --debug Set variable 'debug'\ -\n --default_copy_to_clipboard_cmd=COMMAND set variable 'default_copy_from_clipboard_cmd'\ -\n --default_paste_from_clipboard_cmd=COMMAND set variable 'default_paste_from_clipboard_cmd'\ -\n --default_open_file_under_cursor_cmd=COMMAND set variable 'default_open_file_under_cursor_cmd'\ -\n --export_csv Export to csv without interaction\ -\n --export_tab Export to tab without interaction\ -\n --export_txt Export to txt without interaction\ -\n --export_mkd Export to markdown without interaction\ -\n --external_functions Set variable 'external_functions'\ -\n --half_page_scroll Set variable 'half_page_scroll'\ -\n --ignorecase Set variable 'ignorecase'\ -\n --import_delimited_as_text Import text as\ -\n --newline_action={j or l} Set variable 'newline_action'\ -\n --nocurses Run interactive but without ncurses interface.\ -\n --numeric Set variable 'numeric'\ -\n --numeric_decimal Set variable 'numeric_decimal'\ -\n --output=FILE Save the results in FILE\ -\n --overlap Set variable 'overlap variable'\ -\n --quit_afterload Quit after loading all the files\ -\n --show_cursor Make the screen cursor follow the active cell\ -\n --tm_gmtoff={seconds} set gmt offset used for converting datetimes to localtime.\ -\n --txtdelim={\",\" or \";\" or \"\\t\" or \"|\"} Sets delimiter when opening a .tab of .csv file"); -#ifdef XLSX - printf("\n\ -\n --sheet=SHEET Open SHEET when loading xlsx file. Default is 1.\ -\n --xlsx_readformulas Set variable 'xlsx_readformulas'"); -#endif - printf("\n\ -\n --version Print version information and exit\ -\n --help Print Help (this message) and exit\n"); - put(user_conf_d, "quit_afterload", "1"); -} diff -Nru sc-im-0.8.2+ds/src/main.h sc-im-0.8.3+ds/src/main.h --- sc-im-0.8.2+ds/src/main.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/main.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -47,18 +47,17 @@ int exit_app(int status); void create_structures(); void delete_structures(); -void load_sc(); + void read_argv(int argc, char ** argv); -void setorder(int i); -void nopipe(); -void signals(); +void read_stdin(); +void handle_argv_exports(); void show_version_and_quit(); void show_usage_and_quit(); -// SIGINT signal +// signals +void signals(); void sig_int(); - -// SIGWINCH signal - resize of terminal +void sig_nopipe(); void sig_winchg(); extern FILE * fdoutput; // output file descriptor (stdout or file) diff -Nru sc-im-0.8.2+ds/src/Makefile sc-im-0.8.3+ds/src/Makefile --- sc-im-0.8.2+ds/src/Makefile 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/Makefile 2023-01-16 15:38:03.000000000 +0000 @@ -58,16 +58,16 @@ # Choose one of the following commands for copying to different clipboards: # You can later change it at runtime. #to copy to tmux clipboard: -CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""tmux load-buffer"\" +#CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""tmux load-buffer"\" #to copy to X clipboard: -#CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""xclip -i -selection clipboard <"\" +CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""xclip -i -selection clipboard <"\" #to copy to OSX clipboard: #CFLAGS += -DDEFAULT_COPY_TO_CLIPBOARD_CMD=\""pbcopy <"\" # # Choose one of the proposed commands for pasting from different clipboards: # You can later change it at runtime. -CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""tmux show-buffer"\" -#CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""xclip -o -selection clipboard"\" +#CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""tmux show-buffer"\" +CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""xclip -o -selection clipboard"\" #CFLAGS += -DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\""pbpaste"\" # Command to open file or link under cursor @@ -168,7 +168,7 @@ LDFLAGS += -lncursesw endif -OBJS = $(patsubst %.c, %.o, $(wildcard *.c) $(wildcard utils/*.c)) gram.o +OBJS = $(patsubst %.c, %.o, $(wildcard *.c) $(wildcard actions/*.c) $(wildcard formats/*.c) $(wildcard cmds/*.c) $(wildcard utils/*.c)) gram.o .PHONY : all clean install docs man_install man_uninstall diff -Nru sc-im-0.8.2+ds/src/maps.c sc-im-0.8.3+ds/src/maps.c --- sc-im-0.8.2+ds/src/maps.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/maps.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -106,8 +106,8 @@ while (m != NULL) { // Check if a mapping already exists in 'b' buffer int pos = block_in_block(b, m->in); - if (pos != -1 && m->mode == curmode) { + if (pos != -1 && m->mode == curmode) { // Replace m->in with m->out in 'b' list if (replace_block_in_block(b, m->in, m->out) == -1) { sc_error("error replacing maps"); @@ -143,12 +143,17 @@ unsigned short l = wcslen(wc); for (i=0; i mappings + if (str[i] == '\\' && i+1 < l && i+2 < l && str[i+1] == '\\' && + (str[i+2] == '<' || str[i+2] == '>')) { + addto_buf(buffer, (wint_t) wc[i+2]); + i += 2; // Add special keys - if (str[i] == '<') { + } else if (str[i] == '<' && !(i>0 && str[i-1] == '\\')) { is_specialkey = 1; - } else if (str[i] == '>') { + } else if (str[i] == '>' && !(i>0 && str[i-1] == '\\')) { is_specialkey = 0; if (! strcasecmp(sk, "CR")) // CR - ENTER key addto_buf(buffer, OKEY_ENTER); diff -Nru sc-im-0.8.2+ds/src/maps.h sc-im-0.8.3+ds/src/maps.h --- sc-im-0.8.2+ds/src/maps.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/maps.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/marks.c sc-im-0.8.3+ds/src/marks.c --- sc-im-0.8.2+ds/src/marks.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/marks.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -34,12 +34,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *******************************************************************************/ - /** * \file marks.c * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. + * \date 28/05/2021 + * \brief source code for handling marks + * NOTE: 'a' - 'z' = 26 + * '0' - '1' = 10 + * 'a' = 97. */ #include @@ -47,99 +49,101 @@ #include "macros.h" #define NUM_MARKS 128 + static struct mark * marks; -// 'a' - 'z' = 26 -// '0' - '1' = 10 /** - * \brief TODO Document create_mark_array() - * + * \brief create_mark_array() + * \details create structure to save the different marks. * \return none */ - void create_mark_array() { marks = (struct mark *) calloc(NUM_MARKS, sizeof(struct mark) ); return; } + /** - * \brief TODO Document free_marks_array() - * + * \brief free_marks_array() * \return none */ - void free_marks_array() { free(marks); + marks = NULL; return; } + /** - * \brief TODO Document get_mark() - * - * \details 'a' = 97 - * \param[in] c - * - * \return none + * \brief get_mark() + * \details get a mark based on the corresponding char. + * \param[in] char c + * \return struct mark * */ - struct mark * get_mark(char c) { return (marks + c); } + /** - * \brief TODO Document set_range_mark() - * - * \param[in] c - * \param[in] s - * + * \brief save a range over a mark + * \param[in] char c + * \param[in] struct sheet * sh + * \param[in] struct srange * s * \return none */ - -void set_range_mark(char c, struct srange * s) { +void set_range_mark(char c, struct sheet * sh, struct srange * s) { // Delete marked ranges when recording a new one with same char del_ranges_by_mark(c); + (marks + c)->sheet = sh; (marks + c)->rng = s; (marks + c)->row = -1; (marks + c)->col = -1; return; } + /** - * \brief TODO Document set_cell_mark() - * + * \brief set_cell_mark() + * \param[in] char c + * \param[in] struct sheet * sh + * \param[in] int row + * \param[in] int col * \return none */ - -void set_cell_mark(char c, int row, int col) { +void set_cell_mark(char c, struct sheet * sh, int row, int col) { // Delete marked ranges when recording a new one with same char del_ranges_by_mark(c); + (marks + c)->sheet = sh; (marks + c)->rng = NULL; (marks + c)->row = row; (marks + c)->col = col; return; } + /** - * \brief TODO Document fix_marks() - * + * \brief fix_marks() + * \details modify marks after some operations that modify the internal row or command. + * such as delete a row or column. + * \param[in] sheet * \param[in] deltar * \param[in] deltac * \param[in] row_desde * \param[in] row_hasta * \param[in] coldesde * \param[in] col_hasta - * * \return none */ - -void fix_marks(int deltar, int deltac, int row_desde, int row_hasta, int col_desde, int col_hasta) { +void fix_marks(struct sheet * sh, int deltar, int deltac, int row_desde, int row_hasta, int col_desde, int col_hasta) { int i; for (i = 0; i < NUM_MARKS-1; i++) { struct mark * m = marks + i; if (m->row >= row_desde && m->row <= row_hasta && - m->col >= col_desde && m->col <= col_hasta ) { + m->col >= col_desde && m->col <= col_hasta && + m->sheet == sh) { m->row += deltar; m->col += deltac; if (m->row < 0) m->row = 0; @@ -149,3 +153,22 @@ return; } +/** + * \brief clean_marks_by_sheet() + * \details clean the marks links to a sheet + * \param[in] struct sheet * sh + * \return none + */ +void clean_marks_by_sheet(struct sheet * sh) { + int i; + if (marks == NULL) return; + for (i = 0; i < NUM_MARKS-1; i++) { + struct mark * m = marks + i; + if (m->sheet == sh) { + m->sheet = NULL; + m->row = 0; + m->col = 0; + } + } + return; +} diff -Nru sc-im-0.8.2+ds/src/marks.h sc-im-0.8.3+ds/src/marks.h --- sc-im-0.8.2+ds/src/marks.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/marks.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -50,6 +50,7 @@ * a mark of a range of cells rather than a mark of just one cell */ struct mark { + struct sheet * sheet; int row; int col; srange * rng; @@ -58,7 +59,8 @@ void create_mark_array(); void free_marks_array(); -void set_cell_mark(char c, int row, int col); -void set_range_mark(char c, struct srange * s); -void fix_marks(int deltar, int deltac, int row_desde, int row_hasta, int col_desde, int col_hasta); +void set_cell_mark(char c, struct sheet * sh, int row, int col); +void set_range_mark(char c, struct sheet * sh, struct srange * s); +void fix_marks(struct sheet * sh, int deltar, int deltac, int row_desde, int row_hasta, int col_desde, int col_hasta); mark * get_mark(char c); +void clean_marks_by_sheet(struct sheet * sh); diff -Nru sc-im-0.8.2+ds/src/ods.c sc-im-0.8.3+ds/src/ods.c --- sc-im-0.8.2+ds/src/ods.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/ods.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file xlsx.c - * \author Andrés Martinelli - * \date 2021-03-27 - * \brief file that contains the functions to support ods file import - * - * \details ods import requires: - * - libzip-dev - * - libxml2-dev - */ - -#ifdef ODS -#include -#include -#include "tui.h" -#include "cmds.h" -#include "sc.h" -#include "utils/string.h" -#include -#endif - -/** - * \brief open_ods() files - * - * \param[in] fname - * \param[in] encoding - * - * \return none - */ - -int open_ods(char * fname, char * encoding) { -#ifdef ODS - struct zip * za; - struct zip_file * zf; - struct zip_stat sb_content; - - char buf[100]; - int err; - int len; - - // open zip file - if ((za = zip_open(fname, 0, &err)) == NULL) { - zip_error_to_str(buf, sizeof(buf), err, errno); - sc_error("can't open zip archive `%s': %s", fname, buf); - return -1; - } - - // open content.xml - char * name = "content.xml"; - zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); - char * content = NULL; - if (zf) { - // some files may not have strings - zip_stat(za, name, ZIP_FL_UNCHANGED, &sb_content); - content = (char *) malloc(sb_content.size); - len = zip_fread(zf, content, sb_content.size); - if (len < 0) { - sc_error("cannot read file %s.\n", name); - free(content); - return -1; - } - zip_fclose(zf); - } - - // XML parse for the sheet file - xmlDoc * doc = NULL; - - // this initialize the library and check potential ABI mismatches - // between the version it was compiled for and the actual shared - // library used. - LIBXML_TEST_VERSION - - - doc = xmlReadMemory(content, sb_content.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); - - if (doc == NULL) { - sc_error("error: could not parse ods file"); - if (content != NULL) free(content); - return -1; - } - - // parse here - xmlNode * cur_node = xmlDocGetRootElement(doc)->xmlChildrenNode; - xmlNode * child_node = NULL; - wchar_t line_interp[FBUFLEN] = L""; - int r=0, c=-1; - while (cur_node != NULL && strcmp((char *) cur_node->name, "body")) cur_node = cur_node->next; // forward until reach body - cur_node = cur_node->xmlChildrenNode; - while (cur_node != NULL && strcmp((char *) cur_node->name, "spreadsheet")) cur_node = cur_node->next; // forward until reach spreadsheet - cur_node = cur_node->xmlChildrenNode; - while (cur_node != NULL && strcmp((char *) cur_node->name, "table")) cur_node = cur_node->next; // forward until reach table - cur_node = cur_node->xmlChildrenNode; - - char * strvalue = NULL; - char * st = NULL; - char * strtype = NULL; - char * value = NULL; - char * strf; - char * value_type = NULL; - - // here traverse table content - while (cur_node != NULL) { - if (! strcmp((char *) cur_node->name, "table-row")) { - // we are inside a table-row - // each of these is a row - child_node = cur_node->xmlChildrenNode; - r++; - c=-1; - - while (child_node != NULL) { - c++; - if ((value_type = (char *) xmlGetProp(child_node, (xmlChar *) "value-type")) == NULL) { child_node = child_node->next; continue; }; - // each of these is table-cell (a column) - - strtype = value_type; // type - - //if (!strcmp(strtype, "time") //get time-value - //TODO - //if (!strcmp(strtype, "date") //get date-value - //TODO - if (!strcmp(strtype, "float")) { - char * formula = (char *) xmlGetProp(child_node, (xmlChar *) "formula"); - if (formula != NULL) { - strf = str_replace (formula, "of:=",""); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "[.",""); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, ";",","); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, ":.",":"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "]",""); - strcpy(formula, strf); - free(strf); - // we take some common function and adds a @ to them - strf = str_replace (formula, "COUNT","@COUNT"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "SUM","@SUM"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "PRODUCT","@PROD"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "AVERAGE","@AVG"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "MIN","@MIN"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "MAX","@MAX"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "ABS","@ABS"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "STDEV","@STDDEV"); - strcpy(formula, strf); - free(strf); - swprintf(line_interp, FBUFLEN, L"let %s%d=%s", coltoa(c), r, formula); - xmlFree(formula); - formula = NULL; - } else { - value = (char *) xmlGetProp(child_node, (xmlChar *) "value"); // type - double l = atof((char *) value); - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, l); - xmlFree(value); - value = NULL; - } - send_to_interp(line_interp); - } else if (!strcmp(strtype, "string") && !strcmp((char *) child_node->xmlChildrenNode->name, "p")) { - strvalue = (char *) xmlNodeGetContent(child_node->xmlChildrenNode); - st = str_replace (strvalue, "\"", "''"); - clean_carrier(st); // we handle padding - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, st); - send_to_interp(line_interp); - free(st); - xmlFree(strvalue); - strvalue = NULL; - } - child_node = child_node->next; - - xmlFree(value_type); - value_type = NULL; - } - } - cur_node = cur_node->next; // forward until reach table - } - int_deleterow(currow, 1); /* delete the first row */ - - // free the document - xmlFreeDoc(doc); - - // Free the global variables that may have been allocated by the parser - xmlCleanupParser(); - - free(content); - - // close zip file - if (zip_close(za) == -1) { - sc_error("cannot close zip archive `%s'", fname); - return -1; - } -#endif - return 0; -} diff -Nru sc-im-0.8.2+ds/src/ods.h sc-im-0.8.3+ds/src/ods.h --- sc-im-0.8.2+ds/src/ods.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/ods.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file ods.h - * \author Andrés Martinelli - * \date 2021-03-27 - * \brief Header file for ods.c - */ - -int open_ods(char * fname, char * encoding); diff -Nru sc-im-0.8.2+ds/src/pipe.c sc-im-0.8.3+ds/src/pipe.c --- sc-im-0.8.2+ds/src/pipe.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/pipe.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -54,26 +54,28 @@ #include "macros.h" #include "tui.h" -// FIXME - pass fd is not neccesary? +extern struct session * session; + /** - * \brief TODO Document getnum() - * + * \brief getnum() * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn * \param[in[ df + * \param[in[ FILE * fd * * \return none +// FIXME - pass fd is not needed */ -void getnum(int r0, int c0, int rn, int cn, FILE * fd) { +void getnum(struct sheet * sh, int r0, int c0, int rn, int cn, FILE * fd) { struct ent ** pp; struct ent * p; int r, c; for (r = r0; r <= rn; r++) { - for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { + for (c = c0, pp = ATBL(sh, sh->tbl, r, c); c <= cn; pp++, c++) { *line = '\0'; p = *pp; if (p) { @@ -95,39 +97,40 @@ } /** - * \brief TODO Document getformat() - * + * \brief getformat() * \param[in] col * \param[in] df - * * \return none */ - +// FIXME - pass fd is not needed void getformat(int col, FILE * fd) { - sprintf(line, "%d %d %d\n", fwidth[col], precision[col], realfmt[col]); + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + sprintf(line, "%d %d %d\n", sh->fwidth[col], sh->precision[col], sh->realfmt[col]); //write(fd, line, strlen(line)); sc_value("%s", line); linelim = -1; } + /** - * \brief TODO Document getfmt() - * + * \brief getfmt() * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn * \param[in] fd - * * \return none */ - +// FIXME - pass fd is not needed void getfmt(int r0, int c0, int rn, int cn, FILE * fd) { - struct ent **pp; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + struct ent ** pp; int r, c; for (r = r0; r <= rn; r++) { - for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { + for (c = c0, pp = ATBL(sh, sh->tbl, r, c); c <= cn; pp++, c++) { *line = '\0'; if (*pp && (*pp)->format) sprintf(line, "%s", (*pp)->format); sc_value("%s", line); @@ -141,23 +144,23 @@ } /** - * \brief TODO Document getstring() - * + * \brief getstring() * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn * \param[in] fd - * * \return none */ - +// FIXME - pass fd is not needed void getstring(int r0, int c0, int rn, int cn, FILE * fd) { - struct ent **pp; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + struct ent ** pp; int r, c; for (r = r0; r <= rn; r++) { - for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { + for (c = c0, pp = ATBL(sh, sh->tbl, r, c); c <= cn; pp++, c++) { *line = '\0'; if (*pp && (*pp)->label) sprintf(line, "%s", (*pp)->label); @@ -171,25 +174,26 @@ linelim = -1; } + /** - * \brief TODO Document getexp() - * + * \brief getexp() * \param[in] r0 * \param[in] c0 * \param[in] rn * \param[in] cn * \param[in] fd - * * \return none */ - +// FIXME - pass fd is not needed void getexp(int r0, int c0, int rn, int cn, FILE * fd) { - struct ent **pp; - struct ent *p; - int r, c; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + struct ent ** pp; + struct ent * p; + int r, c; for (r = r0; r <= rn; r++) { - for (c = c0, pp = ATBL(tbl, r, c); c <= cn; pp++, c++) { + for (c = c0, pp = ATBL(sh, sh->tbl, r, c); c <= cn; pp++, c++) { *line = '\0'; p = *pp; if (p && p->expr) { diff -Nru sc-im-0.8.2+ds/src/pipe.h sc-im-0.8.3+ds/src/pipe.h --- sc-im-0.8.2+ds/src/pipe.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/pipe.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -42,7 +42,7 @@ * \brief Header file for pipe.c */ -void getnum(int r0, int c0, int rn, int cn, FILE * fd); +void getnum(struct sheet * sh, int r0, int c0, int rn, int cn, FILE * fd); void getformat(int col, FILE * fd); void getfmt(int r0, int c0, int rn, int cn, FILE * fd); void getstring(int r0, int c0, int rn, int cn, FILE * fd); diff -Nru sc-im-0.8.2+ds/src/plot.c sc-im-0.8.3+ds/src/plot.c --- sc-im-0.8.2+ds/src/plot.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/plot.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file plot.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include -#include -#include - -#include "plot.h" -#include "file.h" -#include "tui.h" - -/** - * \brief TODO Document plotedit() - * - * \param[in] s - * - * \return none - */ - -int plotedit(wchar_t * s) { -#ifdef GNUPLOT - // edit ~/.scim/plotxxxx (or /usr/local/share/scim/plotxxxx) - char command[BUFFERSIZE]; - - if (! wcscmp(s, L"line") || ! wcscmp(s, L"scatter") || - ! wcscmp(s, L"pie") || ! wcscmp(s, L"bar")) { - char buffer[PATHLEN + 5]; - char path_out[PATHLEN]; - char type[BUFFERSIZE]; - wcstombs(type, s, BUFFERSIZE); - sprintf(buffer, "plot_%s", type); - if (! plugin_exists(buffer, strlen(buffer), path_out)) { - sc_error("could not load plot template file"); - return -1; - } - ui_pause(); - - char * editor; - if (! (editor = getenv("EDITOR"))) - editor = DFLT_EDITOR; - sprintf(command, "%.*s %.*s", 100, editor, 100, path_out); - - if (system(command) == -1) sc_error("Failed editting plot file - errno:%d", errno); - ui_resume(); - } else { - sc_error("error: invalid plot file: %ls", s); - return -1; - } - return 0; -#else - sc_error("Gnuplot was not installed when building Sc-im. Please rebuild Sc-im."); - return -1; -#endif -} - -/** - * \brief TODO Document plot() - * - * \param[in] s - * \param[in] r - * \param[in] c - * \param[in] rf - * \param[in] cf - * - * \return none - */ - -int plot(char * s, int r, int c, int rf, int cf) { -#ifdef GNUPLOT - // create tmp file - char datafile[] = "/tmp/sc-im-plotdataXXXXXX"; - int fd = mkstemp(datafile); - if (fd == -1) { - sc_error("Error while creating temp file for plot"); - return -1; - } - - // export range to temp file in csv format - export_delim(datafile, ',', r, c, rf, cf, 0); - - // call gnuplot with ~/.scim/plotline (or /usr/local/share/scim/plotline) and temp data file - char command[BUFFERSIZE]; - char buffer[PATHLEN]; - char buffer1[PATHLEN]; - sprintf(command, "gnuplot -e \"filename='%s'\"", datafile); - - if (! strcmp(s, "line") || ! strcmp(s, "scatter") || - ! strcmp(s, "pie") || ! strcmp(s, "bar")) { - sprintf(buffer, "plot_%s", s); - if (! plugin_exists(buffer, strlen(buffer), buffer1)) { - sc_error("could not load default plotline file"); - return -1; - } - sprintf(command + strlen(command), " %s", buffer1); - - } else { - sc_error("plot option not valid"); - return -1; - } - - ui_pause(); - - if (system(command) == -1) - sc_error("Failed during plot - errno:%d", errno); - getchar(); - ui_resume(); - - // close file descriptor - close(fd); - - // remove temp file - unlink(datafile); - - return 0; -#else - sc_error("Gnuplot was not installed when building Sc-im. Please rebuild Sc-im."); - return -1; -#endif -} diff -Nru sc-im-0.8.2+ds/src/plot.h sc-im-0.8.3+ds/src/plot.h --- sc-im-0.8.2+ds/src/plot.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/plot.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file plot.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for plot.c - */ - -int plot(char * s, int r, int c, int rf, int cf); -int plotedit(wchar_t * s); diff -Nru sc-im-0.8.2+ds/src/range.c sc-im-0.8.3+ds/src/range.c --- sc-im-0.8.2+ds/src/range.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/range.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -51,15 +51,13 @@ #include "sc.h" #include "marks.h" #include "macros.h" +#include "color.h" #include "conf.h" #include "xmalloc.h" // for scxfree srange * ranges = NULL; -extern int currow; -extern int curcol; -extern unsigned char * col_hidden; -extern unsigned char * row_hidden; +extern struct session * session; /** * \brief Create a range from either to marks or two cells. @@ -73,6 +71,8 @@ */ srange * create_range(char c, char d, struct ent * tl, struct ent * br) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; int tlrow, tlcol, brrow, brcol; if (c == '\0' && d == '\0') { @@ -91,12 +91,12 @@ brcol = md->col > mc->col ? md->col : mc->col; } - if ( row_hidden[tlrow] || row_hidden[brrow] ) { + if (sh->row_hidden[tlrow] || sh->row_hidden[brrow] ) { sc_error("Row of cell is hidden"); return NULL; } - if ( col_hidden[tlcol] || col_hidden[brcol] ) { + if (sh->col_hidden[tlcol] || sh->col_hidden[brcol] ) { sc_error("Column of cell is hidden"); return NULL; } @@ -113,14 +113,14 @@ r->brcol = brcol; //r->orig_col = -1; //r->orig_row = -1; - r->orig_row = currow; - r->orig_col = curcol; + r->orig_row = sh->currow; + r->orig_col = sh->curcol; r->marks[0] = c; r->marks[1] = d; r->pnext = NULL; r->selected = 1; - currow = r->tlrow; - curcol = r->tlcol; + sh->currow = r->tlrow; + sh->curcol = r->tlcol; // Only add to list if a range was created if (exists_range == NULL && ranges == NULL) { @@ -331,6 +331,8 @@ */ void add_range(char * name, struct ent_ptr left, struct ent_ptr right, int is_range) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; register char * p; int minr, minc, maxr, maxc; int minrf, mincf, maxrf, maxcf; @@ -352,9 +354,9 @@ maxc = left.vp->col; maxcf = left.vf & FIX_COL; } - left.vp = lookat(minr, minc); + left.vp = lookat(sh, minr, minc); left.vf = minrf | mincf; - right.vp = lookat(maxr, maxc); + right.vp = lookat(sh, maxr, maxc); right.vf = maxrf | maxcf; if ( ! find_range(name, strlen(name), (struct ent *) 0, (struct ent *) 0, &prev)) { @@ -407,7 +409,7 @@ rng_base->r_prev = rng; rng_base = rng; } - modflg++; + roman->modflg++; } /** @@ -420,6 +422,8 @@ */ void del_range(struct ent * left, struct ent * right) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; struct range * r; int minr, minc, maxr, maxc; @@ -428,8 +432,8 @@ maxr = left->row > right->row ? left->row : right->row; maxc = left->col > right->col ? left->col : right->col; - left = lookat(minr, minc); - right = lookat(maxr, maxc); + left = lookat(sh, minr, minc); + right = lookat(sh, maxr, maxc); if ( find_range((char *) 0, 0, left, right, &r)) return; @@ -442,7 +446,7 @@ rng_base = r->r_next; scxfree((char *) (r->r_name)); scxfree((char *) r); - modflg++; + roman->modflg++; } /** diff -Nru sc-im-0.8.2+ds/src/range.h sc-im-0.8.3+ds/src/range.h --- sc-im-0.8.2+ds/src/range.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/range.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/sc.h sc-im-0.8.3+ds/src/sc.h --- sc-im-0.8.2+ds/src/sc.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/sc.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -38,7 +38,7 @@ /** * \file sc.h * \author Andrés Martinelli - * \date 2017-07-18 + * \date 23/05/2021 * \brief Header file for sc.c */ @@ -48,9 +48,6 @@ #include #include -//#define ATBL(tbl, row, col) (*(tbl + row) + (col)) -extern struct ent ** ATBL(struct ent ***, int, int ); - #define MINROWS 100 /* minimum size at startup */ /* MAX rows size of sheet. Default 65536. */ @@ -81,7 +78,7 @@ #define PATHLEN 1024 /* maximum path length */ #define MAXCMD 160 /* for ! command and commands that use the pager */ -#define STDERRBUF 8192 /* stderr buffer size */ +#define STDERRBUF 1024 /* stderr buffer size */ #ifndef DFLT_PAGER #define DFLT_PAGER "more" /* more is probably more widespread than less */ @@ -96,10 +93,74 @@ //#endif #ifndef FALSE - # define FALSE 0 - # define TRUE 1 + #define FALSE 0 + #define TRUE 1 #endif +/* structure to hold multiple documents */ +struct session { + struct roman * first_doc; + struct roman * last_doc; + struct roman * cur_doc; +}; + +/* structure to hold an opened document with its sheets */ +struct roman { + char * name; + struct sheet * first_sh; + struct sheet * last_sh; + struct sheet * cur_sh; + short flags; + struct roman * next; /* to link to other roman structs */ + struct roman * prev; /* to link to other roman structs */ + int modflg; /* Indicates a change was made since last save */ + int loading; /* kept for backwards compatibility. + * TODO replace it and use it with flags. use a macro + * to check in every roman struct of session + */ +}; + +/* flag values for roman struct */ +#define is_loading 0001 +#define is_opened 0002 +#define is_closed 0004 +#define is_empty 0010 +#define is_allocated 0020 + +/* structure to store sheet data */ +struct sheet { + struct ent *** tbl; /* matrix to hold sheet cells */ + char * name; + int id; /* an id of sheet must be kept so that we can insert vertex's ordered + (and look them up) in the dependency graph. */ + int currow; /* current row of the selected cell. */ + int curcol; /* current column of the selected cell. */ + int lastrow; /* row of last selected cell */ + int lastcol; /* col of last selected cell */ + int maxrows; /* max alloc'ed row */ + int maxcols; /* max alloc'ed col */ + int maxrow, maxcol; /* max row and col with data stored */ + int * fwidth; /* columns width */ + int * precision; /* columns decimal precision */ + short flags; /* to keep some flags */ + int * realfmt; + unsigned char * col_hidden; + unsigned char * col_frozen; + unsigned char * row_hidden; + unsigned char * row_frozen; + unsigned char * row_format; /* rows height */ + struct sheet * next; /* to link to other sheets */ + struct sheet * prev; /* to link to other sheets */ + int rescol; /* Columns reserved for row numbers */ + int offscr_sc_rows, offscr_sc_cols; /* off screen spreadsheet rows and columns */ + int nb_frozen_rows, nb_frozen_cols; /* total number of frozen rows/cols */ + int nb_frozen_screenrows; /* screen rows occupied by those frozen rows */ + int nb_frozen_screencols; /* screen cols occupied by those frozen columns */ +}; + +//#define ATBL(tbl, row, col) (*(tbl + row) + (col)) +extern struct ent ** ATBL(struct sheet * sh, struct ent ***, int, int ); + /* * Some not too obvious things about the flags: * is_valid means there is a valid number in v. @@ -111,13 +172,9 @@ * So, either v or label can be set to a constant. * Either (but not both at the same time) can be set from an expression. */ +#define VALID_CELL(s, p, r, c) ((p = *ATBL(s, s->tbl, r, c)) && ((p->flags & is_valid) || p->label)) -#define VALID_CELL(p, r, c) ((p = *ATBL(tbl, r, c)) && ((p->flags & is_valid) || p->label)) - -// TODO Properly document these structs using doxygen tags. Possibly -// not the same as functions. What is the standard way? - -/* info for each cell, only alloc'd when something is stored in a cell */ +/* structure to store cell contents */ struct ent { double v; /* v && label are set in EvalAll() */ char * label; @@ -134,6 +191,7 @@ #define FIX_ROW 1 #define FIX_COL 2 +#define GET_ENT 4 /* * ent_ptr holds the row/col # and address type of a cell @@ -147,6 +205,14 @@ int vf; struct ent * vp; struct enode * expr; /* for getent */ + struct sheet * sheet; + struct ent_ptr * next; /* for use in added/removed lists in undo and yanklist */ +}; + +// used for yank list +struct allocation_list { + struct ent_ptr ** items; + int size; }; // stores a range (left, right) @@ -181,20 +247,22 @@ } e; }; -struct impexfilt { +/* struct impexfilt { char ext[PATHLEN]; char plugin[PATHLEN]; char type; struct impexfilt * next; -}; +}; */ /* Use this structure to save the last 'g' command */ struct go_save { + struct sheet * g_sheet; int g_type; double g_n; char * g_s; int g_row; int g_col; + int g_flow; int g_lastrow; int g_lastcol; int strow; @@ -203,6 +271,42 @@ int errsearch; }; +#define INSERT(NEW, FIRST,LAST,NEXT,PREV) \ + do { \ + if(FIRST == 0) FIRST=LAST=NEW; \ + else { \ + NEW->PREV=LAST; \ + NEW->NEXT=LAST->NEXT; \ + LAST->NEXT=NEW; \ + if(NEW->NEXT !=NULL) NEW->NEXT->PREV=NEW; \ + LAST=NEW; \ + }\ + } while(0) + + + #define INSERT_BEFORE(NEW, FIRST,LAST,NEXT,PREV) \ + do { \ + if(FIRST == 0) FIRST=LAST=NEW; \ + else { \ + NEW->NEXT=FIRST; \ + NEW->PREV=FIRST->PREV;\ + FIRST->PREV=NEW; \ + FIRST=NEW; \ + }\ + } while(0) + + #define REMOVE(ELEM,FIRST,LAST,NEXT,PREV) \ + do { \ + if(ELEM==FIRST) { \ + FIRST=ELEM->NEXT; \ + if (FIRST == 0) LAST=0; \ + else ELEM->NEXT->PREV=0; \ + } else { \ + ELEM->PREV->NEXT=ELEM->NEXT; \ + if (ELEM->NEXT ==0) LAST=ELEM->PREV; \ + else ELEM->NEXT->PREV=ELEM->PREV; } \ + } while(0) + /* op values */ #define O_VAR 'v' #define O_CONST 'k' @@ -303,20 +407,24 @@ #define is_label 0100 #define iscleared 0200 #define may_sync 0400 + /* cell error (1st generation (ERROR) or 2nd+ (INVALID)) */ #define CELLOK 0 #define CELLERROR 1 #define CELLINVALID 2 #define CELLREF 3 + /* calculation order */ #define BYCOLS 1 #define BYROWS 2 + /* tblprint style output for: */ #define TBL 1 /* 'tbl' */ #define LATEX 2 /* 'LaTeX' */ #define TEX 3 /* 'TeX' */ #define SLATEX 4 /* 'SLaTeX' (Scandinavian LaTeX) */ #define FRAME 5 /* tblprint style output for FrameMaker */ + /* Types for etype() */ #define NUM 1 #define STR 2 @@ -326,26 +434,11 @@ #define GROWCOL 3 /* add columns */ #define GROWBOTH 4 /* grow both */ -extern int currow, curcol; -extern int maxrow, maxcol; -extern struct ent *** tbl; // data table ref. in vmtbl.c and ATBL() -extern char curfile[]; extern int arg; -extern int lastrow, lastcol; extern int gmyrow, gmycol; // globals used for @myrow, @mycol cmds -extern int rescol; // columns reserved for row numbers -extern int maxrows, maxcols; // # cells currently allocated extern int rowsinrange; // Number of rows in target range of a goto extern int colsinrange; // Number of cols in target range of a goto -extern int * fwidth; -extern int * precision; -extern int * realfmt; extern char * colformat[10]; -extern unsigned char * col_hidden; -extern unsigned char * row_hidden; -extern unsigned char * row_format; -extern unsigned char * row_frozen; -extern unsigned char * col_frozen; extern char line[FBUFLEN]; extern int linelim; extern int changed; @@ -376,7 +469,7 @@ extern int tbl_style; extern int loading; -extern struct enode * copye(struct enode *e, int Rdelta, int Cdelta, int r1, int c1, int r2, int c2, int transpose); +extern struct enode * copye(struct enode *e, struct sheet * sh, int Rdelta, int Cdelta, int r1, int c1, int r2, int c2, int special); extern char dpoint; // country-dependent decimal point from locale extern char thsep; // country-dependent thousands separator from locale extern char * coltoa(int col); @@ -385,22 +478,21 @@ extern char * r_name(int r1, int c1, int r2, int c2); extern char * scxmalloc(unsigned n); extern char * scxrealloc(char * ptr, unsigned n); -extern char * seval(struct ent * ent, struct enode * se); +extern char * seval(struct sheet * sh, struct ent * ent, struct enode * se); extern char * v_name(int row, int col); -extern double eval(struct ent * ent, struct enode * e); +extern double eval(struct sheet * sh, struct ent * ent, struct enode * e); extern struct enode * new(int op, struct enode * a1, struct enode * a2); extern struct enode * new_const(int op, double a1); extern struct enode * new_range(int op, struct range_s a1); extern struct enode * new_str(char * s); extern struct enode * new_var(int op, struct ent_ptr a1); -extern struct ent * lookat(int row, int col); +extern struct ent * lookat(struct sheet * sh, int row, int col); // return pointer to 'ent' of cell. Create it if it doesn't exist extern void EvalAll(); -extern void checkbounds(int * rowp, int * colp); +extern void checkbounds(struct sheet * sh, int * rowp, int * colp); extern void clearent(struct ent * v); extern void closefile(FILE * f, int pid, int rfd); extern void colshow_op(); extern struct colorpair *cpairs[8]; -extern void editexp(int row, int col); extern void efree(struct enode * e); extern void label(struct ent * v, char * s, int flushdir); diff -Nru sc-im-0.8.2+ds/src/sc-im.1 sc-im-0.8.3+ds/src/sc-im.1 --- sc-im-0.8.2+ds/src/sc-im.1 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/sc-im.1 2023-01-16 15:38:03.000000000 +0000 @@ -159,10 +159,10 @@ Enter a numeric constant or expression into the current cell. .TP .BR < -Enter a label string into the current cell. Right aligned +Enter a label string into the current cell. Left aligned .TP .BR > -Enter a label string into the current cell. Left aligned +Enter a label string into the current cell. Right aligned .TP .BR { Left justify the string in the current cell. diff -Nru sc-im-0.8.2+ds/src/sheet.c sc-im-0.8.3+ds/src/sheet.c --- sc-im-0.8.2+ds/src/sheet.c 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/sheet.c 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2013-2021, Andrés Martinelli * + * All rights reserved. * + * * + * This file is a part of sc-im * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * + * Chuck Martin. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. All advertising materials mentioning features or use of this software * + * must display the following acknowledgement: * + * This product includes software developed by Andrés Martinelli * + * . * + * 4. Neither the name of the Andrés Martinelli nor the * + * names of other contributors may be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *******************************************************************************/ + +/** + * \file sheet.c + * \author Andrés Martinelli + * some of this code is by Roman Pollak - @roman65536 + * \date 2021-05-20 + * \brief source file to handle sheets + * \see Homepage: https://github.com/andmarti1424/sc-im + */ + +#include +#include "sheet.h" +#include "file.h" +#include "yank.h" +#include "marks.h" +#include "graph.h" + +int id_sheet = 0; + +/** + * \brief new_sheet() + * \param[doc] roman struct + * \param[name] sheet name + * \return sutrct sheet * + */ +struct sheet * new_sheet(struct roman * doc, char * name) { + struct sheet * sh; + if ((sh = search_sheet(doc, name)) != 0 ) return sh; + + sh = (struct sheet *) calloc(1, sizeof(struct sheet)); + INSERT(sh, (doc->first_sh), (doc->last_sh), next, prev); + sh->name = strdup(name); + + sh->tbl = NULL; + + sh->currow = 0; /* current row of the selected cell. */ + sh->curcol = 0; /* current column of the selected cell. */ + sh->lastrow = 0; /* row of last selected cell */ + sh->lastcol = 0; /* col of last selected cell */ + + sh->offscr_sc_cols = 0; // off screen spreadsheet rows and columns + sh->offscr_sc_rows = 0; + sh->nb_frozen_rows = 0; + sh->nb_frozen_cols = 0; // total number of frozen rows/cols + sh->nb_frozen_screenrows = 0; // screen rows occupied by those frozen rows + sh->nb_frozen_screencols = 0; // screen cols occupied by those frozen columns + + sh->maxcol = 0; + sh->maxrow = 0; + sh->id = id_sheet++; /* an id of sheet must be kept so that we can insert vertex's ordered + (and look them up) in the dependency graph. */ + /* + sh->hash= (void *) calloc(HASH_NR,sizeof(void *)); + sh->nr_hash=HASH_NR; + sh->ccol = 16; + sh->crow = 32768; + objs_cache_init(&sh->cache_ent, sizeof(struct Ent), NULL); + */ + return sh; + } + +/** + * \brief search_sheet() + * \param[doc] roman struct + * \param[name] sheet name + * \return struct sheet * + */ +struct sheet * search_sheet(struct roman * doc, char * name) { + if (doc == NULL || name == NULL || ! strlen(name)) return NULL; + struct sheet * sh; + + for(sh = doc->first_sh; sh != 0; sh = sh->next) { + if (sh->name == NULL) continue; + if (! strcmp(name, sh->name)) return sh; + } + return NULL; +} + + +/** + * \brief get_num_sheets() + * \param[doc] roman struct + * \return [int] number of sheets + */ +int get_num_sheets(struct roman * doc) { + if (doc == NULL) return 0; + struct sheet * sh; + int cnt = 0; + for(sh = doc->first_sh; sh != NULL ; sh = sh->next) { + cnt++; + } + return cnt; +} + +/** + * \brief free_session(): free memory of a session calling delete_doc + * \param[doc] roman struct + * \return void + */ +void free_session(struct session * session) { + while (session != NULL) { + struct roman * r_aux, * r = session->first_doc; + // traverse romans + while (r != NULL) { + r_aux = r->next; + delete_doc(session, r); + r = r_aux; + } + // free session + free(session); + session = NULL; + } + return; +} + + +/** + * \brief delete_doc() + * \details delete content of a doc and free its memory calling delete_sheet() + * \param[doc] struct roman * + * \param[sh] struct sheet * + * \return void + */ +void delete_doc(struct session * session, struct roman * doc) { + // remove the link of doc to session + REMOVE(doc, (session->first_doc), (session->last_doc), next, prev); + + // traverse doc sheets + struct sheet * s_aux, * sh = doc->first_sh; + while (sh != NULL) { + s_aux = sh->next; + delete_sheet(doc, sh, 1); + sh = s_aux; + } + if (doc->name != NULL) { + free(doc->name); + doc->name = NULL; + } + free(doc); + return; +} + +/** + * \brief delete_sheet() + * \details delete content of a sheet and free its memory + * \param[doc] struct roman * + * \param[sh] struct sheet * + * \param[flg_free] int + * \return void + */ +void delete_sheet(struct roman * roman, struct sheet * sh, int flg_free) { + REMOVE(sh, (roman->first_sh), (roman->last_sh), next, prev); + + // mark '->sheet to NULL' in all ents on yanklist that refers to this sheet + struct ent_ptr * yl = get_yanklist(); + while (yl != NULL) { + if (yl->sheet == sh) yl->sheet = NULL; + yl = yl->next; + } + + // reset marks that links to the sheet we are deleting + clean_marks_by_sheet(sh); + + // free sheet + erasedb(sh, flg_free); // clear sh and free on if flg_free is true + + // if we are deleting a sheet not at exit + // we need to update references of ents of other sheets + // that could refer to this one by rebuilding the graph. + if (! flg_free) rebuild_graph(); + + for (int row = 0; sh->tbl != NULL && row < sh->maxrows; row++) { + if (sh->tbl[row] != NULL) { + free(sh->tbl[row]); + sh->tbl[row] = NULL; + } + } + + free(sh->tbl); + free(sh->fwidth); + free(sh->precision); + free(sh->realfmt); + free(sh->col_hidden); + free(sh->col_frozen); + free(sh->row_hidden); + free(sh->row_frozen); + free(sh->row_format); + + if (sh->name != NULL) { + free(sh->name); + sh->name = NULL; + } + free(sh); + sh = NULL; + return; +} + diff -Nru sc-im-0.8.2+ds/src/sheet.h sc-im-0.8.3+ds/src/sheet.h --- sc-im-0.8.2+ds/src/sheet.h 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/src/sheet.h 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,8 @@ +#include "sc.h" + +struct sheet * search_sheet(struct roman * doc, char * name); +struct sheet * new_sheet(struct roman * doc, char * name); +int get_num_sheets(struct roman * doc); +void free_session(struct session * session); +void delete_sheet(struct roman * roman, struct sheet * sh, int flg_free); +void delete_doc(struct session * session, struct roman * doc); diff -Nru sc-im-0.8.2+ds/src/shift.c sc-im-0.8.3+ds/src/shift.c --- sc-im-0.8.2+ds/src/shift.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/shift.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,333 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file shift.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include "shift.h" -#include "sc.h" -#include "vmtbl.h" // for growtbl -#include "cmds.h" -#include "dep_graph.h" -#include "undo.h" -#include "marks.h" -#include "yank.h" -#include "conf.h" -#include "tui.h" - -extern graphADT graph; -extern int cmd_multiplier; - -/** - * @brief Shift function - handles undo - * - * Shift functin - handles unto. Should also be called form gram.y. - * - * \param[in] r - * \param[in] c - * \param[in] rf - * \param[in] cf - * \param[in] type - * - * \return none - */ - -void shift(int r, int c, int rf, int cf, wchar_t type) { - if ( any_locked_cells(r, c, rf, cf) && (type == L'h' || type == L'k') ) { - sc_error("Locked cells encountered. Nothing changed"); - return; - } -#ifdef UNDO - create_undo_action(); -#endif - int ic = cmd_multiplier + 1; - - switch (type) { - - case L'j': - fix_marks( (rf - r + 1) * cmd_multiplier, 0, r, maxrow, c, cf); -#ifdef UNDO - save_undo_range_shift(cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf); -#endif - while (ic--) shift_range(ic, 0, r, c, rf, cf); - break; - - case L'k': - fix_marks( -(rf - r + 1) * cmd_multiplier, 0, r, maxrow, c, cf); - yank_area(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, 'a', cmd_multiplier); // keep ents in yanklist for sk -#ifdef UNDO - ents_that_depends_on_range(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf); - copy_to_undostruct(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, UNDO_DEL, HANDLE_DEPS, NULL); - save_undo_range_shift(-cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf); -#endif - while (ic--) shift_range(-ic, 0, r, c, rf, cf); - if (get_conf_int("autocalc") && ! loading) EvalAll(); -#ifdef UNDO - copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); -#endif - break; - - case L'h': - fix_marks(0, -(cf - c + 1) * cmd_multiplier, r, rf, c, maxcol); - yank_area(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), 'a', cmd_multiplier); // keep ents in yanklist for sk -#ifdef UNDO - // here we save in undostruct, all the ents that depends on the deleted one (before change) - ents_that_depends_on_range(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1)); - copy_to_undostruct(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), UNDO_DEL, HANDLE_DEPS, NULL); - save_undo_range_shift(0, -cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1)); -#endif - while (ic--) shift_range(0, -ic, r, c, rf, cf); - - if (get_conf_int("autocalc") && ! loading) EvalAll(); - //update(TRUE); // this is used just to make debugging easier -#ifdef UNDO - copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL); -#endif - break; - - case L'l': - fix_marks(0, (cf - c + 1) * cmd_multiplier, r, rf, c, maxcol); -#ifdef UNDO - save_undo_range_shift(0, cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1)); -#endif - while (ic--) shift_range(0, ic, r, c, rf, cf); - break; - } -#ifdef UNDO - end_undo_action(); - extern struct ent_ptr * deps; - if (deps != NULL) free(deps); - deps = NULL; -#endif - /* just for testing - sync_refs(); - rebuild_graph(); - sync_refs(); - rebuild_graph(); */ - cmd_multiplier = 0; - return; -} - -/** - * \brief Shift a range to 'ENTS' - * - * \param[in] delta_rows - * \param[in] delta_cols - * \param[in] tlrow - * \param[in] tlcol - * \param[in] brrow - * \param[in] brcol - * - * \return none - */ - -void shift_range(int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol) { - currow = tlrow; - curcol = tlcol; - - if (delta_rows > 0) shift_cells_down (brrow - tlrow + 1, brcol - tlcol + 1); - else if (delta_rows < 0) shift_cells_up (brrow - tlrow + 1, brcol - tlcol + 1); - - if (delta_cols > 0) shift_cells_right(brrow - tlrow + 1, brcol - tlcol + 1); - else if (delta_cols < 0) shift_cells_left (brrow - tlrow + 1, brcol - tlcol + 1); - - return; -} - -/** - * \brief Shift cells down - * - * \param[in] deltarows - * \param[in] deltacols - * - * \return none - */ - -void shift_cells_down(int deltarows, int deltacols) { - int r, c; - struct ent ** pp; - if (currow > maxrow) maxrow = currow; - maxrow += deltarows; - if ((maxrow >= maxrows) && !growtbl(GROWROW, maxrow, 0)) - return; - - for (r = maxrow; r > currow + deltarows - 1; r--) { - for (c = curcol; c < curcol + deltacols; c++) { - pp = ATBL(tbl, r, c); - pp[0] = *ATBL(tbl, r-deltarows, c); - if ( pp[0] ) pp[0]->row += deltarows; - } - } - // blank new ents - for (c = curcol; c < curcol + deltacols; c++) - for (r = currow; r < currow + deltarows; r++) { - pp = ATBL(tbl, r, c); - *pp = (struct ent *) 0; - } - return; -} - -/** - * \brief Shift cells right - * - * \param[in] deltaros - * \param[in] deltacols - * - * \return none - */ - -void shift_cells_right(int deltarows, int deltacols) { - int r, c; - struct ent ** pp; - - if (curcol + deltacols > maxcol) - maxcol = curcol + deltacols; - maxcol += deltacols; - - if ((maxcol >= maxcols) && !growtbl(GROWCOL, 0, maxcol)) - return; - - int lim = maxcol - curcol - deltacols; - for (r=currow; r < currow + deltarows; r++) { - pp = ATBL(tbl, r, maxcol); - for (c = lim; c-- >= 0; pp--) - if ((pp[0] = pp[-deltacols])) pp[0]->col += deltacols; - - pp = ATBL(tbl, r, curcol); - for (c = curcol; c < curcol + deltacols; c++, pp++) - *pp = (struct ent *) 0; - } - return; -} - -/** - * \brief Shift cells up - * - * \param[in] deltarows - * \param[in] deltacols - * - * \return none - */ - -void shift_cells_up(int deltarows, int deltacols) { - int r, c; - struct ent ** pp; - - for (r = currow; r <= maxrow; r++) { - for (c = curcol; c < curcol + deltacols; c++) { - - if (r < currow + deltarows) { - pp = ATBL(tbl, r, c); - - /* delete vertex in graph - unless vertex is referenced by other. Shall comment this? See NOTE1 above */ - vertexT * v = getVertex(graph, *pp, 0); - if (v != NULL && v->back_edges == NULL ) destroy_vertex(*pp); - - if (*pp) { - mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted - //clearent(*pp); - //free(*pp); - *pp = NULL; - } - } - if (r <= maxrow - deltarows) { - pp = ATBL(tbl, r, c); - pp[0] = *ATBL(tbl, r + deltarows, c); - if ( pp[0] ) pp[0]->row -= deltarows; - } - //blank bottom ents - if (r > maxrow - deltarows) { - pp = ATBL(tbl, r, c); - *pp = (struct ent *) 0; - } - } - } - return; -} - -/** - * \brief Shift cells left - * - * \param[in] deltarows - * \param[in] deltacols - * - * \return none - */ - -void shift_cells_left(int deltarows, int deltacols) { - int r, c; - struct ent ** pp; - - for (c = curcol; c <= maxcol; c++) { - for (r = currow; r < currow + deltarows; r++) { - - if (c < curcol + deltacols) { - pp = ATBL(tbl, r, c); - - /* delete vertex in graph - unless vertex is referenced by other */ - vertexT * v = getVertex(graph, *pp, 0); - if (v != NULL && v->back_edges == NULL ) destroy_vertex(*pp); - - if (*pp) { - mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted - //clearent(*pp); - //free(*pp); - *pp = NULL; - } - } - if (c <= maxcol - deltacols) { - pp = ATBL(tbl, r, c); - pp[0] = *ATBL(tbl, r, c + deltacols); - if ( pp[0] ) pp[0]->col -= deltacols; - } - //blank bottom ents - if (c > maxcol - deltacols) { - pp = ATBL(tbl, r, c); - *pp = (struct ent *) 0; - } - } - } - return; -} diff -Nru sc-im-0.8.2+ds/src/shift.h sc-im-0.8.3+ds/src/shift.h --- sc-im-0.8.2+ds/src/shift.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/shift.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file shift.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for shift.c - */ - -void shift_cells(int type, int arg, int delta); -void shift_cells_up(int deltarows, int deltacols); -void shift_cells_down(int deltarows, int deltacols); -void shift_cells_left(int deltarows, int deltacols); -void shift_cells_right(int deltarows, int deltacols); -void shift_range(int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol); -void shift(int r, int c, int rf, int cf, wchar_t type); diff -Nru sc-im-0.8.2+ds/src/sort.c sc-im-0.8.3+ds/src/sort.c --- sc-im-0.8.2+ds/src/sort.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/sort.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,230 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file sort.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a brief file description. - */ - -/* Adaptation of Chuck Martin's code - */ - -#include -#include -#include -#include -#include -#include - -#include "macros.h" -#include "yank.h" -#include "cmds.h" -#include "conf.h" -#include "color.h" -#include "xmalloc.h" // for scxfree - -int compare(const void * row1, const void * row2); - -struct sortcrit { - int direction, type, column; -} * sort; - -int howmany; - -/** - * \brief TODO Write a brief function description> - * - * \param[in] left - * \param[in] right - * \param[in] criteria - * - * \return none - */ - -void sortrange(struct ent * left, struct ent * right, char * criteria) { - int minr, minc, maxr, maxc, r, c; - int * rows, col = 0; - int cp = 0; - - minr = left->row < right->row ? left->row : right->row; - minc = left->col < right->col ? left->col : right->col; - maxr = left->row > right->row ? left->row : right->row; - maxc = left->col > right->col ? left->col : right->col; - - sort = (struct sortcrit *) scxmalloc((2 * sizeof(struct sortcrit))); - - // Save 'ent' elements in the range to the 'rows' structure - rows = (int *) scxmalloc((maxr - minr + 1) * sizeof(int)); - for (r = minr, c = 0; r <= maxr; r++, c++) - rows[c] = r; - - if (! criteria) { - sort[0].direction = 1; - sort[0].type = 1; - sort[0].column = minc; - sort[1].direction = 1; - sort[1].type = 0; - sort[1].column = minc; - howmany = 2; - } else { - howmany = 0; - while (criteria[cp]) { - if (howmany > 1) - sort = (struct sortcrit *) scxrealloc((char *) sort, (howmany + 1) * (sizeof(struct sortcrit))); - - switch (criteria[cp++]) { - case '+': - sort[howmany].direction = 1; - break; - case '-': - sort[howmany].direction = -1; - break; - default: - sc_error("Invalid sort criteria"); - return; - } - switch (criteria[cp++]) { - case '#': - sort[howmany].type = 0; - break; - case '$': - sort[howmany].type = 1; - break; - default: - sc_error("Invalid sort criteria"); - return; - } - if (criteria[cp]) { - col = toupper(criteria[cp++]) - 'A'; - } else { - sc_error("Invalid sort criteria"); - return; - } - if (criteria[cp] && criteria[cp] != '+' && criteria[cp] != '-' && criteria[cp] != ';') - col = (col + 1) * 26 + toupper(criteria[cp++]) - 'A'; - sort[howmany].column = col; - if (col < minc || col > maxc) { - sc_error("Invalid sort criteria"); - return; - } - cp++; - howmany++; - if (cp > strlen(criteria)) - break; - } - } - - // Sort 'rows' structure - qsort(rows, maxr - minr + 1, sizeof(int), compare); - - //currow = minr; - //curcol = minc; - - yank_area(minr, minc, maxr, maxc, 's', 1); // save yanklist in the original range - - - // Fix the 'ent' elements in the sorted range - struct ent * p_aux, * yl = get_yanklist(); - - for (c = 0, p_aux = yl; p_aux; p_aux = p_aux->next) { - if (rows[c] != p_aux->row) { - for (c = 0; c <= maxr - minr && rows[c] != p_aux->row; c++) ; - if (c > maxr - minr) { - sc_error("sort error"); - return; - } - } - p_aux->row = minr + c; - } - - currow = minr; - curcol = minc; - - paste_yanked_ents(0, 's'); // paste ents over currow and curcol - - scxfree((char *) sort); - scxfree((char *) rows); - - if (criteria) scxfree(criteria); -} - -/** - * \brief TODO Write a brief function description> - * - * \param[in] row1 - * \param[in] row2 - * - * \return result - */ - -int compare(const void * row1, const void * row2) { - struct ent * p1; - struct ent * p2; - double diff; - int result = 0; - int i; - - for (i = 0; !result && i < howmany; i++) { - p1 = *ATBL(tbl, *((int *) row1), sort[i].column); - p2 = *ATBL(tbl, *((int *) row2), sort[i].column); - - if (sort[i].type) { - if (p1 && p1->label) { - if (p2 && p2->label) { - result = strcmp(p1->label, p2->label); - } else { - result = -1; - } - } else if (p2 && p2->label) { - result = 1; - } - } else if (p1 && p2 && p1->flags & is_valid && p2->flags & is_valid) { - diff = (p1->v - p2->v); - result = (diff > 0 ? 1 : diff < 0 ? -1 : 0); - } else if (p1 && p1->flags & is_valid) { - result = -1; - } else if (p2 && p2->flags & is_valid) { - result = 1; - } - result *= sort[i].direction; - } - - if (! result) result = (*((int *) row1) - *((int *) row2)); - - return (result); -} diff -Nru sc-im-0.8.2+ds/src/sort.h sc-im-0.8.3+ds/src/sort.h --- sc-im-0.8.2+ds/src/sort.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/sort.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file sort.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for sort.c - */ - -void sortrange(struct ent * left, struct ent * right, char * criteria); diff -Nru sc-im-0.8.2+ds/src/subtotal.c sc-im-0.8.3+ds/src/subtotal.c --- sc-im-0.8.2+ds/src/subtotal.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/subtotal.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file subtotal.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include "sc.h" -#include "macros.h" -#include "cmds.h" -#include "shift.h" -#include "tui.h" - -/* -#include -#include -#include -#include -#include -#include - -#include "yank.h" -#include "conf.h" -#include "color.h" -#include "xmalloc.h" // for scxfree -*/ - -/** - * \brief TODO Document subtotal() - * - * \details Example command: subtotal A @sum C. If you want to replace a presxistant - * subtotals, you should use: rsubtotal A @sum C. - * - * \param[in] r used in defining the range of the data to be rearranged with subtotals - * \param[in] c used in defining the range of the data to be rearranged with subtotals - * \param[in] rf used in defining the range of the data to be rearranged with subtotals - * \param[in] cf used in defining the range of the data to be rearranged with subtotals - * \param[in] group_col - * \param[in] operation the operation to be done over the group can be one of the - * following: @sum, @prod, @avg, @count, @stddev, @max, @min - * \param[in] ope_col the operation column - * \param[in] replace_subtotal - * - * \return none - */ - -int subtotal(int r, int c, int rf, int cf, int group_col, char * operation, int ope_col, int replace_subtotals) { - // check ope_col and group_col are valid - if (ope_col < c || ope_col > cf || group_col < c || group_col > cf) return -1; - - // check if they are headers in first row - struct ent * p, * q; - int headers_in_first_row = 0; - if ((p = *ATBL(tbl, r, ope_col)) && p->label && - (q = *ATBL(tbl, r+1, ope_col)) && ! q->label) headers_in_first_row=1; - - // group operation shall be done over text content ! - wchar_t cline [BUFFERSIZE]; - p = *ATBL(tbl, r + headers_in_first_row, group_col); - swprintf(cline, BUFFERSIZE, L"+$%s", coltoa(group_col)); - - // sort the range - extern wchar_t interp_line[BUFFERSIZE]; - swprintf(interp_line, BUFFERSIZE, L"sort %s%d:", coltoa(c), r + headers_in_first_row); - swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d \"%ls\"", coltoa(cf), rf, cline); - send_to_interp(interp_line); - - // traverse the range and replace subtotals - // - // TODO replace subtotals only if replace_subtotals is set - int i, j, is_subtotal_row; - extern int cmd_multiplier; - //if (replace_subtotals) { - for (i=r+headers_in_first_row; i <= rf; i++) { - is_subtotal_row=0; - for (j=c; jlabel && p->label[0] == '+' && p->label[1] == '@') { is_subtotal_row=1; break; } - } - if (is_subtotal_row) { - cmd_multiplier = 1; - shift(i, c, i, cf, L'k'); - i--; - rf--; - } - } - //} - - // traverse the range and add subtotals - int new_rows = 0; - wchar_t cmd[BUFFERSIZE]; - int row_start_range = r + headers_in_first_row; - for (i=r+headers_in_first_row+1; i <= rf + new_rows + 1; i++) { - p = *ATBL(tbl, i-1, group_col); - q = *ATBL(tbl, i, group_col); - - // TODO ignore preexistance subtotals by default - - if ( (p && q && p->label && q->label && strcmp(q->label, p->label) != 0) - || i == rf + new_rows + 1) { - cmd_multiplier = 1; - shift(i, c, i, cf, L'j'); - - swprintf(cmd, BUFFERSIZE, L"rightstring %s%d = \"+%s(%s)\"", coltoa(group_col), i, operation, p->label); - send_to_interp(cmd); - - swprintf(cmd, BUFFERSIZE, L"let %s%d = %s(%s%d:%s%d)", coltoa(ope_col), i, operation, - coltoa(ope_col), row_start_range, coltoa(ope_col), i-1); - send_to_interp(cmd); - valueize_area(i, ope_col, i, ope_col); - - new_rows++; - i++; - row_start_range = i; - } - } - - return 0; -} - diff -Nru sc-im-0.8.2+ds/src/subtotal.h sc-im-0.8.3+ds/src/subtotal.h --- sc-im-0.8.2+ds/src/subtotal.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/subtotal.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file subtotal.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for subtotal.c - */ - -int subtotal(int r, int c, int rf, int cf, int group_col, char * operation, int ope_col, int replace_subtotals); diff -Nru sc-im-0.8.2+ds/src/trigger.c sc-im-0.8.3+ds/src/trigger.c --- sc-im-0.8.2+ds/src/trigger.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/trigger.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -67,7 +67,7 @@ #include "tui.h" #include "undo.h" #include "conf.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "trigger.h" #include "file.h" @@ -75,6 +75,8 @@ #include "lua.h" #endif +extern struct session * session; + /** * \brief TODO Document set_trigger() * @@ -87,8 +89,9 @@ * \return none */ -void set_trigger(int r, int c, int rf, int cf, char * str) { - if (any_locked_cells(r, c, rf, cf)) { +void set_trigger(struct sheet * sh, int r, int c, int rf, int cf, char * str) { + struct roman * roman = session->cur_doc; + if (any_locked_cells(sh, r, c, rf, cf)) { sc_error("Locked cells encountered. Nothing changed"); return; } @@ -118,7 +121,7 @@ for (i = r; i <= rf; i++) { for (j = c; j <= cf; j++) { // action - n = lookat(i, j); + n = lookat(sh, i, j); if (n->trigger == NULL) n->trigger = (struct trigger *) malloc(sizeof(struct trigger)); else { @@ -154,6 +157,7 @@ } } n->trigger->flag = tmp; + if (! roman->loading) sc_info("Trigger was set"); } } destroy_dictionary(d); @@ -171,8 +175,8 @@ * \return none */ -void del_trigger(int r, int c, int rf, int cf ) { - if (any_locked_cells(r, c, rf, cf)) { +void del_trigger(struct sheet * sh, int r, int c, int rf, int cf ) { + if (any_locked_cells(sh, r, c, rf, cf)) { sc_error("Locked cells encountered. Nothing changed"); return; } @@ -182,7 +186,7 @@ for (i = r; i <= rf; i++) { for (j = c; j <= cf; j++) { // action - n = lookat(i, j); + n = lookat(sh, i, j); if (n->trigger != NULL ) { if ((n->trigger->flag & TRG_C) == TRG_C) { dlclose(n->trigger->handle); @@ -208,16 +212,21 @@ * \return none */ -void do_trigger( struct ent *p , int rw) { +void do_trigger(struct ent *p , int rw) { struct trigger * trigger = p->trigger; if(in_trigger) return; in_trigger = 1; + #ifdef XLUA - if ((trigger->flag & TRG_LUA ) == TRG_LUA) + if ((trigger->flag & TRG_LUA ) == TRG_LUA) { + sc_info("%d %d", p->row, p->col); doLuaTrigger_cell(p,rw); + } #endif - if ((trigger->flag & TRG_C ) == TRG_C) + + if ((trigger->flag & TRG_C ) == TRG_C) { do_C_Trigger_cell(p,rw); + } in_trigger = 0; return; } diff -Nru sc-im-0.8.2+ds/src/trigger.h sc-im-0.8.3+ds/src/trigger.h --- sc-im-0.8.2+ds/src/trigger.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/trigger.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -56,7 +56,7 @@ int (*c_function) (struct ent *, int); }; -void do_trigger( struct ent *p , int rw); -void set_trigger(int r, int c, int rf, int cf, char * str); -void del_trigger(int r, int c, int rf, int cf ); +void do_trigger(struct ent * p, int rw); +void set_trigger(struct sheet * sh, int r, int c, int rf, int cf, char * str); +void del_trigger(struct sheet * sh, int r, int c, int rf, int cf ); void do_C_Trigger_cell(struct ent * p, int rw); diff -Nru sc-im-0.8.2+ds/src/tui.c sc-im-0.8.3+ds/src/tui.c --- sc-im-0.8.2+ds/src/tui.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/tui.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -88,10 +88,11 @@ #include "input.h" #include "tui.h" #include "range.h" +#include "interp.h" #include "sc.h" -#include "cmds.h" -#include "cmds_visual.h" -#include "cmds_command.h" +#include "cmds/cmds.h" +#include "cmds/cmds_visual.h" +#include "cmds/cmds_command.h" #include "conf.h" #include "version.h" #include "file.h" @@ -103,6 +104,7 @@ extern int cmd_pending; extern int cmd_multiplier; extern char insert_edit_submode; +extern struct session * session; WINDOW * main_win; WINDOW * input_win; @@ -184,8 +186,12 @@ set_term(sstdout); endwin(); + // ncurses memory leak? + // delscreen(sstdout); set_term(sstderr); endwin(); + // ncurses memory leak? + // delscreen(sstderr); return; } @@ -265,11 +271,12 @@ wmove(input_pad, 0, 0); status_line_empty = 0; - ui_refresh_pad(0); #ifdef USECOLORS ui_set_ucolor(input_win, &ucolors[INPUT], DEFAULT_COLOR); + ui_set_ucolor(input_pad, &ucolors[NORMAL], DEFAULT_COLOR); #endif - if (type == DEBUG_MSG || (loading && type == ERROR_MSG)) { + ui_refresh_pad(0); + if (type == DEBUG_MSG || (session != NULL && session->cur_doc != NULL && session->cur_doc->loading && type == ERROR_MSG)) { wtimeout(input_pad, -1); wgetch(input_pad); wtimeout(input_pad, TIMEOUT_CURSES); @@ -301,7 +308,7 @@ * \return none */ void ui_do_welcome() { - char * msg_title = "SC-IM - SpreadSheet Calculator Improvised"; + char * msg_title = "sc-im - SpreadSheet Calculator Improvised"; char * msg_by = "An SC fork by Andrés Martinelli"; char * msg_version = rev; char * msg_help = "Press :help to get help "; @@ -315,8 +322,8 @@ #endif // show headings - int nbcols = calc_mobile_cols(NULL); - int nbrows = calc_mobile_rows(NULL); + int nbcols = calc_mobile_cols(session->cur_doc->cur_sh, NULL); + int nbrows = calc_mobile_rows(session->cur_doc->cur_sh, NULL); ui_show_sc_col_headings(main_win, nbcols); ui_show_content(main_win, nbrows, nbcols); ui_show_sc_row_headings(main_win, nbrows); // show_sc_row_headings must be after show_content @@ -386,11 +393,13 @@ * \return none */ void ui_update(int header) { - if (loading) return; + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; + + if (roman->loading) return; if (cmd_multiplier > 1) return; if (get_conf_int("nocurses")) return; - if (header) { #ifdef USECOLORS wbkgd(main_win, COLOR_PAIR((ucolors[DEFAULT].fg+1) * (COLORS) + ucolors[DEFAULT].bg + 2)); // comment this to prevent bold to be reset @@ -398,12 +407,7 @@ wbkgd(input_pad, COLOR_PAIR((ucolors[DEFAULT].fg+1) * (COLORS) + ucolors[DEFAULT].bg + 2)); #endif - // Clean from top to bottom - wmove(main_win, 0, 0); - wclrtobot(main_win); - // comment this to prevent info message to be erased - //wmove(input_win, 0, 0); - //wclrtobot(input_win); + if (header) { ui_show_celldetails(); // always before ui_print_mode ui_print_mode(); wrefresh(input_win); @@ -411,10 +415,10 @@ } /* You can't hide the last row or col */ - while (row_hidden[currow]) - currow++; - while (col_hidden[curcol]) - curcol++; + while (sh->row_hidden[sh->currow]) + sh->currow++; + while (sh->col_hidden[sh->curcol]) + sh->curcol++; /* * Calculate offscreen rows and columns @@ -428,15 +432,20 @@ * the number of visible mobile columns and rows. The more there are * frozen rows/cols, the fewer mobile rows/cols. */ - int nb_mobile_cols = calc_mobile_cols(NULL); - int nb_mobile_rows = calc_mobile_rows(NULL); + int nb_mobile_cols = calc_mobile_cols(sh, NULL); // Show sc_col headings: A, B, C, D.. ui_show_sc_col_headings(main_win, nb_mobile_cols); - // Show the content of the cells - // Numeric values, strings. - ui_show_content(main_win, nb_mobile_rows, nb_mobile_cols); + int nb_mobile_rows; + int redraw_needed; + do { + nb_mobile_rows = calc_mobile_rows(sh, NULL); + + // Show the content of the cells + // Numeric values, strings. + redraw_needed = ui_show_content(main_win, nb_mobile_rows, nb_mobile_cols); + } while (redraw_needed); // Show sc_row headings: 0, 1, 2, 3.. ui_show_sc_row_headings(main_win, nb_mobile_rows); // schow_sc_row_headings must be after show_content @@ -505,6 +514,8 @@ * \return none */ void ui_print_mult_pend() { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; if (curmode != NORMAL_MODE && curmode != VISUAL_MODE && curmode != EDIT_MODE) return; int row_orig, col_orig; @@ -521,18 +532,20 @@ strcat(strm, "?"); } - char field[rescol+1]; + char field[sh->rescol+1]; field[0]='\0'; - sprintf(field, "%0*d", rescol - (int) strlen(strm), 0); + sprintf(field, "%0*d", sh->rescol - (int) strlen(strm), 0); subst(field, '0', ' '); strcat(strm, field); - mvwprintw(input_win, 0, COLS - rescol - 14, "%s", strm); + mvwprintw(input_win, 0, COLS - sh->rescol - 14, "%s", strm); wrefresh(input_win); // Return cursor to previous position wmove(input_pad, row_orig, col_orig); - ui_refresh_pad(0); + int scroll = 0; + if (inputline_pos > COLS - 14) scroll = inputline_pos - COLS + 14; + ui_refresh_pad(scroll); if (status_line_empty && curmode != EDIT_MODE && get_conf_int("show_cursor")) { // Leave cursor on selected cell when no status message @@ -544,12 +557,11 @@ /** * \brief Show first and second row (header). Handle cursor position. - * * \return none */ void ui_show_header() { //ui_clr_header(0); - ui_clr_header(1); + //ui_clr_header(1); // the clr stuff should be called outside this function // print multiplier ui_print_mult_pend(); @@ -570,6 +582,7 @@ case EDIT_MODE: mvwprintw(input_pad, 0, 1, "%ls", inputline); wmove(input_pad, 0, inputline_pos + 1); + break; } int scroll = 0; if (inputline_pos > COLS - 14) scroll += inputline_pos - COLS + 14; @@ -624,11 +637,6 @@ ui_set_ucolor(input_win, &ucolors[MODE], DEFAULT_COLOR); #endif - strm[0] = '\0'; - if (get_conf_int("filename_with_mode") && curfile[0]) { - sprintf(strm, "%s ", curfile); - } - if (curmode == NORMAL_MODE) { strcat(strm, " -- NORMAL --"); ui_write_j(input_win, strm, row, RIGHT); @@ -663,8 +671,8 @@ ui_set_ucolor(input_win, &ucolors[INPUT], DEFAULT_COLOR); #endif // show ':' - mvwprintw(input_pad, 0, 0, ":"); - wmove(input_pad, 0, 1); + //mvwprintw(input_pad, 0, 0, ":"); + //wmove(input_pad, 0, 1); } return; @@ -680,6 +688,8 @@ * \return none */ void ui_show_sc_row_headings(WINDOW * win, int nb_mobile_rows) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; #ifdef USECOLORS if (has_colors()) ui_set_ucolor(win, &ucolors[HEADINGS], DEFAULT_COLOR); #endif @@ -689,31 +699,31 @@ int winrow = RESCOLHEADER; int mobile_rows = nb_mobile_rows; - int total_rows = nb_mobile_rows + nb_frozen_rows; + int total_rows = nb_mobile_rows + sh->nb_frozen_rows; - for (i = 0; i < maxrows && total_rows > 0; i++) { - if (row_hidden[i]) + for (i = 0; i < sh->maxrows && total_rows > 0; i++) { + if (sh->row_hidden[i]) continue; - if (! row_frozen[i]) { - if (i < offscr_sc_rows) + if (! sh->row_frozen[i]) { + if (i < sh->offscr_sc_rows) continue; if (--mobile_rows < 0) continue; } --total_rows; - if ( (s != NULL && i >= s->tlrow && i <= s->brrow) || i == currow ) { + if ( (s != NULL && i >= s->tlrow && i <= s->brrow) || i == sh->currow ) { #ifdef USECOLORS if (has_colors()) ui_set_ucolor(win, &ucolors[CELL_SELECTION], DEFAULT_COLOR); #else wattron(win, A_REVERSE); #endif } - mvwprintw (win, winrow, 0, "%*d ", rescol-1, i); - if (row_frozen[i]) mvwprintw (win, winrow, rescol-1, "!"); + mvwprintw (win, winrow, 0, "%*d ", sh->rescol-1, i); + if (sh->row_frozen[i]) mvwprintw (win, winrow, sh->rescol-1, "!"); - for (j = 1; j < row_format[i]; j++) - mvwprintw (win, winrow+j, 0, "%*c ", rescol-1, ' '); + for (j = 1; j < sh->row_format[i]; j++) + mvwprintw (win, winrow+j, 0, "%*c ", sh->rescol-1, ' '); #ifdef USECOLORS if (has_colors()) ui_set_ucolor(win, &ucolors[HEADINGS], DEFAULT_COLOR); @@ -721,7 +731,7 @@ wattroff(win, A_REVERSE); #endif - winrow += row_format[i]; + winrow += sh->row_format[i]; } } @@ -735,21 +745,23 @@ * \return none */ void ui_show_sc_col_headings(WINDOW * win, int nb_mobile_cols) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; int i; srange * s = get_selected_range(); wmove(win, 0, 0); wclrtoeol(win); - int wincol = rescol; + int wincol = sh->rescol; int mobile_cols = nb_mobile_cols; - int total_cols = nb_mobile_cols + nb_frozen_cols; + int total_cols = nb_mobile_cols + sh->nb_frozen_cols; - for (i = 0; i < maxcols && total_cols > 0; i++) { - if (col_hidden[i]) + for (i = 0; i < sh->maxcols && total_cols > 0; i++) { + if (sh->col_hidden[i]) continue; - if (! col_frozen[i]) { - if (i < offscr_sc_cols) + if (! sh->col_frozen[i]) { + if (i < sh->offscr_sc_cols) continue; if (--mobile_cols < 0) continue; @@ -763,7 +775,7 @@ ui_set_ucolor(win, &ucolors[HEADINGS_ODD], DEFAULT_COLOR); #endif - if ( (s != NULL && i >= s->tlcol && i <= s->brcol) || i == curcol ) { + if ( (s != NULL && i >= s->tlcol && i <= s->brcol) || i == sh->curcol ) { #ifdef USECOLORS if (has_colors()) ui_set_ucolor(win, &ucolors[CELL_SELECTION], DEFAULT_COLOR); #else @@ -771,10 +783,12 @@ #endif } - // we want ! after column name: - int k = (fwidth[i] - 1) / 2; - mvwprintw(win, 0, wincol, "%*s%s%s%*s", k, "", coltoa(i), - col_frozen[i] ? "!" : "", fwidth[i] - k - (col_frozen[i] ? strlen(coltoa(i))+1 : strlen(coltoa(i))), ""); + char *a = coltoa(i); + int l1 = (i < 26) ? 1 : 2; + int l2 = sh->col_frozen[i] ? 1 : 0; + int f1 = (sh->fwidth[i] - l1 - l2)/2 + l1; + int f2 = sh->fwidth[i] - f1; + mvwprintw(win, 0, wincol, "%*s%*s", f1, a, -f2, sh->col_frozen[i] ? "!" : ""); #ifdef USECOLORS if (has_colors() && i % 2 == 0) @@ -785,7 +799,7 @@ wattroff(win, A_REVERSE); #endif - wincol += fwidth[i]; + wincol += sh->fwidth[i]; } } @@ -799,8 +813,11 @@ * * \return none */ -void ui_show_content(WINDOW * win, int nb_mobile_rows, int nb_mobile_cols) { +int ui_show_content(WINDOW * win, int nb_mobile_rows, int nb_mobile_cols) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; int row, col; + int redraw_needed = FALSE; srange * s = get_selected_range(); int conf_underline_grid = get_conf_int("underline_grid"); @@ -810,36 +827,39 @@ int winrow = RESCOLHEADER; int mobile_rows = nb_mobile_rows; - int total_rows = nb_mobile_rows + nb_frozen_rows; + int total_rows = nb_mobile_rows + sh->nb_frozen_rows; + + wmove(win, winrow, 0); + wclrtobot(win); - for (row = 0; row < maxrows && total_rows > 0; row++) { - if (row_hidden[row]) + for (row = 0; row < sh->maxrows && total_rows > 0; row++) { + if (sh->row_hidden[row]) continue; - if (! row_frozen[row]) { - if (row < offscr_sc_rows) + if (! sh->row_frozen[row]) { + if (row < sh->offscr_sc_rows) continue; if (--mobile_rows < 0) continue; } --total_rows; - int wincol = rescol; + int wincol = sh->rescol; int mobile_cols = nb_mobile_cols; - int total_cols = nb_mobile_cols + nb_frozen_cols; + int total_cols = nb_mobile_cols + sh->nb_frozen_cols; - for (col = 0; col < maxcols && total_cols > 0; col++) { - if (col_hidden[col]) + for (col = 0; col < sh->maxcols && total_cols > 0; col++) { + if (sh->col_hidden[col]) continue; - if (! col_frozen[col]) { - if (col < offscr_sc_cols) + if (! sh->col_frozen[col]) { + if (col < sh->offscr_sc_cols) continue; if (--mobile_cols < 0) continue; } --total_cols; - struct ent ** p = ATBL(tbl, row, col); - int fieldlen = fwidth[col]; + struct ent ** p = ATBL(sh, sh->tbl, row, col); + int fieldlen = sh->fwidth[col]; // Clean format #ifdef USECOLORS @@ -866,7 +886,7 @@ } // setup color for selected cell - if ((currow == row) && (curcol == col)) { + if ((sh->currow == row) && (sh->curcol == col)) { #ifdef USECOLORS if (has_colors()) ui_set_ucolor(win, &ucolors[CELL_SELECTION_SC], ucolors[CELL_SELECTION_SC].bg != DEFAULT_COLOR ? DEFAULT_COLOR : col % 2 == 0 ? ucolors[GRID_EVEN].bg : ucolors[GRID_ODD].bg); #else @@ -911,7 +931,7 @@ if (res == 0 || res == 1) { strcpy(num, formated_s); } else if (res == -1) { - sprintf(num, "%.*f", precision[col], (*p)->v); + sprintf(num, "%.*f", sh->precision[col], (*p)->v); } } @@ -942,7 +962,7 @@ } // repaint a blank cell or range - if ( (currow == row && curcol == col) || + if ( (sh->currow == row && sh->curcol == col) || ( in_range && row >= ranges->tlrow && row <= ranges->brrow && col >= ranges->tlcol && col <= ranges->brcol ) ) { #ifdef USECOLORS @@ -966,7 +986,7 @@ wchar_t w; int i, j, k; - for (k=0; k < row_format[row]; k++) { + for (k=0; k < sh->row_format[row]; k++) { for (i = 0; i < fieldlen; ) { w = L' '; j = mvwin_wchnstr (win, winrow+k, wincol+i, cht, 1); @@ -987,13 +1007,7 @@ // else if get_conf_int("hide_number_from_combined")) // num[0]='\0'; // } - pad_and_align(text, num, fieldlen, align, (*p)->pad, out, row_format[row]); - - // auto wrap - if (!conf_truncate && !conf_overlap && conf_autowrap) { - int newheight = (wcslen(out) + fwidth[col] - 1) / fwidth[col]; - if (row_format[row] < newheight) row_format[row] = newheight; - } + pad_and_align(text, num, fieldlen, align, (*p)->pad, out, sh->row_format[row]); #ifdef USECOLORS if (has_colors() && conf_underline_grid) { @@ -1003,24 +1017,35 @@ wattr_set(win, attr | A_UNDERLINE, color, NULL); } #endif - // 'out' may contain the output to fill multiple rows. not just one. - int count_row = 0; - wchar_t new[wcslen(out)+1]; - for (count_row = 0; count_row < row_format[row]; count_row++) { - int cw = count_width_widestring(out, fieldlen); - wcscpy(new, out); - if (conf_truncate || !conf_overlap) new[cw] = L'\0'; - - int whites = fieldlen - cw; - while (whites-- > 0) add_wchar(new, L' ', wcslen(new)); - if (wcslen(new)) mvwprintw(win, winrow+count_row, wincol, "%ls", new); - //wclrtoeol(win); - if (cw) del_range_wchars(out, 0, cw-1); - if (conf_overlap) break; + + if (!conf_truncate && !conf_overlap && conf_autowrap) { + // auto wrap + int newheight = (wcslen(out) + sh->fwidth[col] - 1) / sh->fwidth[col]; + if (sh->row_format[row] < newheight) { + sh->row_format[row] = newheight; + /* calc_mobile_rows() didn't know about this */ + redraw_needed = TRUE; + } + } + + if (!conf_overlap || sh->row_format[row] != 1) { + int k; + wchar_t *p_out = out; + for (k = 0; k < sh->row_format[row]; k++) { + int eol = count_width_widestring(p_out, fieldlen); + wchar_t save = p_out[eol]; + p_out[eol] = L'\0'; + mvwprintw(win, winrow+k, wincol, "%*ls", -fieldlen, p_out); + p_out[eol] = save; + p_out += eol; + } + } else { + //sh->row_format[row] = 1; + mvwprintw(win, winrow, wincol, "%*ls", -fieldlen, out); } } - if (currow == row && curcol == col) { + if (sh->currow == row && sh->curcol == col) { curwinrow = winrow; curwincol = wincol; if (out[0] == L'\0') { @@ -1041,8 +1066,10 @@ wincol += fieldlen; } - winrow += row_format[row]; + winrow += sh->row_format[row]; } + + return redraw_needed; } @@ -1098,26 +1125,61 @@ /** * \brief Draw cell content detail in header + * Also show current sheet name * \return none */ void ui_show_celldetails() { + // return if no open file + if (session->cur_doc == NULL) return; + + struct sheet * sh = session->cur_doc->cur_sh; + char head[FBUFLEN]; int il_pos = 0; + // show filenames + for (struct roman * rom = session->first_doc; rom != NULL; rom = rom->next) { +#ifdef USECOLORS + ui_set_ucolor(input_win, &ucolors[FILENM], DEFAULT_COLOR); +#endif + char * file_name = rom->name == NULL ? "[No Name]" : rom->name; + mvwprintw(input_win, 0, il_pos, "%s:", file_name); + il_pos += strlen(file_name) + 1; + + // show sheets + for (struct sheet * sh = rom->first_sh; sh != NULL; sh = sh->next) { + if (sh == session->cur_doc->cur_sh) { +#ifdef USECOLORS + ui_set_ucolor(input_win, &ucolors[CURRENT_SHEET], DEFAULT_COLOR); +#endif + if (get_conf_int("show_cursor")) mvwprintw(input_win, 0, il_pos++, "*"); + } else { +#ifdef USECOLORS + ui_set_ucolor(input_win, &ucolors[SHEET], DEFAULT_COLOR); +#endif + if (get_conf_int("show_cursor")) mvwprintw(input_win, 0, il_pos++, " "); + } + mvwprintw(input_win, 0, il_pos, "{%s}", sh->name); + il_pos += strlen(sh->name) + 2; + } + mvwprintw(input_win, 0, il_pos, " "); + il_pos += 2; + } + // show cell in header - #ifdef USECOLORS +#ifdef USECOLORS ui_set_ucolor(input_win, &ucolors[CELL_ID], DEFAULT_COLOR); - #endif - sprintf(head, "%s%d ", coltoa(curcol), currow); - mvwprintw(input_win, 0, 0, "%s", head); +#endif + sprintf(head, "%s%d ", coltoa(sh->curcol), sh->currow); + mvwprintw(input_win, 0, il_pos, "%s", head); il_pos += strlen(head); // show the current cell's format - #ifdef USECOLORS +#ifdef USECOLORS ui_set_ucolor(input_win, &ucolors[CELL_FORMAT], DEFAULT_COLOR); - #endif +#endif - register struct ent *p1 = *ATBL(tbl, currow, curcol); + struct ent *p1 = *ATBL(sh, sh->tbl, sh->currow, sh->curcol); // show padding if (p1 != NULL && p1->pad) @@ -1129,17 +1191,17 @@ if ((p1) && p1->format) sprintf(head + strlen(head), "(%s) ", p1->format); else - sprintf(head + strlen(head), "(%d %d %d) ", fwidth[curcol], precision[curcol], realfmt[curcol]); + sprintf(head + strlen(head), "(%d %d %d) ", sh->fwidth[sh->curcol], sh->precision[sh->curcol], sh->realfmt[sh->curcol]); mvwprintw(input_win, 0, il_pos, "%s", head); il_pos += strlen(head); // show expr - #ifdef USECOLORS +#ifdef USECOLORS ui_set_ucolor(input_win, &ucolors[CELL_CONTENT], DEFAULT_COLOR); - #endif +#endif if (p1 && p1->expr) { linelim = 0; - editexp(currow, curcol); /* set line to expr */ + editexp(sh, sh->currow, sh->curcol); /* set line to expr */ linelim = -1; sprintf(head, "[%.*s] ", FBUFLEN-4, line); mvwprintw(input_win, 0, il_pos, "%s", head); @@ -1151,10 +1213,10 @@ // cut string if its too large! if (strlen(head) > COLS - il_pos - 1) { - head[COLS - il_pos - 1 - 15]='>'; - head[COLS - il_pos - 1 - 14]='>'; - head[COLS - il_pos - 1 - 13]='>'; - head[COLS - il_pos - 1 - 12]='\0'; + head[COLS - il_pos - 1 - 19]='>'; + head[COLS - il_pos - 1 - 18]='>'; + head[COLS - il_pos - 1 - 17]='>'; + head[COLS - il_pos - 1 - 16]='\0'; } mvwprintw(input_win, 0, il_pos, "%s", head); @@ -1191,8 +1253,10 @@ * \return -1 if there is no format in the cell */ int ui_get_formated_value(struct ent ** p, int col, char * value) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; //char * cfmt = (*p)->format ? (*p)->format : NULL; - char * cfmt = (*p)->format ? (*p)->format : (realfmt[col] >= 0 && realfmt[col] < COLFORMATS && colformat[realfmt[col]] != NULL) ? colformat[realfmt[col]] : NULL; + char * cfmt = (*p)->format ? (*p)->format : (sh->realfmt[col] >= 0 && sh->realfmt[col] < COLFORMATS && colformat[sh->realfmt[col]] != NULL) ? colformat[sh->realfmt[col]] : NULL; if (cfmt) { if (*cfmt == 'd') { @@ -1200,12 +1264,12 @@ strftime(value, sizeof(char) * FBUFLEN, cfmt + 1, localtime(&v)); return 0; } else { - format(cfmt, precision[col], (*p)->v, value, sizeof(char) * FBUFLEN); + format(cfmt, sh->precision[col], (*p)->v, value, sizeof(char) * FBUFLEN); return 1; } } else { // there is no format // FIXME: error with number and text in same cell and no overlap - engformat(realfmt[col], fwidth[col], precision[col], (*p)->v, value, sizeof(char) * FBUFLEN); + engformat(sh->realfmt[col], sh->fwidth[col], sh->precision[col], (*p)->v, value, sizeof(char) * FBUFLEN); ltrim(value, ' '); return 1; } @@ -1339,6 +1403,7 @@ * \return user input */ char * ui_query(char * initial_msg) { + struct roman * roman = session->cur_doc; char * hline = (char *) malloc(sizeof(char) * BUFFERSIZE); hline[0]='\0'; @@ -1355,11 +1420,11 @@ // curses is enabled int loading_o; - if (loading) { - loading_o=loading; - loading=0; + if (roman->loading) { + loading_o = roman->loading; + roman->loading = 0; ui_update(0); - loading=loading_o; + roman->loading = loading_o; } curs_set(1); @@ -1540,13 +1605,10 @@ */ #ifdef MOUSE void ui_handle_mouse(MEVENT event) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; if (isendwin()) return; - // if out of range return - int i, j, r = 0, c = 0; - if ( event.x < RESCOL || ( get_conf_int("input_bar_bottom") && (event.y == 0 || event.y >= LINES - RESROW)) || - ( !get_conf_int("input_bar_bottom") && (event.y <= RESROW))) return; - // if mode is not handled return if (curmode != NORMAL_MODE && curmode != INSERT_MODE && curmode != COMMAND_MODE) return; @@ -1554,13 +1616,13 @@ #ifdef BUTTON5_PRESSED if (curmode == NORMAL_MODE && (event.bstate & BUTTON4_PRESSED || // scroll up event.bstate & BUTTON5_PRESSED)) { // scroll down - int n = calc_mobile_rows(NULL); + int n = calc_mobile_rows(sh, NULL); if (get_conf_int("half_page_scroll")) n = n / 2; - lastcol = curcol; - lastrow = currow; - currow = event.bstate & BUTTON5_PRESSED ? forw_row(n)->row : back_row(n)->row; - if (event.bstate & BUTTON5_PRESSED) scroll_down(n); - else scroll_up(n); + sh->lastcol = sh->curcol; + sh->lastrow = sh->currow; + sh->currow = event.bstate & BUTTON5_PRESSED ? forw_row(sh, n)->row : back_row(sh, n)->row; + if (event.bstate & BUTTON5_PRESSED) scroll_down(sh, n); + else scroll_up(sh, n); unselect_ranges(); ui_update(TRUE); return; @@ -1573,49 +1635,55 @@ // return if not a single click if (! (event.bstate & BUTTON1_CLICKED)) return; - c = event.x - RESCOL; - r = event.y - RESROW + (get_conf_int("input_bar_bottom") ? 1 : - 1); + // get coordinates corresponding to the grid area + int c = event.x - sh->rescol; + int r = event.y - RESROW + (get_conf_int("input_bar_bottom") ? 1 : -1); - int mobile_cols = calc_mobile_cols(NULL); - int mobile_rows = calc_mobile_rows(NULL); + // if out of range return + if ( c < 0 || c >= SC_DISPLAY_COLS || + r < 0 || r >= SC_DISPLAY_ROWS ) return; + + int i, j; + int mobile_cols = calc_mobile_cols(sh, NULL); + int mobile_rows = calc_mobile_rows(sh, NULL); int scr_col = 0; int scr_row = 0; - for (i = 0; i < maxcols; i++) { - if (col_hidden[i]) + for (i = 0; i < sh->maxcols; i++) { + if (sh->col_hidden[i]) continue; - if (! col_frozen[i]) { - if (i < offscr_sc_cols) + if (! sh->col_frozen[i]) { + if (i < sh->offscr_sc_cols) continue; if (--mobile_cols < 0) continue; } - scr_col += fwidth[i]; + scr_col += sh->fwidth[i]; if (scr_col >= c + 1) break; } // same for rows - for (j = 0; j < maxrows; j++) { - if (row_hidden[j]) + for (j = 0; j < sh->maxrows; j++) { + if (sh->row_hidden[j]) continue; - if (! row_frozen[j]) { - if (j < offscr_sc_rows) + if (! sh->row_frozen[j]) { + if (j < sh->offscr_sc_rows) continue; if (--mobile_rows < 0) continue; } - scr_row += row_format[j]; + scr_row += sh->row_format[j]; if (scr_row >= r + 1) break; } - if (i >= maxcols || j >= maxrows) return; + if (i >= sh->maxcols || j >= sh->maxrows) return; // if in normal mode, change currow and curcol if (curmode == NORMAL_MODE) { - curcol = i; - currow = j; + sh->curcol = i; + sh->currow = j; unselect_ranges(); // if in insert or command mode, we add the selected cell to inputbar diff -Nru sc-im-0.8.2+ds/src/tui.h sc-im-0.8.3+ds/src/tui.h --- sc-im-0.8.2+ds/src/tui.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/tui.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -91,7 +91,7 @@ void ui_sc_msg(char * s, int type, ...); void ui_set_ucolor(WINDOW * w, struct ucolor * uc, int bg_override); -void ui_show_content(WINDOW * win, int mxrow, int mxcol); +int ui_show_content(WINDOW * win, int mxrow, int mxcol); void ui_show_sc_row_headings(WINDOW * win, int mxrow); void ui_show_sc_col_headings(WINDOW * win, int mxcol); void ui_add_cell_detail(char * d, struct ent * p1); diff -Nru sc-im-0.8.2+ds/src/undo.c sc-im-0.8.3+ds/src/undo.c --- sc-im-0.8.2+ds/src/undo.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/undo.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -38,7 +38,7 @@ /** * \file undo.c * \author Andrés Martinelli - * \date 04/05/2021 + * \date 06/06/2021 * \brief This file contains the main functions to support the undo/redo feature. */ @@ -48,9 +48,12 @@ * p_ant: pointer to 'undo' struct. If NULL, this node is the first change * for the session. * - * struct ent * added: 'ent' elements added by the change + * struct ent_ptr * added: 'ent' elements added by the change * - * struct ent * removed: 'ent' elements removed by the change + * struct ent_ptr * removed: 'ent' elements removed by the change + * + * struct allocation_list * allocations: since we alloc over added and removed + * list in batches. we need to keep the first position in memory of each calloc. * * struct undo_range_shift * range_shift: range shifted by change * @@ -71,11 +74,6 @@ * * col_unfrozed: integers list (int *) unfrozen cols on screen * - * struct ent_ptr * allocations: since we alloc over added and removed - * list in batches. we need to keep the first position in memory of each calloc. - * - * int alloc_size: the number of batch allocations. - * * struct undo_cols_format * cols_format: list of 'undo_col_info' elements used for * undoing / redoing changes in columns format (fwidth, precision y realfmt) * @@ -85,6 +83,13 @@ * p_sig: pointer to 'undo' struct, If NULL, this node is the last change in * the session. * + * modflg_bef: document modflg before the change + * maxrow_bef: sheet maxrow before the change + * maxcol_bef: sheet maxcol before the change + * modflg_aft: document modflg after the change + * maxrow_aft: sheet maxrow after the change + * maxcol_aft: sheet maxcol after the change + * * Follows one level UNDO/REDO scheme. A change (C1) is made, then an UNDO operation, and * another change (C2). From there later changes are removed. * Scheme: @@ -140,15 +145,18 @@ #ifdef UNDO #include +#include "sc.h" #include "undo.h" #include "macros.h" +#include "color.h" #include "curses.h" #include "conf.h" -#include "sc.h" -#include "cmds.h" +#include "cmds/cmds.h" #include "marks.h" -#include "shift.h" -#include "dep_graph.h" +#include "actions/shift.h" +#include "graph.h" + +extern struct session * session; // undolist static struct undo * undo_list = NULL; @@ -162,21 +170,21 @@ // Temporal variable static struct undo undo_item; + /** * \brief Init 'undo_item' - * * \return none */ void create_undo_action() { undo_item.added = NULL; undo_item.removed = NULL; undo_item.allocations = NULL; - undo_item.alloc_size = 0; undo_item.p_ant = NULL; undo_item.p_sig = NULL; undo_item.range_shift = NULL; undo_item.cols_format = NULL; undo_item.rows_format = NULL; + undo_item.sheet = session->cur_doc->cur_sh; // we should keep the current sheet reference undo_item.row_hidded = NULL; undo_item.row_showed = NULL; @@ -186,9 +194,13 @@ undo_item.col_showed = NULL; undo_item.col_frozed = NULL; undo_item.col_unfrozed = NULL; + undo_item.modflg_bef = session->cur_doc->modflg; + undo_item.maxrow_bef = undo_item.sheet->maxrow; + undo_item.maxcol_bef = undo_item.sheet->maxcol; return; } + /** * @brief end_undo_action() * @@ -197,18 +209,21 @@ * * \return none */ - void end_undo_action() { + struct roman * roman = session->cur_doc; + undo_item.modflg_aft = roman->modflg; + undo_item.maxrow_aft = undo_item.sheet->maxrow; + undo_item.maxcol_aft = undo_item.sheet->maxcol; add_to_undolist(undo_item); - // in case we need to dismiss this undo_item! + // just check if we need to dismiss this undo_item! if ((undo_item.added == NULL && undo_item.allocations == NULL && undo_item.removed == NULL && undo_item.range_shift == NULL && undo_item.row_hidded == NULL && undo_item.row_showed == NULL && undo_item.row_frozed == NULL && undo_item.col_frozed == NULL && undo_item.row_unfrozed == NULL && undo_item.col_unfrozed == NULL && undo_item.cols_format == NULL && undo_item.rows_format == NULL && - undo_item.col_hidded == NULL && undo_item.col_showed == NULL) || loading) { + undo_item.col_hidded == NULL && undo_item.col_showed == NULL) || roman->loading) { if (undo_list->p_ant != NULL) undo_list = undo_list->p_ant; undo_list_pos--; clear_from_current_pos(); @@ -217,8 +232,9 @@ return; } + /** - * \brief Document add_to_undolist() + * \brief add_to_undolist() * * \details Add an undo node to the undolist. Allocate memory for * undo struct. Fill variable with undo_item value and append it @@ -228,7 +244,6 @@ * * \return none */ - void add_to_undolist(struct undo u) { // If not at the end of the list, remove from the end if (undo_list != NULL && undo_list_pos != len_undo_list()) clear_from_current_pos(); @@ -239,8 +254,8 @@ // Add 'ent' elements ul->added = u.added; ul->removed = u.removed; + ul->sheet = u.sheet; ul->allocations = u.allocations; - ul->alloc_size = u.alloc_size; ul->range_shift = u.range_shift; ul->cols_format = u.cols_format; ul->rows_format = u.rows_format; @@ -271,6 +286,7 @@ return; } + /** * \brief Dismiss current undo_item * @@ -284,64 +300,72 @@ * * \return none */ - void dismiss_undo_item(struct undo * ul) { if (ul == NULL) ul = &undo_item; // first free inside each added and removed ents // (their labels, expressions, etc. - struct ent * en; - struct ent * de; + struct ent_ptr * en; + struct ent_ptr * de; en = ul->added; // free added while (en != NULL) { de = en->next; - clearent(en); - //free(en); // do not free the struct * ent. thats get freed later in batches + clearent(en->vp); + free(en->vp); + en->vp = NULL; en = de; } en = ul->removed; // free removed while (en != NULL) { de = en->next; - clearent(en); - //free(en); // do not free the struct * ent. thats get freed below in batches + clearent(en->vp); + free(en->vp); + en->vp = NULL; en = de; } // now free added and removed lists // in the way they were alloc'ed (as batches) - int i, size = ul->allocations != NULL ? ul->allocations[0].vf : 0; - struct ent_ptr * alls = ul->allocations; + int i, size = ul->allocations != NULL ? ul->allocations->size : 0; + struct ent_ptr ** alls = ul->allocations != NULL ? ul->allocations->items : NULL; for (i = 0; i < size; i++) { - free(alls->vp); - alls->vp = NULL; + free(*alls); // each ent_ptr + *alls = NULL; alls++; } - free(ul->allocations); - ul->allocations = NULL; + if (ul->allocations != NULL) { + if (ul->allocations->items != NULL) { + free(ul->allocations->items); + ul->allocations->items = NULL; + } + free(ul->allocations); + ul->allocations = NULL; + } - if (ul->range_shift != NULL) free(ul->range_shift); // Free undo_range_shift memory - if (ul->cols_format != NULL) { // Free cols_format memory + if (ul->range_shift != NULL) free(ul->range_shift); // Free undo_range_shift memory + if (ul->cols_format != NULL) { // Free cols_format memory free(ul->cols_format->cols); free(ul->cols_format); } - if (ul->rows_format != NULL) { // Free rows_format memory + if (ul->rows_format != NULL) { // Free rows_format memory free(ul->rows_format->rows); free(ul->rows_format); } - if (ul->row_hidded != NULL) free(ul->row_hidded); // Free hidden row memory - if (ul->col_hidded != NULL) free(ul->col_hidded); // Free hidden col memory - if (ul->row_showed != NULL) free(ul->row_showed); // Free showed row memory - if (ul->row_frozed != NULL) free(ul->row_frozed); // Free frozed row memory - if (ul->col_showed != NULL) free(ul->col_showed); // Free showed col memory - if (ul->col_frozed != NULL) free(ul->col_frozed); // Free frozed col memory + if (ul->row_hidded != NULL) free(ul->row_hidded); // Free hidden row memory + if (ul->col_hidded != NULL) free(ul->col_hidded); // Free hidden col memory + if (ul->row_showed != NULL) free(ul->row_showed); // Free showed row memory + if (ul->row_frozed != NULL) free(ul->row_frozed); // Free frozed row memory + if (ul->col_showed != NULL) free(ul->col_showed); // Free showed col memory + if (ul->col_frozed != NULL) free(ul->col_frozed); // Free frozed col memory if (ul->row_unfrozed != NULL) free(ul->row_unfrozed); // Free unfrozed row memory if (ul->col_unfrozed != NULL) free(ul->col_unfrozed); // Free unfrozed col memory return; } + /** * \brief Cascade free UNDO node memory * @@ -349,7 +373,6 @@ * * \return none */ - void free_undo_node(struct undo * ul) { struct undo * e; @@ -365,12 +388,11 @@ return; } + /** * \brief Remove nodes below the current position from the undolist - * * \return none */ - void clear_from_current_pos() { if (undo_list == NULL) return; @@ -386,12 +408,11 @@ return; } + /** * \brief Remove undolist content - * * \return none */ - void clear_undo_list() { if (undo_list == NULL) return; @@ -406,24 +427,41 @@ undo_list = NULL; undo_list_pos = 0; - return; } + /** * \brief Return the length of the undo list - * * \return length of undolist */ - int len_undo_list() { return undo_list_len; } +/* + * \brief ent_ptr_exists_on_list + * \details check if an ent exists on ent_ptr list + * (used for added / removed lists of undo struct) + * return 0 if not exists or 1 if exists. + */ +int ent_ptr_exists_on_list(struct ent_ptr * list, struct ent_ptr * ep) { + int repeated = 0; + if (ep == NULL) return repeated; + while (list != NULL && list->vp != NULL) { + if (list->sheet == ep->sheet && list->vp->row == ep->vp->row && list->vp->col == ep->vp->col) { + repeated = 1; + break; + } + list = list->next; + } + return repeated; +} + /** * \brief copy_to_undostruct() * - * \details Take a range of 'ent' elements and create ent copies to keep in undo structs lists + * \details Take a range of 'ent' elements of a sheet, and create ent copies to keep in undo structs lists * such as the 'added' or 'removed' lists. * * char type: indicates UNDO_ADD ('a') for added list. or UNDO_DEL ('d') for the 'removed' list. @@ -431,56 +469,53 @@ * handle_deps: if set to HANDLE_DEPS it will store the dependencies of the specified range as well. * remember deps is a global variable. * - * destination: struct ent * pointer to use in the copy. if none was given, just malloc one. + * destination: struct ent_ptr ** to use in the copy. if none was given, just malloc one. + * Note that if destination is not null, the struct ent * vp inside the struct ent_ptr is already malloc'ed * returns: none */ - -void copy_to_undostruct (int ri, int ci, int rf, int cf, char type, short handle_deps, struct ent ** destination) { +void copy_to_undostruct (struct sheet * sh, int ri, int ci, int rf, int cf, char type, short handle_deps, struct ent_ptr ** destination) { int i, c, r; struct ent * p; extern struct ent_ptr * deps; - //int repeated; - // ask for memory to keep struct ent * for the whole range // and only if no destination pointer was given - struct ent * y_cells = destination == NULL ? NULL : *destination; + struct ent_ptr * y_cells = destination == NULL ? NULL : *destination; if (y_cells == NULL && handle_deps == HANDLE_DEPS && deps != NULL) - y_cells = (struct ent *) calloc((rf-ri+1)*(cf-ci+1)+deps->vf, sizeof(struct ent)); + y_cells = (struct ent_ptr *) calloc((rf-ri+1)*(cf-ci+1) + deps->vf, sizeof(struct ent_ptr)); else if (y_cells == NULL) - y_cells = (struct ent *) calloc((rf-ri+1)*(cf-ci+1), sizeof(struct ent)); + y_cells = (struct ent_ptr *) calloc((rf-ri+1)*(cf-ci+1), sizeof(struct ent_ptr)); // if no destination pointer was given // we save the pointer for future free - if (destination == NULL) save_pointer_after_calloc(y_cells); + if (destination == NULL) save_yl_pointer_after_calloc(y_cells); for (r = ri; r <= rf; r++) for (c = ci; c <= cf; c++) { - p = *ATBL(tbl, r, c); + p = *ATBL(sh, sh->tbl, r, c); if (p == NULL) continue; - // initialize the 'ent' - cleanent(y_cells); - /* here check that ent to add is not already in the list * if so, avoid to add a duplicate ent - * commented cause its resource consuming and harmless to duplicate - struct ent * lista = type == 'a' ? undo_item.added : undo_item.removed; - repeated = 0; - while (lista != NULL) { - if (lista->row == r && lista->col == c) { - repeated = 1; - break; - } - lista = lista->next; - } - if (repeated) continue; */ + struct ent_ptr * lista = type == 'a' ? undo_item.added : undo_item.removed; + struct ent_ptr e; + e.sheet = sh; + e.vp = p; + if (ent_ptr_exists_on_list(lista, &e)) continue; + + // initialize the 'ent' + //if (destination == NULL) y_cells->vp = malloc(sizeof(struct ent)); + y_cells->vp = malloc(sizeof(struct ent)); + cleanent(y_cells->vp); + y_cells->sheet = sh; // Copy cell at 'r, c' contents to 'y_cells' ent - copyent(y_cells, lookat(r, c), 0, 0, 0, 0, 0, 0, 'u'); + y_cells->vp->expr = NULL; + copyent(y_cells->vp, sh, lookat(sh, r, c), 0, 0, 0, 0, 0, 0, 'u'); // Append 'ent' element at the beginning + //TODO: add it ordered? if (type == UNDO_ADD) { y_cells->next = undo_item.added; undo_item.added = y_cells; @@ -497,16 +532,21 @@ // do the same for dependencies if (handle_deps == HANDLE_DEPS) for (i = 0; deps != NULL && i < deps->vf; i++) { - p = *ATBL(tbl, deps[i].vp->row, deps[i].vp->col); + p = *ATBL(deps[i].sheet, deps[i].sheet->tbl, deps[i].vp->row, deps[i].vp->col); if (p == NULL) continue; // initialize the 'ent' - cleanent(y_cells); + //if (destination == NULL) y_cells->vp = malloc(sizeof(struct ent)); + y_cells->vp = malloc(sizeof(struct ent)); + cleanent(y_cells->vp); + y_cells->sheet = deps[i].sheet; // Copy cell at deps[i].vp->row, deps[i].vp->col contents to 'y_cells' ent - copyent(y_cells, lookat(deps[i].vp->row, deps[i].vp->col), 0, 0, 0, 0, 0, 0, 'u'); + copyent(y_cells->vp, deps[i].sheet, lookat(deps[i].sheet, deps[i].vp->row, deps[i].vp->col), 0, 0, 0, 0, 0, 0, 'u'); + //sc_debug("copy_to_undostruct a undo %d %d", deps[i].vp->row, deps[i].vp->col); // Append 'ent' element at the beginning + //TODO: add it ordered? if (type == UNDO_ADD) { y_cells->next = undo_item.added; undo_item.added = y_cells; @@ -520,8 +560,10 @@ return; } + + /** - * \brief save_pointer_after_calloc() + * \brief save_yl_pointer_after_calloc() * * \details This function keeps in a pointer array every pointer that was returned by calloc * so we can free them @@ -529,45 +571,71 @@ * \param[in] struct ent e * \return void */ -void save_pointer_after_calloc(struct ent * e) { - undo_item.allocations = (struct ent_ptr *) realloc(undo_item.allocations, sizeof(struct ent_ptr) * (++(undo_item.alloc_size))); - undo_item.allocations[0].vf = undo_item.alloc_size; // we always keep size of list in the first position ! - undo_item.allocations[undo_item.alloc_size-1].vp = e; // keep the pointer so later can be freed + +void save_yl_pointer_after_calloc(struct ent_ptr * e) { + if (undo_item.allocations == NULL) { + undo_item.allocations = malloc(sizeof(struct allocation_list)); + undo_item.allocations->size = 0; + undo_item.allocations->items = NULL; + } + undo_item.allocations->items = (struct ent_ptr **) realloc(undo_item.allocations->items, sizeof(struct ent_ptr *) * (++(undo_item.allocations->size))); + undo_item.allocations->items[undo_item.allocations->size-1] = e; // keep the pointer so later can be freed } -/** + +/* * \brief copy_cell_to_undostruct() * * \details This function adds an struct ent * (new) to undo struct lists. * its contents are based on the struct ent * (ori). * could be added list or deleted list depending on the type. - * \param[in] struct ent e - * \param[in] struct ent ori + * \param[in] struct ent_ptr * e_ptr + * \param[in] struct sheet * sh_ori + * \param[in] struct ent * ori * \param[in] char type: indicates UNDO_ADD ('a') for added list. or UNDO_DEL ('d') for the 'removed' list. * - * the struct ent pointer is already alloc'ed - * + * the struct ent_ptr * e_ptr should be already alloc'ed * \return void + * NOTE: used on yank.c + * */ -void copy_cell_to_undostruct (struct ent * e, struct ent * ori, char type) { - struct ent * new = e; +void copy_cell_to_undostruct (struct ent_ptr * e_ptr, struct sheet * sh_ori, struct ent * ori, char type) { + /* here check that ent to add is not already in the list + * if so, avoid to add a duplicate ent + */ + struct ent_ptr * lista = type == 'a' ? undo_item.added : undo_item.removed; + struct ent_ptr e; + e.sheet = sh_ori; + e.vp = ori; + if (ent_ptr_exists_on_list(lista, &e)) return; + // in case of returning because ent exists on list, make sure struct ent_ptr gets freed later. + + // if reached here, malloc and add to undolist + struct ent_ptr * new_ptr = e_ptr; + struct ent * new = malloc(sizeof(struct ent)); + // initialize the 'ent' cleanent(new); // Copy 'ori' cell contents to 'new' ent - copyent(new, ori, 0, 0, 0, 0, 0, 0, 'u'); + copyent(new, sh_ori, ori, 0, 0, 0, 0, 0, 0, 'u'); + + new_ptr->sheet = sh_ori; + new_ptr->vp = new; // Append 'ent' element at the beginning + //TODO: add it ordered? if (type == UNDO_ADD) { - new->next = undo_item.added; - undo_item.added = new; + new_ptr->next = undo_item.added; + undo_item.added = new_ptr; } else { - new->next = undo_item.removed; - undo_item.removed = new; + new_ptr->next = undo_item.removed; + undo_item.removed = new_ptr; } return; } + /** * \brief add_undo_col_format() * @@ -596,6 +664,7 @@ return; } + /** * \brief add_undo_row_format() * @@ -620,10 +689,11 @@ return; } + /** - * \brief TODO Document save_undo_range_shift() + * \brief save_undo_range_shift() * - * \detials Take a range, a rows and columns delta and save them into + * \details Take a range, a rows and columns delta and save them into * they undo struct. Used to shift ranges when UNDO or REDO without * duplicating 'ent'elements. * @@ -636,7 +706,6 @@ * * \return none */ - void save_undo_range_shift(int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol) { struct undo_range_shift * urs = (struct undo_range_shift *) malloc( (unsigned) sizeof(struct undo_range_shift ) ); urs->delta_rows = delta_rows; @@ -650,6 +719,7 @@ } /* + * \brief undo_hide_show() * This function is used for undoing and redoing * changes caused by commands that hide/show rows/columns of screen * such as Zr Zc Sc Sr commands. @@ -657,9 +727,6 @@ * that are showed or hidden because of a change. * As these lists are dynamically built, in the first position of every list, * we always store the number of elements that the list has. - */ -/** - * \brief todo document undo_hide_show() * * \details this function is used for undoint and redoing changes * caused by commands that hide/show rows/columns of screen such @@ -749,7 +816,6 @@ * * \return none */ - void undo_freeze_unfreeze(int row, int col, char type, int arg) { int i; if (type == 'f') { @@ -816,83 +882,92 @@ * * \return none */ - void do_undo() { + struct roman * roman = session->cur_doc; if (undo_list == NULL || undo_list_pos == 0) { sc_error("No UNDO's left."); return; } - int ori_currow = currow; - int ori_curcol = curcol; - int mf = modflg; // save modflag status + // move to the according sheet + struct sheet * sh = undo_list->sheet; + roman->cur_sh = sh; + + int ori_currow = sh->currow; + int ori_curcol = sh->curcol; + //int mf = roman->modflg; // save modflag status struct undo * ul = undo_list; // removed added ents - struct ent * i = ul->added; + struct ent_ptr * i = ul->added; while (i != NULL) { - struct ent * pp = *ATBL(tbl, i->row, i->col); - clearent(pp); - cleanent(pp); + erase_area(i->sheet, i->vp->row, i->vp->col, i->vp->row, i->vp->col, 1, 0); i = i->next; } // Make undo shift, if any if (ul->range_shift != NULL) { + int deltarows = ul->range_shift->delta_rows; + int deltacols = ul->range_shift->delta_cols; + int brrow = ul->range_shift->brrow; + int tlrow = ul->range_shift->tlrow; + int brcol = ul->range_shift->brcol; + int tlcol = ul->range_shift->tlcol; // fix marks for rows - if (ul->range_shift->delta_rows > 0) // sj - fix_marks(-(ul->range_shift->brrow - ul->range_shift->tlrow + 1), 0, ul->range_shift->tlrow, maxrow, ul->range_shift->tlcol, ul->range_shift->brcol); - else if (ul->range_shift->delta_rows < 0) // sk - fix_marks( (ul->range_shift->brrow - ul->range_shift->tlrow + 1), 0, ul->range_shift->tlrow, maxrow, ul->range_shift->tlcol, ul->range_shift->brcol); + if (deltarows > 0) // sj + fix_marks(sh, -(brrow - tlrow + 1), 0, tlrow, sh->maxrow, tlcol, brcol); + else if (deltarows < 0) // sk + fix_marks(sh, (brrow - tlrow + 1), 0, tlrow, sh->maxrow, tlcol, brcol); // handle row_hidden - fix_row_hidden(ul->range_shift->delta_rows, ul->range_shift->tlrow, maxrow); + fix_row_hidden(sh, deltarows, tlrow, sh->maxrow); // fix marks for cols - if (ul->range_shift->delta_cols > 0) // sl - fix_marks(0, -(ul->range_shift->brcol - ul->range_shift->tlcol + 1), ul->range_shift->tlrow, ul->range_shift->brrow, ul->range_shift->tlcol, maxcol); - else if (ul->range_shift->delta_cols < 0) // sh - fix_marks(0, (ul->range_shift->brcol - ul->range_shift->tlcol + 1), ul->range_shift->tlrow, ul->range_shift->brrow, ul->range_shift->tlcol, maxcol); + if (deltacols > 0) // sl + fix_marks(sh, 0, -(brcol - tlcol + 1), tlrow, brrow, tlcol, sh->maxcol); + else if (deltacols < 0) // sh + fix_marks(sh, 0, (brcol - tlcol + 1), tlrow, brrow, tlcol, sh->maxcol); // handle col_hidden - fix_col_hidden(ul->range_shift->delta_cols, ul->range_shift->tlcol, maxcol); + fix_col_hidden(sh, deltacols, tlcol, sh->maxcol); // handle row_frozen - fix_row_frozen(ul->range_shift->delta_rows, ul->range_shift->tlrow, maxrow); + fix_row_frozen(sh, deltarows, tlrow, sh->maxrow); // handle col_frozen - fix_col_frozen(ul->range_shift->delta_cols, ul->range_shift->tlcol, maxcol); + fix_col_frozen(sh, deltacols, tlcol, sh->maxcol); // shift range now - shift_range(- ul->range_shift->delta_rows, - ul->range_shift->delta_cols, - ul->range_shift->tlrow, ul->range_shift->tlcol, ul->range_shift->brrow, ul->range_shift->brcol); + shift_range(sh, - deltarows, - deltacols, tlrow, tlcol, brrow, brcol); // shift col_formats here. - if (ul->range_shift->tlcol >= 0 && ul->range_shift->tlrow == 0 && ul->range_shift->brrow == maxrow) { // && ul->range_shift->delta_cols > 0) { + if (tlcol >= 0 && tlrow == 0 && brrow == sh->maxrows) { + //sh->maxcols -= deltacols; int i; - if (ul->range_shift->delta_cols > 0) - for (i = ul->range_shift->brcol + ul->range_shift->delta_cols; i <= maxcol; i++) { - fwidth[i - ul->range_shift->delta_cols] = fwidth[i]; - precision[i - ul->range_shift->delta_cols] = precision[i]; - realfmt[i - ul->range_shift->delta_cols] = realfmt[i]; + if (deltacols > 0) + for (i = brcol + deltacols; i <= sh->maxcols; i++) { + sh->fwidth[i - deltacols] = sh->fwidth[i]; + sh->precision[i - deltacols] = sh->precision[i]; + sh->realfmt[i - deltacols] = sh->realfmt[i]; } else - for (i = maxcol; i >= ul->range_shift->tlcol - ul->range_shift->delta_cols; i--) { - fwidth[i] = fwidth[i + ul->range_shift->delta_cols]; - precision[i] = precision[i + ul->range_shift->delta_cols]; - realfmt[i] = realfmt[i + ul->range_shift->delta_cols]; + for (i = sh->maxcols; i >= tlcol - deltacols; i--) { + sh->fwidth[i] = sh->fwidth[i + deltacols]; + sh->precision[i] = sh->precision[i + deltacols]; + sh->realfmt[i] = sh->realfmt[i + deltacols]; } } // do the same for rows here. - if (ul->range_shift->tlrow >= 0 && ul->range_shift->tlcol == 0 && ul->range_shift->brcol == maxcol) { // && ul->range_shift->delta_rows > 0) { + if (tlrow >= 0 && tlcol == 0 && brcol == sh->maxcols) { + //sh->maxrows -= deltarows; int i; - if (ul->range_shift->delta_rows > 0) - for (i = ul->range_shift->brrow + ul->range_shift->delta_rows; i <= maxrow; i++) - row_format[i - ul->range_shift->delta_rows] = row_format[i]; + if (deltarows > 0) + for (i = brrow + deltarows; i <= sh->maxrows; i++) + sh->row_format[i - deltarows] = sh->row_format[i]; else - for (i = maxrow; i >= ul->range_shift->tlrow - ul->range_shift->delta_rows; i--) - row_format[i] = row_format[i + ul->range_shift->delta_rows]; + for (i = sh->maxrow; i >= tlrow - deltarows; i--) + sh->row_format[i] = sh->row_format[i + deltarows]; } } @@ -903,12 +978,12 @@ //} // Append 'ent' elements from the removed ones - struct ent * j = ul->removed; + struct ent_ptr * j = ul->removed; while (j != NULL) { struct ent * h; - if ((h = *ATBL(tbl, j->row, j->col))) clearent(h); - struct ent * e_now = lookat(j->row, j->col); - (void) copyent(e_now, j, 0, 0, 0, 0, 0, 0, 0); + if ((h = *ATBL(j->sheet, j->sheet->tbl, j->vp->row, j->vp->col))) clearent(h); + struct ent * e_now = lookat(j->sheet, j->vp->row, j->vp->col); + (void) copyent(e_now, j->sheet, j->vp, 0, 0, 0, 0, 0, 0, 0); j = j->next; } @@ -918,28 +993,28 @@ int * pd = ul->col_hidded; int left = *(pd++); while (left--) { - col_hidden[*(pd++)] = FALSE; + sh->col_hidden[*(pd++)] = FALSE; } } else if (ul->col_showed != NULL) { int * pd = ul->col_showed; int left = *(pd++); while (left--) { - col_hidden[*(pd++)] = TRUE; + sh->col_hidden[*(pd++)] = TRUE; } } else if (ul->row_hidded != NULL) { int * pd = ul->row_hidded; int left = *(pd++); while (left--) { - row_hidden[*(pd++)] = FALSE; + sh->row_hidden[*(pd++)] = FALSE; } } else if (ul->row_showed != NULL) { int * pd = ul->row_showed; int left = *(pd++); while (left--) { - row_hidden[*(pd++)] = TRUE; + sh->row_hidden[*(pd++)] = TRUE; } } @@ -949,28 +1024,28 @@ int * pd = ul->col_unfrozed; int left = *(pd++); while (left--) { - col_frozen[*(pd++)] = TRUE; + sh->col_frozen[*(pd++)] = TRUE; } } - if (ul->col_frozed != NULL) { + if (ul->col_frozed != NULL) { int * pd = ul->col_frozed; int left = *(pd++); while (left--) { - col_frozen[*(pd++)] = FALSE; + sh->col_frozen[*(pd++)] = FALSE; } } if (ul->row_unfrozed != NULL) { int * pd = ul->row_unfrozed; int left = *(pd++); while (left--) { - row_frozen[*(pd++)] = TRUE; + sh->row_frozen[*(pd++)] = TRUE; } } if (ul->row_frozed != NULL) { int * pd = ul->row_frozed; int left = *(pd++); while (left--) { - row_frozen[*(pd++)] = FALSE; + sh->row_frozen[*(pd++)] = FALSE; } } @@ -982,9 +1057,9 @@ for (i=0; i < size; i++) { if (uf->cols[i].type == 'R') { - fwidth[uf->cols[i].col] = uf->cols[i].fwidth; - precision[uf->cols[i].col] = uf->cols[i].precision; - realfmt[uf->cols[i].col] = uf->cols[i].realfmt; + sh->fwidth[uf->cols[i].col] = uf->cols[i].fwidth; + sh->precision[uf->cols[i].col] = uf->cols[i].precision; + sh->realfmt[uf->cols[i].col] = uf->cols[i].realfmt; } } } @@ -997,125 +1072,141 @@ for (i=0; i < size; i++) { if (uf->rows[i].type == 'R') { - row_format[uf->rows[i].row] = uf->rows[i].format; + sh->row_format[uf->rows[i].row] = uf->rows[i].format; } } } // for every ent in added and removed, we reeval expression to update graph - struct ent * ie = ul->added; + struct ent_ptr * ie = ul->added; while (ie != NULL) { struct ent * p; - if ((p = *ATBL(tbl, ie->row, ie->col)) && p->expr) - EvalJustOneVertex(p, 1); + if ((p = *ATBL(ie->sheet, ie->sheet->tbl, ie->vp->row, ie->vp->col)) && p->expr) + EvalJustOneVertex(ie->sheet, p, 1); ie = ie->next; } ie = ul->removed; while (ie != NULL) { struct ent * p; - if ((p = *ATBL(tbl, ie->row, ie->col)) && p->expr) - EvalJustOneVertex(p, 1); + if ((p = *ATBL(ie->sheet, ie->sheet->tbl, ie->vp->row, ie->vp->col)) && p->expr) + EvalJustOneVertex(ie->sheet, p, 1); ie = ie->next; } // Restores cursor position - currow = ori_currow; - curcol = ori_curcol; + sh->currow = ori_currow; + sh->curcol = ori_curcol; // decrease modflg - modflg = mf - 1; + //roman->modflg = mf - 1; + + // restore maxrow, maxcol and modflg status before the action + roman->modflg = undo_item.modflg_bef; + sh->maxrow = undo_item.maxrow_bef; + sh->maxcol = undo_item.maxcol_bef; if (undo_list->p_ant != NULL) undo_list = undo_list->p_ant; sc_info("Change: %d of %d", --undo_list_pos, len_undo_list()); return; } + /** * \brief Do REDO - * * Shift a range of an undo shift range to the original position, if any, * append 'ent' elements from 'added' and remove those from 'removed'. - * * \return none */ - void do_redo() { - //FIXME check why undo_list_pos can sometimes be > len_undo_list(). it shouldnt!! - //if ( undo_list == NULL || undo_list_pos >= len_undo_list() ) { + struct roman * roman = session->cur_doc; + if ( undo_list == NULL || undo_list_pos == len_undo_list() ) { sc_error("No REDO's left."); return; } - int ori_currow = currow; - int ori_curcol = curcol; - int mf = modflg; // save modflag status - - //if (undo_list->p_ant == NULL && undo_list_pos == 0); - //else if (undo_list->p_sig != NULL) undo_list = undo_list->p_sig; if ((undo_list->p_ant != NULL || undo_list_pos != 0) && (undo_list->p_sig != NULL)) undo_list = undo_list->p_sig; struct undo * ul = undo_list; + struct sheet * sh = undo_list->sheet; + + int ori_currow = sh->currow; + int ori_curcol = sh->curcol; + //int mf = roman->modflg; // save modflag status + + // move to the according sheet + roman->cur_sh = sh; // Remove 'ent' elements - struct ent * i = ul->removed; + struct ent_ptr * i = ul->removed; while (i != NULL) { - struct ent * pp = *ATBL(tbl, i->row, i->col); - clearent(pp); - cleanent(pp); + erase_area(i->sheet, i->vp->row, i->vp->col, i->vp->row, i->vp->col, 1, 0); i = i->next; } // Make undo shift, if any if (ul->range_shift != NULL) { + int deltarows = ul->range_shift->delta_rows; + int deltacols = ul->range_shift->delta_cols; + int brrow = ul->range_shift->brrow; + int tlrow = ul->range_shift->tlrow; + int brcol = ul->range_shift->brcol; + int tlcol = ul->range_shift->tlcol; // fix marks for rows - if (ul->range_shift->delta_rows > 0) // sj - fix_marks( (ul->range_shift->brrow - ul->range_shift->tlrow + 1), 0, ul->range_shift->tlrow, maxrow, ul->range_shift->tlcol, ul->range_shift->brcol); - else if (ul->range_shift->delta_rows < 0) // sk - fix_marks(-(ul->range_shift->brrow - ul->range_shift->tlrow + 1), 0, ul->range_shift->tlrow, maxrow, ul->range_shift->tlcol, ul->range_shift->brcol); + if (deltarows > 0) // sj + fix_marks(sh, (brrow - tlrow + 1), 0, tlrow, sh->maxrow, tlcol, brcol); + else if (deltarows < 0) // sk + fix_marks(sh, -(brrow - tlrow + 1), 0, tlrow, sh->maxrow, tlcol, brcol); // handle row_hidden - fix_row_hidden(-ul->range_shift->delta_rows, ul->range_shift->tlrow, maxrow); + fix_row_hidden(sh, -deltarows, tlrow, sh->maxrow); // fix marks for cols - if (ul->range_shift->delta_cols > 0) // sl - fix_marks(0, (ul->range_shift->brcol - ul->range_shift->tlcol + 1), ul->range_shift->tlrow, ul->range_shift->brrow, ul->range_shift->tlcol, maxcol); - else if (ul->range_shift->delta_cols < 0) // sh - fix_marks(0, -(ul->range_shift->brcol - ul->range_shift->tlcol + 1), ul->range_shift->tlrow, ul->range_shift->brrow, ul->range_shift->tlcol, maxcol); + if (deltacols > 0) // sl + fix_marks(sh, 0, (brcol - tlcol + 1), tlrow, brrow, tlcol, sh->maxcol); + else if (deltacols < 0) // sh + fix_marks(sh, 0, -(brcol - tlcol + 1), tlrow, brrow, tlcol, sh->maxcol); // handle col_hidden - fix_col_hidden(-ul->range_shift->delta_cols, ul->range_shift->tlcol, maxcol); + fix_col_hidden(sh, -deltacols, tlcol, sh->maxcol); + + // handle row_frozen + fix_row_frozen(sh, -deltarows, tlrow, sh->maxrow); + + // handle col_frozen + fix_col_frozen(sh, -deltacols, tlcol, sh->maxcol); // shift range now - shift_range(ul->range_shift->delta_rows, ul->range_shift->delta_cols, - ul->range_shift->tlrow, ul->range_shift->tlcol, ul->range_shift->brrow, ul->range_shift->brcol); + shift_range(sh, deltarows, deltacols, tlrow, tlcol, brrow, brcol); // shift col_formats here - if (ul->range_shift->tlcol >= 0 && ul->range_shift->tlrow == 0 && ul->range_shift->brrow == maxrow) { + if (tlcol >= 0 && tlrow == 0 && brrow == sh->maxrow) { + //sh->maxcols += deltacols; int i; - if (ul->range_shift->delta_cols > 0) - for (i = maxcol; i >= ul->range_shift->tlcol + ul->range_shift->delta_cols; i--) { - fwidth[i] = fwidth[i - ul->range_shift->delta_cols]; - precision[i] = precision[i - ul->range_shift->delta_cols]; - realfmt[i] = realfmt[i - ul->range_shift->delta_cols]; + if (deltacols > 0) + for (i = sh->maxcols; i >= tlcol + deltacols; i--) { + sh->fwidth[i] = sh->fwidth[i - deltacols]; + sh->precision[i] = sh->precision[i - deltacols]; + sh->realfmt[i] = sh->realfmt[i - deltacols]; } else - for (i = ul->range_shift->tlcol; i - ul->range_shift->delta_cols <= maxcol; i++) { - fwidth[i] = fwidth[i - ul->range_shift->delta_cols]; - precision[i] = precision[i - ul->range_shift->delta_cols]; - realfmt[i] = realfmt[i - ul->range_shift->delta_cols]; + for (i = tlcol; i - deltacols <= sh->maxcols; i++) { + sh->fwidth[i] = sh->fwidth[i - deltacols]; + sh->precision[i] = sh->precision[i - deltacols]; + sh->realfmt[i] = sh->realfmt[i - deltacols]; } } // do the same for rows here - if (ul->range_shift->tlrow >= 0 && ul->range_shift->tlcol == 0 && ul->range_shift->brcol == maxcol) { + if (tlrow >= 0 && tlcol == 0 && brcol == sh->maxcols) { + //sh->maxrows += deltarows; int i; - if (ul->range_shift->delta_rows > 0) - for (i = maxrow; i >= ul->range_shift->tlrow + ul->range_shift->delta_rows; i--) - row_format[i] = row_format[i - ul->range_shift->delta_rows]; + if (deltarows > 0) + for (i = sh->maxrows; i >= tlrow + deltarows; i--) + sh->row_format[i] = sh->row_format[i - deltarows]; else - for (i = ul->range_shift->tlrow; i - ul->range_shift->delta_rows <= maxrow; i++) - row_format[i] = row_format[i - ul->range_shift->delta_rows]; + for (i = tlrow; i - deltarows <= sh->maxrows; i++) + sh->row_format[i] = sh->row_format[i - deltarows]; } } @@ -1126,12 +1217,12 @@ //} // Append 'ent' elements - struct ent * j = ul->added; + struct ent_ptr * j = ul->added; while (j != NULL) { struct ent * h; - if ((h = *ATBL(tbl, j->row, j->col))) clearent(h); - struct ent * e_now = lookat(j->row, j->col); - (void) copyent(e_now, j, 0, 0, 0, 0, 0, 0, 0); + if ((h = *ATBL(j->sheet, j->sheet->tbl, j->vp->row, j->vp->col))) clearent(h); + struct ent * e_now = lookat(j->sheet, j->vp->row, j->vp->col); + (void) copyent(e_now, j->sheet, j->vp, 0, 0, 0, 0, 0, 0, 0); j = j->next; } @@ -1141,28 +1232,28 @@ int * pd = ul->col_hidded; int left = *(pd++); while (left--) { - col_hidden[*(pd++)] = TRUE; + sh->col_hidden[*(pd++)] = TRUE; } } else if (ul->col_showed != NULL) { int * pd = ul->col_showed; int left = *(pd++); while (left--) { - col_hidden[*(pd++)] = FALSE; + sh->col_hidden[*(pd++)] = FALSE; } } else if (ul->row_hidded != NULL) { int * pd = ul->row_hidded; int left = *(pd++); while (left--) { - row_hidden[*(pd++)] = TRUE; + sh->row_hidden[*(pd++)] = TRUE; } } else if (ul->row_showed != NULL) { int * pd = ul->row_showed; int left = *(pd++); while (left--) { - row_hidden[*(pd++)] = FALSE; + sh->row_hidden[*(pd++)] = FALSE; } } @@ -1172,28 +1263,28 @@ int * pd = ul->col_unfrozed; int left = *(pd++); while (left--) { - col_frozen[*(pd++)] = FALSE; + sh->col_frozen[*(pd++)] = FALSE; } } if (ul->col_frozed != NULL) { int * pd = ul->col_frozed; int left = *(pd++); while (left--) { - col_frozen[*(pd++)] = TRUE; + sh->col_frozen[*(pd++)] = TRUE; } } if (ul->row_unfrozed != NULL) { int * pd = ul->row_unfrozed; int left = *(pd++); while (left--) { - row_frozen[*(pd++)] = FALSE; + sh->row_frozen[*(pd++)] = FALSE; } } if (ul->row_frozed != NULL) { int * pd = ul->row_frozed; int left = *(pd++); while (left--) { - row_frozen[*(pd++)] = TRUE; + sh->row_frozen[*(pd++)] = TRUE; } } @@ -1205,9 +1296,9 @@ for (i=0; i < size; i++) { if (uf->cols[i].type == 'A') { - fwidth[uf->cols[i].col] = uf->cols[i].fwidth; - precision[uf->cols[i].col] = uf->cols[i].precision; - realfmt[uf->cols[i].col] = uf->cols[i].realfmt; + sh->fwidth[uf->cols[i].col] = uf->cols[i].fwidth; + sh->precision[uf->cols[i].col] = uf->cols[i].precision; + sh->realfmt[uf->cols[i].col] = uf->cols[i].realfmt; } } } @@ -1220,36 +1311,40 @@ for (i=0; i < size; i++) { if (uf->rows[i].type == 'A') { - row_format[uf->rows[i].row] = uf->rows[i].format; + sh->row_format[uf->rows[i].row] = uf->rows[i].format; } } } // for every ent in added and removed, we reeval expression to update graph - struct ent * ie = ul->added; + struct ent_ptr * ie = ul->added; while (ie != NULL) { struct ent * p; - if ((p = *ATBL(tbl, ie->row, ie->col)) && p->expr) - EvalJustOneVertex(p, 1); + if ((p = *ATBL(ie->sheet, ie->sheet->tbl, ie->vp->row, ie->vp->col)) && p->expr) + EvalJustOneVertex(ie->sheet, p, 1); ie = ie->next; } ie = ul->removed; while (ie != NULL) { struct ent * p; - if ((p = *ATBL(tbl, ie->row, ie->col)) && p->expr) - EvalJustOneVertex(p, 1); + if ((p = *ATBL(ie->sheet, ie->sheet->tbl, ie->vp->row, ie->vp->col)) && p->expr) + EvalJustOneVertex(ie->sheet, p, 1); ie = ie->next; } // Restores cursor position - currow = ori_currow; - curcol = ori_curcol; + sh->currow = ori_currow; + sh->curcol = ori_curcol; // increase modflg - modflg = mf + 1; + //roman->modflg = mf + 1; - sc_info("Change: %d of %d", ++undo_list_pos, len_undo_list()); + // restore maxrow, maxcol and modflg status before the action + roman->modflg = undo_item.modflg_aft; + sh->maxrow = undo_item.maxrow_aft; + sh->maxcol = undo_item.maxcol_aft; + sc_info("Change: %d of %d", ++undo_list_pos, len_undo_list()); return; } #endif diff -Nru sc-im-0.8.2+ds/src/undo.h sc-im-0.8.3+ds/src/undo.h --- sc-im-0.8.2+ds/src/undo.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/undo.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -49,14 +49,14 @@ struct undo { struct undo * p_ant; - struct ent * added; - struct ent * removed; + struct ent_ptr * added; + struct ent_ptr * removed; + struct allocation_list * allocations; + struct sheet * sheet; // the sheet where the action took place struct undo_range_shift * range_shift; struct undo_cols_format * cols_format; struct undo_rows_format * rows_format; struct undo * p_sig; - struct ent_ptr * allocations; - int alloc_size; int * row_hidded; int * row_showed; int * col_hidded; @@ -65,6 +65,13 @@ int * row_unfrozed; int * col_frozed; int * col_unfrozed; + /* keep modflg, maxrow and maxcol status before and after changes */ + int modflg_bef; + int modflg_aft; + int maxrow_bef; + int maxrow_aft; + int maxcol_bef; + int maxcol_aft; }; struct undo_range_shift { @@ -104,7 +111,7 @@ void create_undo_action(); void end_undo_action(); -void copy_to_undostruct (int ri, int ci, int rf, int cf, char type, short handle_deps, struct ent ** destination); +void copy_to_undostruct (struct sheet * sh, int ri, int ci, int rf, int cf, char type, short handle_deps, struct ent_ptr ** destination); void save_undo_range_shift(int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol); void undo_hide_show(int row, int col, char type, int arg); void undo_freeze_unfreeze(int row, int col, char type, int arg); @@ -121,5 +128,6 @@ int len_undo_list(); void free_undo_node(struct undo * ul); void dismiss_undo_item(struct undo * ul); -void copy_cell_to_undostruct (struct ent * new, struct ent * ori, char type); -void save_pointer_after_calloc(struct ent * e); +void copy_cell_to_undostruct(struct ent_ptr * e_ptr, struct sheet * sh_ori, struct ent * ori, char type); +void save_yl_pointer_after_calloc(struct ent_ptr * e); +int ent_ptr_exists_on_list(struct ent_ptr * list, struct ent_ptr * ep); diff -Nru sc-im-0.8.2+ds/src/utils/extra.c sc-im-0.8.3+ds/src/utils/extra.c --- sc-im-0.8.2+ds/src/utils/extra.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/utils/extra.c 2023-01-16 15:38:03.000000000 +0000 @@ -52,6 +52,7 @@ //#include "../range.h" extern int find_range(char * name, int len, struct ent * lmatch, struct ent * rmatch, struct range ** rng); +extern struct session * session; #define freen(x) nofreeNULL(x) void nofreeNULL(void *x) { @@ -70,11 +71,13 @@ */ char * v_name(int row, int col) { + struct roman * roman = session->cur_doc; + struct sheet * sh = roman->cur_sh; struct ent *v; struct range *r; static char buf[20]; - v = lookat(row, col); + v = lookat(sh, row, col); if ( ! find_range((char *) 0, 0, v, v, &r) ) { return (r->r_name); } else { diff -Nru sc-im-0.8.2+ds/src/utils/string.c sc-im-0.8.3+ds/src/utils/string.c --- sc-im-0.8.2+ds/src/utils/string.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/utils/string.c 2023-01-16 15:38:03.000000000 +0000 @@ -212,7 +212,7 @@ } /** - * \brief Rind string B inside string S + * \brief Find string B inside string S * * \param[in] * \param[in[ b diff -Nru sc-im-0.8.2+ds/src/version.h sc-im-0.8.3+ds/src/version.h --- sc-im-0.8.2+ds/src/version.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/version.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -39,11 +39,11 @@ * \file version.h * \author Andrés Martinelli * \date 2021-05-13 - * \brief Header file containing the SC-IM version number + * \brief Header file containing the sc-im version number */ /* * CODE REVISION NUMBER: + * the definition is on last line of help.c */ - -char * rev = "version 0.8.2"; +extern char * rev; diff -Nru sc-im-0.8.2+ds/src/vmtbl.c sc-im-0.8.3+ds/src/vmtbl.c --- sc-im-0.8.2+ds/src/vmtbl.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/vmtbl.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -55,6 +55,8 @@ #define ATBL_P(tbl, row, col) (*(tbl + row) + (col)) +extern struct session * session; + /* * check to see if *rowp && *colp are currently allocated, if not expand the * current size if we can. @@ -69,34 +71,34 @@ * \return none */ -void checkbounds(int *rowp, int *colp) { +void checkbounds(struct sheet * sh, int * rowp, int * colp) { if (*rowp < 0) *rowp = 0; - else if (*rowp >= maxrows) { - if (*colp >= maxcols) { - if (!growtbl(GROWBOTH, *rowp, *colp)) { - *rowp = maxrows - 1; - *colp = maxcols - 1; + else if (*rowp >= sh->maxrows) { + if (*colp >= sh->maxcols) { + if (!growtbl(sh, GROWBOTH, *rowp, *colp)) { + *rowp = sh->maxrows - 1; + *colp = sh->maxcols - 1; } return; } else { - if (!growtbl(GROWROW, *rowp, 0)) - *rowp = maxrows - 1; + if (!growtbl(sh, GROWROW, *rowp, 0)) + *rowp = sh->maxrows - 1; return; } } if (*colp < 0) *colp = 0; - else if (*colp >= maxcols) { - if (!growtbl(GROWCOL, 0, *colp)) - *colp = maxcols - 1; + else if (*colp >= sh->maxcols) { + if (!growtbl(sh, GROWCOL, 0, *colp)) + *colp = sh->maxcols - 1; } } #endif /* ! PSC */ /* scxrealloc will just scxmalloc if oldptr is == NULL */ #define GROWALLOC(newptr, oldptr, nelem, type, msg) \ - newptr = (type *)scxrealloc((char *)oldptr, \ + newptr = (type *) scxrealloc((char *) oldptr, \ (unsigned)(nelem * sizeof(type))); \ if (newptr == (type *)NULL) { \ sc_error(msg); \ @@ -124,7 +126,7 @@ * \return FALSE if we cannot grow */ -int growtbl(int rowcol, int toprow, int topcol) { +int growtbl(struct sheet * sh, int rowcol, int toprow, int topcol) { int * fwidth2; int * precision2; int * realfmt2; @@ -141,34 +143,34 @@ int newrows; int i; - newrows = maxrows; + newrows = sh->maxrows; #endif /* ! PSC */ - newcols = maxcols; + newcols = sh->maxcols; if (rowcol == GROWNEW) { #ifndef PSC - maxrows = toprow = 0; + sh->maxrows = toprow = 0; /* when we first start up, fill the screen w/ cells */ { int startval; - startval = LINES - RESROW; + startval = SC_DISPLAY_ROWS; newrows = startval > MINROWS ? startval : MINROWS; - startval = ((COLS) - rescol) / DEFWIDTH; + startval = SC_DISPLAY_COLS / DEFWIDTH; newcols = startval > MINCOLS ? startval : MINCOLS; } #else newcols = MINCOLS; #endif /* !PSC */ - maxcols = topcol = 0; + sh->maxcols = topcol = 0; } #ifndef PSC /* set how much to grow */ if ((rowcol == GROWROW) || (rowcol == GROWBOTH)) { - if ((maxcols == MAXROWS) || (toprow >= MAXROWS)) { + if ((sh->maxcols == MAXROWS) || (toprow >= MAXROWS)) { sc_error(nolonger); return (FALSE); } - if (toprow > maxrows) + if (toprow > sh->maxrows) newrows = GROWAMT + toprow; else newrows += GROWAMT; @@ -179,12 +181,12 @@ } #endif /* !PSC */ if ((rowcol == GROWCOL) || (rowcol == GROWBOTH)) { - if ((maxcols == ABSMAXCOLS) || (topcol >= ABSMAXCOLS)) { + if ((sh->maxcols == ABSMAXCOLS) || (topcol >= ABSMAXCOLS)) { sc_error(nowider); return (FALSE); } - if (topcol > maxcols) + if (topcol > sh->maxcols) newcols = GROWAMT + topcol; else newcols += GROWAMT; @@ -198,81 +200,84 @@ struct ent *** lnullit; int lcnt; - GROWALLOC(row_hidden2, row_hidden, newrows, unsigned char, nolonger); - memset(row_hidden + maxrows, 0, (newrows - maxrows) * sizeof(unsigned char)); + GROWALLOC(row_hidden2, sh->row_hidden, newrows, unsigned char, nolonger); + memset(sh->row_hidden + sh->maxrows, 0, (newrows - sh->maxrows) * sizeof(unsigned char)); - GROWALLOC(row_format2, row_format, newrows, unsigned char, nolonger); - memset(row_format + maxrows, 1, (newrows - maxrows) * sizeof(unsigned char)); + GROWALLOC(row_format2, sh->row_format, newrows, unsigned char, nolonger); + memset(sh->row_format + sh->maxrows, 1, (newrows - sh->maxrows) * sizeof(unsigned char)); - GROWALLOC(row_frozen2, row_frozen, newrows, unsigned char, nolonger); - memset(row_frozen + maxrows, 0, (newrows - maxrows) * sizeof(unsigned char)); + GROWALLOC(row_frozen2, sh->row_frozen, newrows, unsigned char, nolonger); + memset(sh->row_frozen + sh->maxrows, 0, (newrows - sh->maxrows) * sizeof(unsigned char)); /* * alloc tbl row pointers, per net.lang.c, calloc does not * necessarily fill in NULL pointers */ - GROWALLOC(tbl2, tbl, newrows, struct ent **, nolonger); - for (lnullit = tbl + maxrows, lcnt = 0; lcnt < newrows - maxrows; lcnt++, lnullit++) + GROWALLOC(tbl2, sh->tbl, newrows, struct ent **, nolonger); + for (lnullit = sh->tbl + sh->maxrows, lcnt = 0; lcnt < newrows - sh->maxrows; lcnt++, lnullit++) *lnullit = (struct ent **)NULL; /* memset(tbl + maxrows, (char *) NULL, (newrows - maxrows) * (sizeof(struct ent **)));*/ } #endif /* !PSC */ if ((rowcol == GROWCOL) || (rowcol == GROWBOTH) || (rowcol == GROWNEW)) { - GROWALLOC(fwidth2, fwidth, newcols, int, nowider); - GROWALLOC(precision2, precision, newcols, int, nowider); - GROWALLOC(realfmt2, realfmt, newcols, int, nowider); + GROWALLOC(fwidth2, sh->fwidth, newcols, int, nowider); + GROWALLOC(precision2, sh->precision, newcols, int, nowider); + GROWALLOC(realfmt2, sh->realfmt, newcols, int, nowider); #ifdef PSC - memset(fwidth + maxcols, 0, (newcols - maxcols) * sizeof(int)); - memset(precision + maxcols, 0, (newcols - maxcols) * sizeof(int)); - memset(realfmt + maxcols, 0, (newcols - maxcols) * sizeof(int)); + memset(sh->fwidth + sh->maxcols, 0, (newcols - sh->maxcols) * sizeof(int)); + memset(sh->precision + sh->maxcols, 0, (newcols - sh->maxcols) * sizeof(int)); + memset(sh->realfmt + sh->maxcols, 0, (newcols - sh->maxcols) * sizeof(int)); } #else - GROWALLOC(col_hidden2, col_hidden, newcols, unsigned char, nowider); - memset(col_hidden + maxcols, 0, (newcols - maxcols) * sizeof(unsigned char)); - for (i = maxcols; i < newcols; i++) { - fwidth[i] = DEFWIDTH; - precision[i] = DEFPREC; - realfmt[i] = DEFREFMT; + GROWALLOC(col_hidden2, sh->col_hidden, newcols, unsigned char, nowider); + memset(sh->col_hidden + sh->maxcols, 0, (newcols - sh->maxcols) * sizeof(unsigned char)); + for (i = sh->maxcols; i < newcols; i++) { + sh->fwidth[i] = DEFWIDTH; + sh->precision[i] = DEFPREC; + sh->realfmt[i] = DEFREFMT; } - GROWALLOC(col_frozen2, col_frozen, newcols, unsigned char, nolonger); - memset(col_frozen + maxcols, 0, (newcols - maxcols) * sizeof(unsigned char)); + GROWALLOC(col_frozen2, sh->col_frozen, newcols, unsigned char, nolonger); + memset(sh->col_frozen + sh->maxcols, 0, (newcols - sh->maxcols) * sizeof(unsigned char)); /* [re]alloc the space for each row */ - for (i = 0; i < maxrows; i++) { - if ((tbl[i] = (struct ent **) scxrealloc((char *)tbl[i], (unsigned) (newcols * sizeof(struct ent **)))) == (struct ent **)0) { + for (i = 0; i < sh->maxrows; i++) { + if ((sh->tbl[i] = (struct ent **) scxrealloc((char *)sh->tbl[i], (unsigned) (newcols * sizeof(struct ent **)))) == (struct ent **)0) { sc_error(nowider); return(FALSE); } - for (nullit = ATBL_P(tbl, i, maxcols), cnt = 0; cnt < newcols - maxcols; cnt++, nullit++) + for (nullit = ATBL_P(sh->tbl, i, sh->maxcols), cnt = 0; cnt < newcols - sh->maxcols; cnt++, nullit++) *nullit = (struct ent *)NULL; - /* memset((char *) ATBL(tbl,i, maxcols), 0, (newcols - maxcols) * sizeof(struct ent **)); */ + /* memset((char *) ATBL(tbl,i, sh->maxcols), 0, (newcols - sh->maxcols) * sizeof(struct ent **)); */ } } else - i = maxrows; + i = sh->maxrows; /* fill in the bottom of the table */ for (; i < newrows; i++) { - if ((tbl[i] = (struct ent **) scxmalloc((unsigned)(newcols * sizeof(struct ent **)))) == (struct ent **) 0) { + if ((sh->tbl[i] = (struct ent **) scxmalloc((unsigned)(newcols * sizeof(struct ent **)))) == (struct ent **) 0) { sc_error(nowider); return(FALSE); } - for (nullit = tbl[i], cnt = 0; cnt < newcols; cnt++, nullit++) + for (nullit = sh->tbl[i], cnt = 0; cnt < newcols; cnt++, nullit++) *nullit = (struct ent *)NULL; - /* memset((char *) tbl[i], 0, newcols * sizeof(struct ent **));*/ + /* memset((char *) sh->tbl[i], 0, newcols * sizeof(struct ent **));*/ } - maxrows = newrows; - - if (maxrows > 1000) rescol = 5; - if (maxrows > 10000) rescol = 6; - if (maxrows > 100000) rescol = 7; - if (maxrows > 1000000) rescol = 8; + sh->maxrows = newrows; #endif /* PSC */ - maxcols = newcols; + sh->rescol = 2; + if (sh->maxrows > 10) sh->rescol = 3; + if (sh->maxrows > 100) sh->rescol = 4; + if (sh->maxrows > 1000) sh->rescol = 5; + if (sh->maxrows > 10000) sh->rescol = 6; + if (sh->maxrows > 100000) sh->rescol = 7; + if (sh->maxrows > 1000000) sh->rescol = 8; + + sh->maxcols = newcols; return (TRUE); } @@ -286,11 +291,13 @@ * \return none */ -struct ent ** ATBL(struct ent ***tbl, int row, int col) { - struct ent **ent=(*(tbl+row)+(col)); +struct ent ** ATBL(struct sheet * sh, struct ent ***tbl, int row, int col) { + struct ent **ent=(*(sh->tbl+row)+(col)); struct ent *v= *ent; - if ((v) && (v->trigger) && ((v->trigger->flag & TRG_READ) == TRG_READ)) - do_trigger(v,TRG_READ); + if ((v) && (v->trigger) && ((v->trigger->flag & TRG_READ) == TRG_READ)) { + //sc_debug("row:%d %d", v->row, v->col); + do_trigger(v,TRG_READ); + } return ent; } diff -Nru sc-im-0.8.2+ds/src/vmtbl.h sc-im-0.8.3+ds/src/vmtbl.h --- sc-im-0.8.2+ds/src/vmtbl.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/vmtbl.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -38,10 +38,11 @@ /** * \file vmtbl.h * \author Andrés Martinelli - * \date 2017-07-18 + * \date 2021-05-20 * \brief Header file for vmtbl.c */ +#include "sheet.h" -void checkbounds(int * rowp, int * colp); -int growtbl(int rowcol, int toprow, int topcol); -struct ent ** ATBL(struct ent ***tbl, int row, int col); +void checkbounds(struct sheet * sh, int * rowp, int * colp); +int growtbl(struct sheet * sh, int rowcol, int toprow, int topcol); +struct ent ** ATBL(struct sheet * sh, struct ent ***tbl, int row, int col); diff -Nru sc-im-0.8.2+ds/src/xls.c sc-im-0.8.3+ds/src/xls.c --- sc-im-0.8.2+ds/src/xls.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/xls.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file TODO - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - */ - -#include -#include -#include -#include -#include "sc.h" -#include "cmds.h" -#include "color.h" -#include "macros.h" -#include "xls.h" -#include "utils/string.h" - -/* - * xls.h is part of libxls. make sure its installed and headers are in path. - * build must be done with '-lxlsreader' - */ -#ifdef XLS -#include -#endif - -/** - * \brief TODO - * - * \details This function loads an excel file into tbl. As SC-IM still - * does not handle multiple sheets, if excel file has multiple sheets, - * only the first one is read. - * - * \return -1 on error - */ - -int open_xls(char * fname, char * encoding) { -#ifdef XLS - - // Set date format reading LOCALE - char fmt[15] = "%d/%m/%Y"; - - #ifdef USELOCALE - #include - #include - char * loc = NULL; - char * f = NULL; - loc = setlocale(LC_TIME, ""); - - if (loc != NULL) { - f = nl_langinfo(D_FMT); - strcpy(fmt, f); - } - #endif - - // Read XLS file - xlsWorkBook * pWB; - xlsWorkSheet * pWS; - WORD r, c; - pWB = xls_open(fname, encoding); - - wchar_t line_interp[FBUFLEN] = L""; - struct ent * n; - - if (pWB == NULL) { - sc_error("Error loading %s", fname); - return -1; - } - - pWS = xls_getWorkSheet(pWB, 0); //only the first sheet - if (pWS == NULL) return -1; - xls_parseWorkSheet(pWS); - - for (r = 0; r <= pWS->rows.lastrow; r++) { // rows - for (c = 0; c <= pWS->rows.lastcol; c++) { // cols - xlsCell * cell = xls_cell(pWS, r, c); - if ((! cell) || (cell->isHidden)) continue; - - // TODO enable rowspan ? - //if (cell->rowspan > 1) continue; - - struct st_xf_data * xf = &pWB->xfs.xf[cell->xf]; - - //sc_debug("%d %d fmt:%d id:%x %d %d", r, c, xf->format, cell->id, cell->d, cell->l); - - // these are dates - if (((xf->format >= 14 && xf->format <= 22) || - (xf->format >= 165 && xf->format <= 180) || - xf->format == 278 || xf->format == 185 || xf->format == 196 || xf->format - == 217 || xf->format == 326 ) - && cell->id != 0x06 - //&& cell->id != 0x27e - && cell->id != 0x0BD - && cell->id != 0x203 ) { - - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15g", coltoa(c), r, (cell->d - 25569) * 86400); - send_to_interp(line_interp); - n = lookat(r, c); - n->format = 0; - char * s = scxmalloc((unsigned)(strlen(fmt) + 2)); - sprintf(s, "%c", 'd'); - strcat(s, "%d/%m/%Y"); - n->format = s; - continue; - - // display the value of the cell (either numeric or string) - } else if (cell->id == 0x27e || cell->id == 0x0BD || cell->id == 0x203) { - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15g", coltoa(c), r, cell->d); - - } else if (cell->id == 0x06) { // formula - if (cell->l == 0) { // its a number - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15g", coltoa(c), r, cell->d); - } else { - if (!strcmp((char *) cell->str, "bool")) { // its boolean, and test cell->d - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, (int) cell->d ? "true" : "false"); - } else if (! strcmp((char *) cell->str, "error")) { // formula is in error - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, "error"); //FIXME - } else { - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, (char *) cell->str); - } - } - - } else if (cell->str != NULL) { - int pad_pos; - if ((pad_pos = str_in_str((char *) cell->str, "\n")) != -1) ((char *) cell->str)[pad_pos] = '\0'; // For spanning - // clean_carrier((char *) cell->str); // For spanning - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, (char *) cell->str); - } else { - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, ""); - } - send_to_interp(line_interp); - } - } - xls_close_WS(pWS); - xls_close_WB(pWB); - auto_justify(0, maxcols, DEFWIDTH); - return 0; -#else - return -1; -#endif -} diff -Nru sc-im-0.8.2+ds/src/xls.h sc-im-0.8.3+ds/src/xls.h --- sc-im-0.8.2+ds/src/xls.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/xls.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file xls.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for xls.c - */ - -int open_xls(char * fname, char * encoding); diff -Nru sc-im-0.8.2+ds/src/xlsx.c sc-im-0.8.3+ds/src/xlsx.c --- sc-im-0.8.2+ds/src/xlsx.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/xlsx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,748 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file xlsx.c - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief TODO Write a tbrief file description. - * - * \details xlsx import requires: - * - libzip-dev - * - libxml2-dev - * - * \details xlsx export requires - * - libxlsxwriter - */ - -#include -#include -#include -#include // for isdigit -#include // for atoi -#include "macros.h" -#include "sc.h" -#include "cmds.h" -#include "tui.h" -#include "conf.h" -#include "lex.h" -#include "utils/string.h" - -#ifdef XLSX -#include -#include -#include -#include "xlsx.h" - -/** - * \brief TODO Document get_xlsx_string() - * - * \details This function takes the DOM of the sharedStrings file - * and based on position, it returns the according string. Note - * that 0 is the first string. - * - * \param[in] doc - * \param[in] pos - * - * \return none - */ - -char * get_xlsx_string(xmlDocPtr doc, int pos) { - xmlNode * cur_node = xmlDocGetRootElement(doc)->xmlChildrenNode; - xmlNode * father; - char * result = NULL; - - while (pos--) cur_node = cur_node->next; - - father = cur_node; - cur_node = father->xmlChildrenNode; - - while (father != NULL) { // traverse children - while (cur_node != NULL) { // traverse relatives - if ( ! xmlStrcmp(cur_node->name, (const xmlChar *) "t") - && cur_node->xmlChildrenNode != NULL - && cur_node->xmlChildrenNode->content != NULL - ) { - result = (char *) cur_node->xmlChildrenNode->content; - //sc_debug("%s %s", cur_node->name, result); - return result; - } - cur_node = cur_node->next; - } - - father = father->xmlChildrenNode; - if (father != NULL) cur_node = father->xmlChildrenNode; - } - - return result; -} - -/* - * this functions takes the DOM of the styles file - * and based on a position, it returns the according numFmtId - * IMPORTANT: note that 0 is the first "xf". - */ -/** - * \brief TODO Document get_xlsx_styles - * - * \details This function takes the DOM of the styles file - * and mased on position, it returns the according numFmtId. - * IMPORTANT: Note that 0 is the first "xf". - * - * \param[in] doc_styles - * \param[in] pos - * - * \return none - */ - -char * get_xlsx_styles(xmlDocPtr doc_styles, int pos) { - // we go forward up to styles data - xmlNode * cur_node = xmlDocGetRootElement(doc_styles)->xmlChildrenNode; - while (cur_node != NULL && !(cur_node->type == XML_ELEMENT_NODE && !strcmp((char *) cur_node->name, "cellXfs"))) - cur_node = cur_node->next; - - cur_node = cur_node->xmlChildrenNode; - // we go forward up to desidered numFmtId - while (pos--) cur_node = cur_node->next; - char * id = (char *) xmlGetProp(cur_node, (xmlChar *) "numFmtId"); - return id; -} - -/** - * \brief TODO Document get_xlsx_number_format_by_id() - * - * \param[in] doc_styles - * \param[in] id - * - * \return none - */ - -char * get_xlsx_number_format_by_id(xmlDocPtr doc_styles, int id) { - if (doc_styles == NULL || !((id >= 165 && id <= 180) || id == 100)) - return NULL; - - // we go forward up to numFmts section - xmlNode * cur_node = xmlDocGetRootElement(doc_styles)->xmlChildrenNode; - while (cur_node != NULL && !(cur_node->type == XML_ELEMENT_NODE && !strcmp((char *) cur_node->name, "numFmts"))) - cur_node = cur_node->next; - - cur_node = cur_node->xmlChildrenNode; - // we go forward up to desidered format - char * idFile = (char *) xmlGetProp(cur_node, (xmlChar *) "numFmtId"); - while (atoi(idFile) != id) { - cur_node = cur_node->next; - free(idFile); - idFile = (char *) xmlGetProp(cur_node, (xmlChar *) "numFmtId"); - } - - if (atoi(idFile) == id) { - free(idFile); - return (char *) xmlGetProp(cur_node, (xmlChar *) "formatCode"); - } else { - free(idFile); - return NULL; - } -} - -/** - * \brief TODO Document get_sheet_data() - * - * \details This function takes the sheetfile DOM and builds the tbl - * spreadsheet (SC-IM format) - * - * \return none - */ - -void get_sheet_data(xmlDocPtr doc, xmlDocPtr doc_strings, xmlDocPtr doc_styles) { - xmlNode * cur_node = xmlDocGetRootElement(doc)->xmlChildrenNode; - xmlNode * child_node = NULL; - wchar_t line_interp[FBUFLEN] = L""; - int r, c; - - // we go forward up to sheet data - while (cur_node != NULL && !(cur_node->type == XML_ELEMENT_NODE && !strcmp((char *) cur_node->name, "sheetData"))) - cur_node = cur_node->next; - - cur_node = cur_node->xmlChildrenNode; // this is sheetdata - while (cur_node != NULL) { - child_node = cur_node->xmlChildrenNode; // this are rows - while (child_node != NULL) { // this are cols - - // We get r y c - char * row = (char *) xmlGetProp(cur_node, (xmlChar *) "r"); - r = atoi(row); - char * col = (char *) xmlGetProp(child_node, (xmlChar *) "r"); - while (isdigit(col[strlen(col)-1])) col[strlen(col)-1]='\0'; - c = atocol(col, strlen(col)); - - char * s = (char *) xmlGetProp(child_node, (xmlChar *) "t"); // type - char * style = NULL; - style = (char *) xmlGetProp(child_node, (xmlChar *) "s"); // style - char * fmtId = style == NULL ? NULL : get_xlsx_styles(doc_styles, atoi(style)); // numfmtId by style number - char * numberFmt = NULL; - char * shared = NULL; - if (fmtId != NULL && atoi(fmtId) != 0) { - numberFmt = get_xlsx_number_format_by_id(doc_styles, atoi(fmtId)); - } - - // string - if ( s != NULL && ! strcmp(s, "s") ) { - char * st = NULL; - char * strvalue = NULL; - if (child_node->xmlChildrenNode != NULL) - strvalue = get_xlsx_string(doc_strings, atoi((char *) child_node-> xmlChildrenNode-> xmlChildrenNode->content)); - if (strvalue != NULL && strvalue[0] != '\0') { - st = str_replace (strvalue, "\"", "''"); - clean_carrier(st); // we handle padding - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, st); - send_to_interp(line_interp); - free(st); - } - - // inlinestring - } else if ( s != NULL && ! strcmp(s, "inlineStr") ) { - char * st = NULL; - char * strvalue = (char *) child_node->xmlChildrenNode->xmlChildrenNode->xmlChildrenNode->content; - if (strvalue != NULL && strvalue[0] != '\0') { - st = str_replace (strvalue, "\"", "''"); - clean_carrier(st); // we handle padding - swprintf(line_interp, FBUFLEN, L"label %s%d=\"%s\"", coltoa(c), r, st); - send_to_interp(line_interp); - free(st); - } - - // numbers (can be dates, results from formulas or simple numbers) - } else { - // date value in v - if (fmtId != NULL && child_node->xmlChildrenNode != NULL && - ! strcmp((char *) child_node->xmlChildrenNode->name, "v") - && ( - (atoi(fmtId) >= 14 && atoi(fmtId) <= 17) || - atoi(fmtId) == 278 || atoi(fmtId) == 185 || - atoi(fmtId) == 196 || atoi(fmtId) == 164 || - atoi(fmtId) == 217 || atoi(fmtId) == 326 || - (((atoi(fmtId) >= 165 && atoi(fmtId) <= 180) || - atoi(fmtId) == 100) && numberFmt != NULL // 100,165-180 are user defined formats!! - && str_in_str(numberFmt, "/") != -1) - )) { - long l = strtol((char *) child_node->xmlChildrenNode->xmlChildrenNode->content, (char **) NULL, 10); - - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15ld", coltoa(c), r, (l - 25568) * 86400 - get_conf_int("tm_gmtoff")); - send_to_interp(line_interp); - struct ent * n = lookat(r, c); - n->format = 0; - char * stringFormat = scxmalloc((unsigned)(strlen("%d/%m/%Y") + 2)); - sprintf(stringFormat, "%c", 'd'); - strcat(stringFormat, "%d/%m/%Y"); - n->format = stringFormat; - - // time value in v - } else if (fmtId != NULL && child_node->xmlChildrenNode != NULL && - ! strcmp((char *) child_node->xmlChildrenNode->name, "v") - && ( - (atoi(fmtId) >= 18 && atoi(fmtId) <= 21) - )) { - double l = atof((char *) child_node->xmlChildrenNode->xmlChildrenNode->content); - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, (l - get_conf_int("tm_gmtoff") * 1.0 / 60 / 60 / 24) * 86400); - send_to_interp(line_interp); - struct ent * n = lookat(r, c); - n->format = 0; - char * stringFormat = scxmalloc((unsigned)(strlen("%H:%M:%S") + 2)); - sprintf(stringFormat, "%c", 'd'); - strcat(stringFormat, "%H:%M:%S"); - n->format = stringFormat; - - // v - straight int value - } else if (//fmtId != NULL && - child_node->xmlChildrenNode != NULL && - ! strcmp((char *) child_node->xmlChildrenNode->name, "v") ){ - double l = atof((char *) child_node->xmlChildrenNode->xmlChildrenNode->content); - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, l); - send_to_interp(line_interp); - - // f - numeric value that is a result from formula - } else if (//fmtId != NULL && - child_node->xmlChildrenNode != NULL && ! strcmp((char *) child_node->xmlChildrenNode->name, "f")) { - - // handle the formula if that is whats desidered!! - if (get_conf_int("xlsx_readformulas") && - // dont handle shared formulas right now - ! (xmlHasProp(child_node->xmlChildrenNode, (xmlChar *) "t") && - ! strcmp((shared = (char *) xmlGetProp(child_node->xmlChildrenNode, (xmlChar *) "t")), "shared")) - ) { - char * formula = (char *) child_node->xmlChildrenNode->xmlChildrenNode->content; - char * strf; - - // we take some excel common function and adds a @ to them - // we replace count sum avg with @count, @sum, @prod, @avg, @min, @max - strf = str_replace (formula, "COUNT","@COUNT"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "SUM","@SUM"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "PRODUCT","@PROD"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "AVERAGE","@AVG"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "MIN","@MIN"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "MAX","@MAX"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "ABS","@ABS"); - strcpy(formula, strf); - free(strf); - strf = str_replace (formula, "STDEV","@STDDEV"); - strcpy(formula, strf); - free(strf); - - // we send the formula to the interpreter and hope to resolve it! - swprintf(line_interp, FBUFLEN, L"let %s%d=%s", coltoa(c), r, formula); - - } else { - double l = atof((char *) child_node->last->xmlChildrenNode->content); - swprintf(line_interp, FBUFLEN, L"let %s%d=%.15f", coltoa(c), r, l); - } - send_to_interp(line_interp); - } - } - - xmlFree(s); - xmlFree(fmtId); - xmlFree(style); - xmlFree(numberFmt); - xmlFree(shared); - - child_node = child_node->next; - xmlFree(col); - xmlFree(row); - } - cur_node = cur_node->next; - } - return; -} - -/** - * \brief TODO Document open_xlsx() - * - * \param[in] fname - * \param[in] encoding - * - * \return none - */ - -int open_xlsx(char * fname, char * encoding) { - struct zip * za; - struct zip_file * zf; - struct zip_stat sb, sb_strings, sb_styles, sh_strings; - char buf[100]; - int err; - int len; - - // open zip file - if ((za = zip_open(fname, 0, &err)) == NULL) { - zip_error_to_str(buf, sizeof(buf), err, errno); - sc_error("can't open zip archive `%s': %s", fname, buf); - return -1; - } - - // open xl/sharedStrings.xml - char * name = "xl/sharedStrings.xml"; - zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); - char * strings = NULL; - if (zf) { - // some files may not have strings - zip_stat(za, name, ZIP_FL_UNCHANGED, &sb_strings); - strings = (char *) malloc(sb_strings.size); - len = zip_fread(zf, strings, sb_strings.size); - if (len < 0) { - sc_error("cannot read file %s.\n", name); - free(strings); - return -1; - } - zip_fclose(zf); - } - - // open xl/styles.xml - name = "xl/styles.xml"; - zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); - if ( ! zf ) { - sc_error("cannot open %s file.", name); - if (strings != NULL) free(strings); - return -1; - } - zip_stat(za, name, ZIP_FL_UNCHANGED, &sb_styles); - char * styles = (char *) malloc(sb_styles.size); - len = zip_fread(zf, styles, sb_styles.size); - if (len < 0) { - sc_error("cannot read file %s.", name); - if (strings != NULL) free(strings); - free(styles); - return -1; - } - zip_fclose(zf); - - - // find specified sheet - if (get_conf_value("sheet") != NULL){ - - //open xml file with sheet names - name = "xl/workbook.xml"; - char namebuf[30]; - int found = 0; - zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); - - if ( zf ) { - zip_stat(za, name, ZIP_FL_UNCHANGED, &sh_strings); - char * wb_strings = (char *) malloc(sh_strings.size); - len = zip_fread(zf, wb_strings, sh_strings.size); - if (len < 0) { - sc_error("cannot read file %s.", name); - free(wb_strings); - return -1; - } - zip_fclose(zf); - - // search workbook xml for sheet with the right name - xmlDoc * sheet_search = xmlReadMemory(wb_strings, sh_strings.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); - xmlNode * cur_node = xmlDocGetRootElement(sheet_search)->xmlChildrenNode; - while (cur_node != NULL && strcmp((char *) cur_node->name,"sheets")) - cur_node = cur_node->next; - cur_node = cur_node->xmlChildrenNode; - - char * sheet_name = NULL; - while (cur_node != NULL && cur_node->next != NULL && sheet_name == NULL) { - sheet_name = (char *) xmlGetProp(cur_node, (xmlChar *) "name"); - if (strcmp(sheet_name, get_conf_value("sheet"))) { - xmlFree(sheet_name); - sheet_name = NULL; - cur_node = cur_node->next; - } - } - if (sheet_name != NULL){ - char * sheet_id = (char *) xmlGetProp(cur_node, (xmlChar *) "sheetId"); - snprintf(namebuf,30,"xl/worksheets/sheet%s.xml", sheet_id); - name = namebuf; - found = 1; - xmlFree(sheet_id); - xmlFree(sheet_name); - } - xmlFreeDoc(sheet_search); - if (wb_strings != NULL) free(wb_strings); - } - - if ( ! found ){ - // use sheet number if sheet name does not match - name = get_conf_value("sheet"); - int i = strlen(name); - while( --i >= 0 && isdigit(name[i]) > 0 ); - name = i < 0 ? "sheet":""; - snprintf(namebuf,30,"xl/worksheets/%s%s.xml",name,get_conf_value("sheet")); - name = namebuf; - } - } else { - // select sheet1 if none specified - name = "xl/worksheets/sheet1.xml"; - } - - //open sheet - zf = zip_fopen(za, name, ZIP_FL_UNCHANGED); - if ( ! zf ) { - sc_error("cannot open %s file.", name); - if (strings != NULL) free(strings); - free(styles); - return -1; - } - zip_stat(za, name, ZIP_FL_UNCHANGED, &sb); - char * sheet = (char *) malloc(sb.size); - len = zip_fread(zf, sheet, sb.size); - if (len < 0) { - sc_error("cannot read file %s.", name); - if (strings != NULL) free(strings); - free(styles); - free(sheet); - return -1; - } - zip_fclose(zf); - - - // XML parse for the sheet file - xmlDoc * doc = NULL; - xmlDoc * doc_strings = NULL; - xmlDoc * doc_styles = NULL; - - // this initialize the library and check potential ABI mismatches - // between the version it was compiled for and the actual shared - // library used. - LIBXML_TEST_VERSION - - // parse the file and get the DOM - doc_strings = xmlReadMemory(strings, sb_strings.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); - doc_styles = xmlReadMemory(styles, sb_styles.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); - doc = xmlReadMemory(sheet, sb.size, "noname.xml", NULL, XML_PARSE_NOBLANKS); - - if (doc == NULL) { - sc_error("error: could not parse file"); - if (strings != NULL) free(strings); - free(styles); - free(sheet); - return -1; - } - - get_sheet_data(doc, doc_strings, doc_styles); - - // free the document - xmlFreeDoc(doc); - xmlFreeDoc(doc_strings); - xmlFreeDoc(doc_styles); - - // Free the global variables that may have been allocated by the parser - xmlCleanupParser(); - - // free both sheet and strings variables - if (strings != NULL) free(strings); - free(styles); - free(sheet); - - // close zip file - if (zip_close(za) == -1) { - sc_error("cannot close zip archive `%s'", fname); - return -1; - } - - auto_justify(0, maxcols, DEFWIDTH); - deleterow(currow, 1); - return 0; -} -#endif - -#ifdef XLSX_EXPORT -#include "xlsxwriter.h" -/** - * \brief TODO Document export_xlsx() - * - * \param[in] filename - * \param[in] r0 - * \param[in] c0 - * \param[in] rn - * \param[in] cn - * - * \return none - */ - -int export_xlsx(char * filename, int r0, int c0, int rn, int cn) { - int row, col; - register struct ent ** pp; - - lxw_workbook * workbook = workbook_new(filename); - lxw_worksheet * worksheet = workbook_add_worksheet(workbook, NULL); - - int bkp_currow = currow; - currow = 0; - insert_row(0); //add a row so that scim formulas apply to excel - - for (row = r0; row <= rn+1; row++) - for (pp = ATBL(tbl, row, col = c0); col <= cn; col++, pp++) - if (*pp) { - // Check format here - lxw_format * format = workbook_add_format(workbook); - - // handle alignment - if ((*pp)->label && (*pp)->flags & is_label) // center align - format_set_align(format, LXW_ALIGN_CENTER); - else if ((*pp)->label && (*pp)->flags & is_leftflush) // left align - format_set_align(format, LXW_ALIGN_LEFT); - else if ((*pp)->label) // right align - format_set_align(format, LXW_ALIGN_RIGHT); - - // handle bold, italic and underline - if ((*pp)->ucolor != NULL && (*pp)->ucolor->bold) - format_set_bold(format); - else if ((*pp)->ucolor != NULL && (*pp)->ucolor->italic) - format_set_italic(format); - else if ((*pp)->ucolor != NULL && (*pp)->ucolor->underline) - format_set_underline(format, LXW_UNDERLINE_SINGLE); - - // handle fg color - if ((*pp)->ucolor != NULL && (*pp)->ucolor->fg) { - int fgcolor; - switch ((*pp)->ucolor->fg) { - case BLACK: - fgcolor = LXW_COLOR_BLACK; - break; - case RED: - fgcolor = LXW_COLOR_RED; - break; - case GREEN: - fgcolor = LXW_COLOR_GREEN; - break; - case YELLOW: - fgcolor = LXW_COLOR_YELLOW; - break; - case BLUE: - fgcolor = LXW_COLOR_BLUE; - break; - case MAGENTA: - fgcolor = LXW_COLOR_MAGENTA; - break; - case CYAN: - fgcolor = LXW_COLOR_CYAN; - break; - case WHITE: - fgcolor = LXW_COLOR_WHITE; - break; - } - format_set_font_color(format, fgcolor); - } - - // handle bg color - if ((*pp)->ucolor != NULL && (*pp)->ucolor->bg) { - int bgcolor; - switch ((*pp)->ucolor->bg) { - case BLACK: - bgcolor = LXW_COLOR_BLACK; - break; - case RED: - bgcolor = LXW_COLOR_RED; - break; - case GREEN: - bgcolor = LXW_COLOR_GREEN; - break; - case YELLOW: - bgcolor = LXW_COLOR_YELLOW; - break; - case BLUE: - bgcolor = LXW_COLOR_BLUE; - break; - case MAGENTA: - bgcolor = LXW_COLOR_MAGENTA; - break; - case CYAN: - bgcolor = LXW_COLOR_CYAN; - break; - case WHITE: - bgcolor = LXW_COLOR_WHITE; - break; - } - format_set_bg_color(format, bgcolor); - } - - // dateformat - if ((*pp) && (*pp)->format && (*pp)->format[0] == 'd') { - char sc_format[BUFFERSIZE]; - char * st = NULL; - strcpy(sc_format, &((*pp)->format[1])); - - st = str_replace(sc_format, "%Y", "yyyy"); - strcpy(sc_format, st); - free(st); - st = str_replace(sc_format, "%y", "yy"); - strcpy(sc_format, st); - free(st); - st = str_replace(sc_format, "%m", "mm"); - strcpy(sc_format, st); - free(st); - st = str_replace(sc_format, "%d", "dd"); - strcpy(sc_format, st); - free(st); - format_set_num_format(format, sc_format); - worksheet_write_number(worksheet, row-1, col, (((*pp)->v + get_conf_int("tm_gmtoff")) / 86400 + 25568) , format); - - // formula - } else if ((*pp) && (*pp)->expr && get_conf_int("xlsx_readformulas")) { - linelim = 0; - editexp((*pp)->row, (*pp)->col); - linelim = -1; - - char * strf; - char formula[BUFFERSIZE]; - strcpy(formula, line); - - strf = str_replace(formula, "@count","count"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@sum","sum"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@prod","product"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@avg","average"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@min","min"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@max","max"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@abs","abs"); - strcpy(formula, strf); - free(strf); - - strf = str_replace(formula, "@stddev","stdev"); - strcpy(formula, strf); - free(strf); - - add_char(formula, '=', 0); - worksheet_write_formula(worksheet, row-1, col, formula, NULL); - - // If a numeric value exists - } else if ( (*pp)->flags & is_valid) { - worksheet_write_number(worksheet, row-1, col, (*pp)->v, format); - - } else if ((*pp)->label) { - worksheet_write_string(worksheet, row-1, col, (*pp)->label, format); - } - /* TODO: handle hidden rows and columns? */ - } - int_deleterow(currow, 1); /* delete the added row */ - currow = bkp_currow; - - return workbook_close(workbook); -} -#endif diff -Nru sc-im-0.8.2+ds/src/xlsx.h sc-im-0.8.3+ds/src/xlsx.h --- sc-im-0.8.2+ds/src/xlsx.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/xlsx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013-2021, Andrés Martinelli * - * All rights reserved. * - * * - * This file is a part of SC-IM * - * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * - * Chuck Martin. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright * - * notice, this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software * - * must display the following acknowledgement: * - * This product includes software developed by Andrés Martinelli * - * . * - * 4. Neither the name of the Andrés Martinelli nor the * - * names of other contributors may be used to endorse or promote products * - * derived from this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY * - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * - * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY * - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - *******************************************************************************/ - -/** - * \file xlsx.h - * \author Andrés Martinelli - * \date 2017-07-18 - * \brief Header file for xlsx.c - */ - -#ifdef XLSX -#include -void get_sheet_data(xmlDocPtr doc, xmlDocPtr doc_strings, xmlDocPtr doc_styles); -char * get_xlsx_string(xmlDocPtr doc, int pos); -char * get_xlsx_styles(xmlDocPtr doc_styles, int pos); -char * get_xlsx_number_format_by_id(xmlDocPtr doc_styles, int id); -#endif -int open_xlsx(char * fname, char * encoding); -#ifdef XLSX_EXPORT -int export_xlsx(char * filename, int r0, int c0, int rn, int cn); -#endif diff -Nru sc-im-0.8.2+ds/src/xmalloc.c sc-im-0.8.3+ds/src/xmalloc.c --- sc-im-0.8.2+ds/src/xmalloc.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/xmalloc.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/xmalloc.h sc-im-0.8.3+ds/src/xmalloc.h --- sc-im-0.8.2+ds/src/xmalloc.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/xmalloc.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * diff -Nru sc-im-0.8.2+ds/src/yank.c sc-im-0.8.3+ds/src/yank.c --- sc-im-0.8.2+ds/src/yank.c 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/yank.c 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -51,33 +51,35 @@ #include "sc.h" #include "stdlib.h" #include "marks.h" -#include "cmds.h" +#include "macros.h" +#include "color.h" +#include "cmds/cmds.h" #include "conf.h" #include "yank.h" -#include "dep_graph.h" +#include "graph.h" #include "xmalloc.h" // for scxfree #ifdef UNDO #include "undo.h" #endif -extern struct ent * forw_row(int arg); -extern struct ent * back_row(int arg); -extern struct ent * forw_col(int arg); -extern struct ent * back_col(int arg); +extern struct ent * forw_row(struct sheet * sh, int arg); +extern struct ent * back_row(struct sheet * sh, int arg); +extern struct ent * forw_col(struct sheet * sh, int arg); +extern struct ent * back_col(struct sheet * sh, int arg); +extern struct session * session; int yank_arg; // number of rows and columns yanked. Used for commands like `4yr` char type_of_yank; // yank type. c=col, r=row, a=range, e=cell, '\0'=no yanking -static struct ent * yanklist; -struct ent * yanklist_tail; // so we can always add ents at the end of the list easily +static struct ent_ptr * yanklist; +struct ent_ptr * yanklist_tail; // so we can always add ents at the end of the list easily unsigned int yanked_cells = 0;// keeping this helps performance + /** - * \brief TODO Document init_yanklist() - * + * \brief init_yanklist() * \return none */ - void init_yanklist() { yanked_cells = 0; type_of_yank = YANK_NULL; @@ -85,48 +87,35 @@ yanklist_tail = NULL; } + /** * \brief Return the yanklist - * - * \return yanklist + * \return struct ent * */ - -struct ent * get_yanklist() { +struct ent_ptr * get_yanklist() { return yanklist; } + /** - * \brief Remove yank 'ent' elements and free corresponding memory - * + * \brief Remove elements from the yanklist and free its memory * \return none */ - void free_yanklist () { if (yanklist == NULL) return; - int c; - // free each ent internally - struct ent * r = yanklist; - struct ent * e; + // free each ent content + struct ent_ptr * r = yanklist; + struct ent_ptr * e; while (r != NULL) { e = r->next; - - if (r->format) scxfree(r->format); - if (r->label) scxfree(r->label); - if (r->expr) efree(r->expr); - if (r->ucolor) free(r->ucolor); - - //free(r); + clearent(r->vp); r = e; } + free(yanklist->vp); // free ents + yanklist->vp = NULL; - for (c = 0; c < COLFORMATS; c++) { - if (colformat[c] != NULL) - scxfree(colformat[c]); - colformat[c] = NULL; - } - - // free yanklist + // free yanklist ent_ptr free(yanklist); yanked_cells = 0; yanklist = NULL; @@ -135,14 +124,12 @@ } /** - * \brief Add an already alloc'ed 'ent' element to the yanklist - * + * \brief Add an already alloc'ed 'ent_ptr' element to the yanklist * yanklist_tail is pointer to the last ent in the list * \param[in] item 'ent' element to add to the yanklist * \return none */ - -void add_ent_to_yanklist(struct ent * item) { +void add_ent_to_yanklist(struct ent_ptr * item) { yanked_cells++; // If yanklist is empty, insert at the beginning @@ -152,142 +139,168 @@ return; } - // If yanklist is NOT empty, insert at the end - // insert at the end + // If yanklist is NOT empty, insert it at the end yanklist_tail->next = item; yanklist_tail = item; return; } + /** - * \brief Yank a range of ents - * + * \brief Yank a range of ents of a given range of a sheet + * \param[in] struct sheet * sh * \param[in] tlrow * \param[in] tlcol * \param[in] brrow * \param[in] brcol - * \param[in] type yank type. c=col, r=row, a=range, e=cell. '\o'=no yanking, + * \param[in] type yank type. c=col, r=row, a=range, e=cell. '\0'=no yanking, * 's' sort. Used for pasting. * \param[in] arg number of rows or columns yanked. Used in commands like * '4yr'. Used for pasting. - * * \return none */ - -void yank_area(int tlrow, int tlcol, int brrow, int brcol, char type, int arg) { +void yank_area(struct sheet * sh, int tlrow, int tlcol, int brrow, int brcol, char type, int arg) { int r,c; type_of_yank = type; yank_arg = arg; free_yanklist(); + int ignore_hidden = get_conf_int("ignore_hidden"); struct ent * e_ori; - // ask for memory to keep struct ent * for the whole range - struct ent * y_cells = (struct ent *) calloc((brrow-tlrow+1)*(brcol-tlcol+1), sizeof(struct ent)); + // ask for memory to keep struct ent_ptr * and struct ent * for the whole range + struct ent_ptr * y_cells = (struct ent_ptr *) calloc((brrow-tlrow+1)*(brcol-tlcol+1), sizeof(struct ent_ptr)); + struct ent * y_cells_vp = (struct ent *) calloc((brrow-tlrow+1)*(brcol-tlcol+1), sizeof(struct ent)); - for (r = tlrow; r <= brrow; r++) + + // work on issue 674 + // if ignore_hidden is set we need to keep the number of hidden rows in case + long hid = 0; + + for (r = tlrow; r <= brrow; r++) { + if (sh->row_hidden[r]) { hid++; continue; } for (c = tlcol; c <= brcol; c++) { - e_ori = *ATBL(tbl, r, c); + e_ori = *ATBL(sh, sh->tbl, r, c); + if (e_ori == NULL) continue; // initialize the 'ent' - cleanent(y_cells); + y_cells->vp = y_cells_vp++; + cleanent(y_cells->vp); // Copy 'e_ori' contents to 'y_cells' ent - (void) copyent(y_cells, e_ori, 0, 0, 0, 0, 0, 0, 0); + y_cells->sheet = sh; + copyent(y_cells->vp, sh, e_ori, 0, 0, 0, 0, 0, 0, 0); // Important: each 'ent' element keeps the corresponding row and col - (y_cells)->row = e_ori->row; - (y_cells)->col = e_ori->col; + (y_cells)->vp->row = e_ori->row; + (y_cells)->vp->col = e_ori->col; + + // work on issue 674 + // if ignore_hidden is set we substract that number to the internal row so all the pasted rows are + // adjacent. this is a special case when we're pulling hidden rows and we want to ignore those hidden ranges + // (example if yanking a result of a filter) + if (ignore_hidden) (y_cells)->vp->row -= hid; add_ent_to_yanklist(y_cells++); } + } // this takes care of a potential memory leak if no ent was added to yanklist // for instance when deleting empty row - if (! yanked_cells) free(y_cells); + if (! yanked_cells) { + free(y_cells); + free(y_cells_vp); + } return; } + /** - * \brief Paste yanked ents + * \brief paste_yanked_ents() * * \details This function is used for pasting ents that were yanked - * with tr, yc, dr, or dc. It is also used for sorting. - * \details If above == 1, paste is done above current row or the - * right of the current column. Enst that were yanked using yy or yanked - * ents of a range, always pasted in currow and curcol positions. - * \details diffr: difference between current rows and the yanked 'ent' - * \details diffc: difference between current columns and the yanked 'ent' - * \details When sorting, rwo and col values can vary from yank to paste + * with yr, yc, dr, or dc. It is also used for sorting. + * If above == 1, paste is done above current row or the + * right of the current column. Ents that were yanked using yy or yanked + * ents of a range, are always pasted over currow and curcol positions + * of the given sheet. + * diffr: difference between current rows and the yanked 'ent' + * diffc: difference between current columns and the yanked 'ent' + * When sorting, rwo and col values can vary from yank to paste * time, so diffr should be zero. - * \details When implementing column sorting, diffc should be zero as well! - * \details type indicates if pasting format only, valuue only for the + * When implementing column sorting, diffc should be zero as well! + * type indicates if pasting format only, valuue only for the * whole content. - * \details yank type: c=col, r=row, a=range, e=cell, '\0'=no yanking. + * yank type: c=col, r=row, a=range, e=cell, '\0'=no yanking. * + * \param[in] struct sheet * sh * \param[in] above * \param[in] type_paste * * \return -1 if locked cells are found * \return 0 otherwise */ - -int paste_yanked_ents(int above, int type_paste) { +int paste_yanked_ents(struct sheet * sh, int above, int type_paste) { + struct roman * roman = session->cur_doc; if (yanklist == NULL) return 0; - struct ent * yl = yanklist; - struct ent * yll = yl; + struct ent_ptr * yl = yanklist; + struct ent_ptr * yll = yl; int diffr = 0, diffc = 0 , ignorelock = 0; extern struct ent_ptr * deps; + //FIXME: + if (yl->sheet == NULL) yl->sheet = roman->cur_sh; + #ifdef UNDO create_undo_action(); #endif - if (type_of_yank == YANK_SORT) { // paste a range that was yanked in the sort function + if (type_of_yank == YANK_SORT) { // paste a range that was yanked in the sort function diffr = 0; - diffc = curcol - yl->col; + diffc = sh->curcol - yl->vp->col; ignorelock = 1; } else if (type_of_yank == YANK_RANGE || type_of_yank == YANK_CELL) { // paste cell or range - diffr = currow - yl->row; - diffc = curcol - yl->col; + diffr = sh->currow - yl->vp->row; + diffc = sh->curcol - yl->vp->col; - } else if (type_of_yank == YANK_ROW) { // paste row + } else if (type_of_yank == YANK_ROW && sh == yl->sheet) { // paste row int c = yank_arg; #ifdef UNDO - copy_to_undostruct(currow + ! above, 0, currow + ! above - 1 + yank_arg, maxcol, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, sh->currow + ! above, 0, sh->currow + ! above - 1 + yank_arg, sh->maxcol, UNDO_DEL, IGNORE_DEPS, NULL); #endif - while (c--) above ? insert_row(0) : insert_row(1); - if (! above) currow = forw_row(1)->row; // paste below - diffr = currow - yl->row; - diffc = yl->col; - fix_marks(yank_arg, 0, currow, maxrow, 0, maxcol); + while (c--) above ? insert_row(sh, 0) : insert_row(sh, 1); + if (! above) sh->currow = forw_row(sh, 1)->row; // paste below + diffr = sh->currow - yl->vp->row; + diffc = yl->vp->col; + fix_marks(sh, yank_arg, 0, sh->currow, sh->maxrow, 0, sh->maxcol); #ifdef UNDO - save_undo_range_shift(yank_arg, 0, currow, 0, currow - 1 + yank_arg, maxcol); + save_undo_range_shift(yank_arg, 0, sh->currow, 0, sh->currow - 1 + yank_arg, sh->maxcol); #endif - } else if (type_of_yank == YANK_COL) { // paste col + } else if (type_of_yank == YANK_COL) { // paste col int c = yank_arg; #ifdef UNDO - copy_to_undostruct(0, curcol + above, maxrow, curcol + above - 1 + yank_arg, UNDO_DEL, IGNORE_DEPS, NULL); + copy_to_undostruct(sh, 0, sh->curcol + above, sh->maxrow, sh->curcol + above - 1 + yank_arg, UNDO_DEL, IGNORE_DEPS, NULL); #endif - while (c--) above ? insert_col(1) : insert_col(0); // insert cols to the right if above or to the left - diffr = yl->row; - diffc = curcol - yl->col; - fix_marks(0, yank_arg, 0, maxrow, curcol, maxcol); + while (c--) above ? insert_col(sh, 1) : insert_col(sh, 0); // insert cols to the right if above or to the left + diffr = yl->vp->row; + diffc = sh->curcol - yl->vp->col; + fix_marks(sh, 0, yank_arg, 0, sh->maxrow, sh->curcol, sh->maxcol); #ifdef UNDO - save_undo_range_shift(0, yank_arg, 0, curcol, maxrow, curcol - 1 + yank_arg); + save_undo_range_shift(0, yank_arg, 0, sh->curcol, sh->maxrow, sh->curcol - 1 + yank_arg); #endif } - // first check if there are any locked cells over destination - // if so, just return + // paste cell or range if (type_of_yank == YANK_RANGE || type_of_yank == YANK_CELL) { + // first check if there are any locked cells over destination + // if so, just return while (yll != NULL) { - int r = yll->row + diffr; - int c = yll->col + diffc; - checkbounds(&r, &c); - if (any_locked_cells(yll->row + diffr, yll->col + diffc, yll->row + diffr, yll->col + diffc)) { + int r = yll->vp->row + diffr; + int c = yll->vp->col + diffc; + checkbounds(sh, &r, &c); + if (any_locked_cells(sh, yll->vp->row + diffr, yll->vp->col + diffc, yll->vp->row + diffr, yll->vp->col + diffc)) { #ifdef UNDO dismiss_undo_item(NULL); #endif @@ -296,38 +309,46 @@ yll = yll->next; } } - + // its really needed to save deps of yanked ents? ents_that_depends_on_list(yl, diffr, diffc); #ifdef UNDO // ask for memory to save the entire yanklist (and its dependencies) in the undo struct - struct ent * y_cells = (struct ent *) calloc(2*(yanked_cells + (deps != NULL ? deps->vf : 0)), sizeof(struct ent)); - save_pointer_after_calloc(y_cells); + // note that the yanked ents could share dependencies. + struct ent_ptr * y_cells = (struct ent_ptr *) calloc(2*(yanked_cells + (deps != NULL ? deps->vf : 0)), sizeof(struct ent_ptr)); + save_yl_pointer_after_calloc(y_cells); + + // save in undo the dependent ents before the paste + copy_to_undostruct(sh, 0, 0, -1, -1, UNDO_DEL, HANDLE_DEPS, &y_cells); #endif + // paste each ent in yank list while (yl != NULL) { + //FIXME: + if (yl->sheet == NULL) yl->sheet = roman->cur_sh; #ifdef UNDO - copy_cell_to_undostruct(y_cells++, lookat(yl->row + diffr, yl->col + diffc), UNDO_DEL); - - // Here pass struct ent ** to copy_to_undostruct - copy_to_undostruct(0, 0, -1, -1, UNDO_DEL, HANDLE_DEPS, &y_cells); + copy_cell_to_undostruct(y_cells++, sh, lookat(sh, yl->vp->row + diffr, yl->vp->col + diffc), UNDO_DEL); #endif // here we delete current content of "destino" ent. if (type_paste == YANK_RANGE || type_paste == YANK_SORT) - erase_area(yl->row + diffr, yl->col + diffc, yl->row + diffr, yl->col + diffc, ignorelock, 0); + erase_area(sh, yl->vp->row + diffr, yl->vp->col + diffc, yl->vp->row + diffr, yl->vp->col + diffc, ignorelock, 0); - struct ent * destino = lookat(yl->row + diffr, yl->col + diffc); + struct ent * destino = lookat(sh, yl->vp->row + diffr, yl->vp->col + diffc); if (type_paste == YANK_RANGE || type_paste == YANK_SORT) { - (void) copyent(destino, yl, 0, 0, 0, 0, 0, 0, 0); + (void) copyent(destino, sh, yl->vp, 0, 0, 0, 0, 0, 0, 0); } else if (type_paste == YANK_FORMAT) { - (void) copyent(destino, yl, 0, 0, 0, 0, 0, 0, 'f'); + (void) copyent(destino, sh, yl->vp, 0, 0, 0, 0, 0, 0, 'f'); } else if (type_paste == YANK_VALUE) { - (void) copyent(destino, yl, 0, 0, 0, 0, 0, 0, 'v'); + (void) copyent(destino, sh, yl->vp, 0, 0, 0, 0, 0, 0, 'v'); + if (yl->sheet == sh && yl->vp->row == destino->row && yl->vp->col == destino->col) { + efree(destino->expr); + destino->expr = NULL; + } } else if (type_paste == YANK_REF) { - (void) copyent(destino, yl, diffr, diffc, 0, 0, maxrows, maxcols, 'c'); + (void) copyent(destino, sh, yl->vp, diffr, diffc, 0, 0, sh->maxrows, sh->maxcols, 'c'); } destino->row += diffr; destino->col += diffc; @@ -335,30 +356,34 @@ /******************** this might be put outside the loop */ // if so, use EvalRange // sync and then eval. - // sync_refs(); + //sync_refs(sh); if (destino->expr) { - syncref(destino->expr); - if (get_conf_int("autocalc")) EvalJustOneVertex(destino, 1); + syncref(sh, destino->expr); + if (get_conf_int("autocalc")) EvalJustOneVertex(sh, destino, 1); //EvalRange(destino->row, destino->col, destino->row, destino->col); } int i; for (i = 0; deps != NULL && i < deps->vf; i++) { - syncref(deps[i].vp->expr); - if (get_conf_int("autocalc")) EvalJustOneVertex(deps[i].vp, 0); + syncref(sh, deps[i].vp->expr); + if (get_conf_int("autocalc") && deps[i].vp->expr) EvalJustOneVertex(sh, deps[i].vp, 0); } /*******************/ - #ifdef UNDO - copy_cell_to_undostruct(y_cells++, lookat(yl->row + diffr, yl->col + diffc), UNDO_ADD); - // store dependencies after the change as well - copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, &y_cells); + copy_cell_to_undostruct(y_cells++, sh, lookat(sh, yl->vp->row + diffr, yl->vp->col + diffc), UNDO_ADD); #endif yl = yl->next; } + +#ifdef UNDO + // save in undo the dependent ents after the paste + copy_to_undostruct(sh, 0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, &y_cells); +#endif + //rebuild_graph(); //if (get_conf_int("autocalc")) EvalAll(); + roman->modflg++; #ifdef UNDO end_undo_action(); diff -Nru sc-im-0.8.2+ds/src/yank.h sc-im-0.8.3+ds/src/yank.h --- sc-im-0.8.2+ds/src/yank.h 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/src/yank.h 2023-01-16 15:38:03.000000000 +0000 @@ -2,10 +2,10 @@ * Copyright (c) 2013-2021, Andrés Martinelli * * All rights reserved. * * * - * This file is a part of SC-IM * + * This file is a part of sc-im * * * - * SC-IM is a spreadsheet program that is based on SC. The original authors * - * of SC are James Gosling and Mark Weiser, and mods were later added by * + * sc-im is a spreadsheet program that is based on sc. The original authors * + * of sc are James Gosling and Mark Weiser, and mods were later added by * * Chuck Martin. * * * * Redistribution and use in source and binary forms, with or without * @@ -55,8 +55,8 @@ #define YANK_REF 'c' void init_yanklist(); -struct ent * get_yanklist(); +struct ent_ptr * get_yanklist(); void free_yanklist (); -void add_ent_to_yanklist(struct ent * item); -void yank_area(int tlrow, int tlcol, int brrow, int brcol, char c, int arg); -int paste_yanked_ents(int above, int type_paste); +void add_ent_to_yanklist(struct ent_ptr * item); +void yank_area(struct sheet * sh, int tlrow, int tlcol, int brrow, int brcol, char type, int arg); +int paste_yanked_ents(struct sheet * sh, int above, int type_paste); diff -Nru sc-im-0.8.2+ds/tests/assert.sh sc-im-0.8.3+ds/tests/assert.sh --- sc-im-0.8.2+ds/tests/assert.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/assert.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,209 @@ +#!/bin/bash +# assert.sh 1.1 - bash unit testing framework +# Copyright (C) 2009-2015 Robert Lehmann +# +# http://github.com/lehmannro/assert.sh +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +export DISCOVERONLY=${DISCOVERONLY:-} +export DEBUG=${DEBUG:-} +export STOP=${STOP:-} +export INVARIANT=${INVARIANT:-} +export CONTINUE=${CONTINUE:-} + +args="$(getopt -n "$0" -l \ + verbose,help,stop,discover,invariant,continue vhxdic $*)" \ +|| exit -1 +for arg in $args; do + case "$arg" in + -h) + echo "$0 [-vxidc]" \ + "[--verbose] [--stop] [--invariant] [--discover] [--continue]" + echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]" + exit 0;; + --help) + cat < [stdin] + (( tests_ran++ )) || : + [[ -z "$DISCOVERONLY" ]] || return + expected=$(echo -ne "${2:-}") + result="$(eval 2>/dev/null $1 <<< ${3:-})" || true + if [[ "$result" == "$expected" ]]; then + [[ -z "$DEBUG" ]] || echo -n . + return + fi + result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")" + [[ -z "$result" ]] && result="nothing" || result="\"$result\"" + [[ -z "$2" ]] && expected="nothing" || expected="\"$2\"" + _assert_fail "expected $expected${_indent}got $result" "$1" "$3" +} + +# Check in file ($1) for a pattern ($2) +# if found, assert if $3 condition is not met +# or if $3 condition is empty +assert_iffound_notcond() { + (( tests_ran++ )) || : + [[ -z "$DISCOVERONLY" ]] || return + file=$1 + pattern=$2 + assert_ne_cond=$3 + + if [[ -z "$assert_ne_cond" ]]; then + grepres="$(grep "$file" -e "$pattern")" || true + else + grepres="$(grep "$file" -e "$pattern" | grep -v "$assert_ne_cond")" || true + fi + + if [[ -z "$grepres" ]]; then + [[ -z "$DEBUG" ]] || echo -n . + return + fi + _assert_fail "$grepres" $file "$1" "$3" +} + +assert_raises() { + # assert_raises [stdin] + (( tests_ran++ )) || : + [[ -z "$DISCOVERONLY" ]] || return + status=0 + (eval $1 <<< ${3:-}) > /dev/null 2>&1 || status=$? + expected=${2:-0} + if [[ "$status" -eq "$expected" ]]; then + [[ -z "$DEBUG" ]] || echo -n . + return + fi + _assert_fail "program terminated with code $status instead of $expected" "$1" "$3" +} + +_assert_fail() { + # _assert_fail + [[ -n "$DEBUG" ]] && echo -n X + report="test #$tests_ran \"$2${3:+ <<< $3}\" failed:${_indent}$1" + if [[ -n "$STOP" ]]; then + [[ -n "$DEBUG" ]] && echo + echo "$report" + exit 1 + fi + tests_errors[$tests_failed]="$report" + (( tests_failed++ )) || : +} + +skip_if() { + # skip_if + (eval $@) > /dev/null 2>&1 && status=0 || status=$? + [[ "$status" -eq 0 ]] || return + skip +} + +skip() { + # skip (no arguments) + shopt -q extdebug && tests_extdebug=0 || tests_extdebug=1 + shopt -q -o errexit && tests_errexit=0 || tests_errexit=1 + # enable extdebug so returning 1 in a DEBUG trap handler skips next command + shopt -s extdebug + # disable errexit (set -e) so we can safely return 1 without causing exit + set +o errexit + tests_trapped=0 + trap _skip DEBUG +} +_skip() { + if [[ $tests_trapped -eq 0 ]]; then + # DEBUG trap for command we want to skip. Do not remove the handler + # yet because *after* the command we need to reset extdebug/errexit (in + # another DEBUG trap.) + tests_trapped=1 + [[ -z "$DEBUG" ]] || echo -n s + return 1 + else + trap - DEBUG + [[ $tests_extdebug -eq 0 ]] || shopt -u extdebug + [[ $tests_errexit -eq 1 ]] || set -o errexit + return 0 + fi +} + + +_assert_reset +: ${tests_suite_status:=0} # remember if any of the tests failed so far +_assert_cleanup() { + local status=$? + # modify exit code if it's not already non-zero + [[ $status -eq 0 && -z $CONTINUE ]] && exit $tests_suite_status +} +trap _assert_cleanup EXIT diff -Nru sc-im-0.8.2+ds/tests/calc1.sc sc-im-0.8.3+ds/tests/calc1.sc --- sc-im-0.8.2+ds/tests/calc1.sc 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/tests/calc1.sc 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -#let A0 = 10 -#let C1 = F5+A0 -#let F1 = 10 -#let F3 = 20 -#let F5 = F1+F3 -#goto A0 - -let A0 = 10 -let C1 = F5+A0 -let F1 = 10 -let F3 = 20 -let F5 = F1+F3 -#goto A0 diff -Nru sc-im-0.8.2+ds/tests/calc2.sc sc-im-0.8.3+ds/tests/calc2.sc --- sc-im-0.8.2+ds/tests/calc2.sc 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/tests/calc2.sc 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -let A1 = 1 -let A2 = 2 -let A0 = @sum(A1:A2) -goto A0 diff -Nru sc-im-0.8.2+ds/tests/calc3.sc sc-im-0.8.3+ds/tests/calc3.sc --- sc-im-0.8.2+ds/tests/calc3.sc 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/tests/calc3.sc 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# This data file was generated by the Spreadsheet Calculator. That is SC-IM, the improved one! -# You almost certainly shouldn't edit it. - -format A 20 3 0 -format B 20 3 1 -format C 20 3 2 -mark a A1 -mark b A1 -mark c A1 -mark d A1 -mark e A1 -mark f A1 -mark g A1 -mark h A1 -mark i A1 -mark j A1 -mark k A1 -mark l A1 -mark m A1 -mark n A1 -mark o A1 -mark p A1 -mark q A1 -mark r A1 -mark s A1 -mark t A1 -mark u A1 -mark v A1 -mark w A1 -mark x A1 -mark y A1 -mark z A1 -rightstring A0 = "fixed-point" -rightstring B0 = "scientific" -rightstring C0 = "engineering" -let A1 = 12300 -let B1 = 12300 -let C1 = 12300 -let A2 = 12300 -let B2 = 12300 -let C2 = 12300 -let A3 = @sum(A1:A2) -let B3 = @sum(B1:B2) -let C3 = @sum(C1:C2) -goto D1 diff -Nru sc-im-0.8.2+ds/tests/gps.sc sc-im-0.8.3+ds/tests/gps.sc --- sc-im-0.8.2+ds/tests/gps.sc 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/tests/gps.sc 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -# This data file was generated by the Spreadsheet Calculator. That is SC-IM, the improved one! -# You almost certainly shouldn't edit it. - -format A 11 2 0 -format B 28 2 0 -format C 21 2 0 -format D 12 2 2 -format F 12 2 2 -mark a B37 G38 -mark b A1 -mark c A1 -mark d A1 -mark e A1 -mark f A1 -mark g A1 -mark h A1 -mark i A1 -mark j A1 -mark k A1 -mark l A1 -mark m A1 -mark n A1 -mark o A1 -mark p A1 -mark q A1 -mark r A1 -mark s A6 G6 -mark t A1 -mark u A1 -mark v A1 -mark w A1 -mark x D4 -mark y A1 -mark z A1 -leftstring A0 = "Constants" -leftstring B1 = "Speed of light" -label C1 = "c" -let D1 = F1/1000 -label E1 = "km/s" -let F1 = 299492458 -label G1 = "m/s" -leftstring B2 = "Gravitational const" -label C2 = "G" -let F2 = 6.67408e-11 -label G2 = "N/kg" -leftstring B3 = "Mass of Earth" -label C3 = "m_E" -let F3 = 5.972e+24 -label G3 = "kg" -leftstring B4 = "Mean radius of Earth" -label C4 = "r_e" -let D4 = 6400 -label E4 = "km" -let F4 = D4*1000 -label G4 = "m" -leftstring A6 = "GPS signal" -leftstring B6 = "https://en.wikipedia.org/wiki/GPS_signals" -leftstring B7 = "L-band base (IF)" -label C7 = "ω_i" -let D7 = 10.23 -label E7 = "MHz" -let F7 = D7*1000000 -label G7 = "Hz" -leftstring B8 = "L1 carrier" -label C8 = "ω_1" -let D8 = D7*154 -label E8 = "MHz" -let F8 = D8*1000000 -label G8 = "Hz" -leftstring B9 = "L2 carrier" -label C9 = "ω_2" -let D9 = D7*120 -label E9 = "MHz" -let F9 = D9*1000000 -label G9 = "Hz" -leftstring B10 = "L3 carrier" -label C10 = "ω_3" -let D10 = D7*135 -label E10 = "MHz" -let F10 = D10*1000000 -label G10 = "Hz" -leftstring B11 = "L4 carrier" -label C11 = "ω_4" -let D11 = D7*1214/9 -label E11 = "MHz" -let F11 = D11*1000000 -label G11 = "Hz" -leftstring B12 = "L5 carrier" -label C12 = "ω_5" -let D12 = D7*115 -label E12 = "MHz" -let F12 = D12*1000000 -label G12 = "Hz" -leftstring B14 = "IF period" -label C14 = "τ_i" -let D14 = F14*1000000000 -label E14 = "ns" -let F14 = 1/F7 -label G14 = "Hz" -leftstring A16 = "Orbit" -leftstring B16 = "https://en.wikipedia.org/wiki/Global_Positioning_System" -leftstring B17 = "Min range" -label C17 = "r_min" -let D17 = 20180 -label E17 = "km" -let F17 = D17*1000 -label G17 = "m" -leftstring B18 = "Orbit radius" -label C18 = "r_o = r_min+r_e" -let D18 = F18/1000 -label E18 = "km" -let F18 = F17+F$4 -label G18 = "m" -leftstring B19 = "Max range (at horizon)" -label C19 = "r_max=√(r_o^2-r_e^2)" -let D19 = F19/1000 -label E19 = "km" -let F19 = @sqrt(F18*F18-F$4*F$4) -label G19 = "m" -leftstring B21 = "Light time min" -label C21 = "r_min/c" -let D21 = F21*1000 -label E21 = "ms" -let F21 = F17/$F$1 -label G21 = "s" -leftstring B22 = "Light time" -label C22 = "r_max/c" -let D22 = F22*1000 -label E22 = "ms" -let F22 = F19/$F$1 -label G22 = "s" -leftstring B24 = "Orbital speed" -label C24 = "v_o = √(G.m_E/r_o)" -let D24 = F24*3600/1000 -label E24 = "km/h" -let F24 = @sqrt(F$2*F$3/F18) -label G24 = "m/s" -leftstring B26 = "sin∠(horizon,Earth centre)" -label C26 = "sin θ = r_e/r_o" -let F26 = F$4/F18 -leftstring B27 = "Range rate at horizon" -label C27 = "v_h=v_o sin θ" -let D27 = F27*3600/1000 -label E27 = "km/h" -let F27 = F24*F26 -label G27 = "m/s" -leftstring A29 = "Max Doppler" -leftstring B30 = "Fractional Doppler" -label C30 = "z = v_h/c" -let F30 = F27/F$1 -leftstring B31 = "L1 shift" -label C31 = "z.ω_1" -let D31 = D8*F$30*1000 -label E31 = "kHz" -let F31 = D31*1000 -label G31 = "Hz" -leftstring B32 = "L2 shift" -label C32 = "z.ω_2" -let D32 = D9*F$30*1000 -label E32 = "kHz" -let F32 = D32*1000 -label G32 = "Hz" -cellcolor A0 "fg=BLACK bg=CYAN" -cellcolor A6 "fg=BLACK bg=CYAN" -cellcolor B6:G6 "fg=BLACK bg=YELLOW" -cellcolor A16 "fg=BLACK bg=CYAN" -cellcolor B16:G16 "fg=BLACK bg=YELLOW" -cellcolor A29 "fg=BLACK bg=CYAN" -goto A35 diff -Nru sc-im-0.8.2+ds/tests/run_all_tests.sh sc-im-0.8.3+ds/tests/run_all_tests.sh --- sc-im-0.8.2+ds/tests/run_all_tests.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/run_all_tests.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,6 @@ +#!/bin/bash +for i in test*.sh +do + echo "Testing $i" + /bin/bash $i keep-vallog +done diff -Nru sc-im-0.8.2+ds/tests/test1.sc sc-im-0.8.3+ds/tests/test1.sc --- sc-im-0.8.2+ds/tests/test1.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test1.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,13 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = B0+2 +let B0 = 23 +newsheet "Sheet2" +movetosheet "Sheet2" +let A0 = 56 +movetosheet "Sheet1" +let C2 = {"Sheet2"}!A0 + A0 +goto B0 diff -Nru sc-im-0.8.2+ds/tests/test1.sh sc-im-0.8.3+ds/tests/test1.sh --- sc-im-0.8.2+ds/tests/test1.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test1.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test1 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh +assert "echo GETNUM C2 | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp'" "81" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" "!" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test2.sc sc-im-0.8.3+ds/tests/test2.sc --- sc-im-0.8.2+ds/tests/test2.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test2.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,15 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = B0+2 +let B0 = 23 +newsheet "Sheet2" +movetosheet "Sheet2" +let A0 = 56 +movetosheet "Sheet1" +let C2 = {"Sheet2"}!A0 + A0 +undo +redo +goto B0 diff -Nru sc-im-0.8.2+ds/tests/test2.sh sc-im-0.8.3+ds/tests/test2.sh --- sc-im-0.8.2+ds/tests/test2.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test2.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test2 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh +assert "echo GETNUM C2 | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|left'" "81" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test3.sc sc-im-0.8.3+ds/tests/test3.sc --- sc-im-0.8.2+ds/tests/test3.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test3.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,15 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +newsheet "Sheet1" +newsheet "dos" +movetosheet "dos" +let A0 = 1.14 +let A1 = 1.16 +let A2 = @sum(A0:A1) +let B3 = {"Sheet1"}!A2 +goto B3 +movetosheet "Sheet1" +let A0 = {"dos"}!B3+{"dos"}!A2 +let A2 = 1 +goto A2 diff -Nru sc-im-0.8.2+ds/tests/test3.sh sc-im-0.8.3+ds/tests/test3.sh --- sc-im-0.8.2+ds/tests/test3.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test3.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test3 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh +assert "echo GETNUM A0 | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|left'" "3.3" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test4.sc sc-im-0.8.3+ds/tests/test4.sc --- sc-im-0.8.2+ds/tests/test4.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test4.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,14 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +newsheet "Sheet1" +newsheet "dos" +movetosheet "dos" +let A0 = 1.14 +let A1 = 1.16 +let A2 = @sum(A0:A1) +let B3 = {"Sheet1"}!A2 +goto B3 +movetosheet "Sheet1" +let A0 = {"dos"}!B3+{"dos"}!A2 +goto A2 diff -Nru sc-im-0.8.2+ds/tests/test4.sh sc-im-0.8.3+ds/tests/test4.sh --- sc-im-0.8.2+ds/tests/test4.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test4.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,28 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test4 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh + +CMD='LET A2 = 1\nUNDO\nGETNUM A0\nGETNUM {"dos"}!B3' +assert "echo -e '${CMD}' | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|left\|Change'" "2.3\n0" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test5.sc sc-im-0.8.3+ds/tests/test5.sc --- sc-im-0.8.2+ds/tests/test5.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test5.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,155 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = 1 +let B0 = A0+1 +let C0 = B0+1 +let D0 = C0+1 +let E0 = D0+1 +let F0 = E0+1 +let G0 = F0+1 +let H0 = G0+1 +let A1 = A0+1 +let B1 = A1+B0 +let C1 = C0+B1 +let D1 = D0+C1 +let E1 = E0+D1 +let F1 = F0+E1 +let G1 = G0+F1 +let A2 = A1+1 +let B2 = A2+B1 +let C2 = C1+B2 +let D2 = D1+C2 +let E2 = E1+D2 +let F2 = F1+E2 +let G2 = G1+F2 +let A3 = A2+1 +let B3 = A3+B2 +let C3 = C2+B3 +let D3 = D2+C3 +let E3 = E2+D3 +let F3 = F2+E3 +let G3 = G2+F3 +let A4 = A3+1 +let B4 = A4+B3 +let C4 = C3+B4 +let D4 = D3+C4 +let E4 = E3+D4 +let F4 = F3+E4 +let G4 = G3+F4 +let A5 = A4+1 +let B5 = A5+B4 +let C5 = C4+B5 +let D5 = D4+C5 +let E5 = E4+D5 +let F5 = F4+E5 +let G5 = G4+F5 +let A6 = A5+1 +let B6 = A6+B5 +let C6 = C5+B6 +let D6 = D5+C6 +let E6 = E5+D6 +let F6 = F5+E6 +let G6 = G5+F6 +let A7 = A6+1 +let B7 = A7+B6 +let C7 = C6+B7 +let D7 = D6+C7 +let E7 = E6+D7 +let F7 = F6+E7 +let G7 = G6+F7 +let A8 = A7+1 +let B8 = A8+B7 +let C8 = C7+B8 +let D8 = D7+C8 +let E8 = E7+D8 +let F8 = F7+E8 +let G8 = G7+F8 +let A9 = A8+1 +let B9 = A9+B8 +let C9 = C8+B9 +let D9 = D8+C9 +let E9 = E8+D9 +let F9 = F8+E9 +let G9 = G8+F9 +let A10 = A9+1 +let B10 = A10+B9 +let C10 = C9+B10 +let D10 = D9+C10 +let E10 = E9+D10 +let F10 = F9+E10 +let G10 = G9+F10 +let A11 = A10+1 +let B11 = A11+B10 +let C11 = C10+B11 +let D11 = D10+C11 +let E11 = E10+D11 +let F11 = F10+E11 +let G11 = G10+F11 +let A12 = A11+1 +let B12 = A12+B11 +let C12 = C11+B12 +let D12 = D11+C12 +let E12 = E11+D12 +let F12 = F11+E12 +let G12 = G11+F12 +let A13 = A12+1 +let B13 = A13+B12 +let C13 = C12+B13 +let D13 = D12+C13 +let E13 = E12+D13 +let F13 = F12+E13 +let G13 = G12+F13 +let A14 = A13+1 +let B14 = A14+B13 +let C14 = C13+B14 +let D14 = D13+C14 +let E14 = E13+D14 +let F14 = F13+E14 +let G14 = G13+F14 +let A15 = A14+1 +let B15 = A15+B14 +let C15 = C14+B15 +let D15 = D14+C15 +let E15 = E14+D15 +let F15 = F14+E15 +let G15 = G14+F15 +let A16 = A15+1 +let B16 = A16+B15 +let C16 = C15+B16 +let D16 = D15+C16 +let E16 = E15+D16 +let F16 = F15+E16 +let G16 = G15+F16 +let A17 = A16+1 +let B17 = A17+B16 +let C17 = C16+B17 +let D17 = D16+C17 +let E17 = E16+D17 +let F17 = F16+E17 +let G17 = G16+F17 +let A18 = A17+1 +let B18 = A18+B17 +let C18 = C17+B18 +let D18 = D17+C18 +let E18 = E17+D18 +let F18 = F17+E18 +let G18 = G17+F18 +let A19 = A18+1 +let B19 = A19+B18 +let C19 = C18+B19 +let D19 = D18+C19 +let E19 = E18+D19 +let F19 = F18+E19 +let G19 = G18+F19 +let A20 = A19+1 +let B20 = A20+B19 +let C20 = C19+B20 +let D20 = D19+C20 +let E20 = E19+D20 +let F20 = F19+E20 +let G20 = G19+F20 +goto H1 diff -Nru sc-im-0.8.2+ds/tests/test5.sh sc-im-0.8.3+ds/tests/test5.sh --- sc-im-0.8.2+ds/tests/test5.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test5.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,28 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test5 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh + +CMD='YANKAREA {"Sheet1"}!G1:G20 "a"\nPASTEYANKED {"Sheet1"} 0 "c"\nGETNUM H20' +assert "echo -e '${CMD}' | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp'" "3404115" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test6.sc sc-im-0.8.3+ds/tests/test6.sc --- sc-im-0.8.2+ds/tests/test6.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test6.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,14 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = 1 +let B0 = A0+1 +let C0 = 12 +let A1 = A0+1 +let B1 = A1+B0 +let A2 = A1+1 +let B2 = A2+B1 +goto C1 diff -Nru sc-im-0.8.2+ds/tests/test6.sh sc-im-0.8.3+ds/tests/test6.sh --- sc-im-0.8.2+ds/tests/test6.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test6.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,28 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test6 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh + +CMD='YANKAREA {"Sheet1"}!B1:B2 "a"\nPASTEYANKED {"Sheet1"} 0 "c"\nGETNUM C1\nUNDO\nPASTEYANKED {"Sheet1"} 0 "c"\nGETNUM C2' +assert "echo -e '${CMD}' | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|Change'" "16\n23" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test7.sc sc-im-0.8.3+ds/tests/test7.sc --- sc-im-0.8.2+ds/tests/test7.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test7.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,155 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = 1 +let B0 = A0+1 +let C0 = B0+1 +let D0 = C0+1 +let E0 = D0+1 +let F0 = E0+1 +let G0 = F0+1 +let H0 = G0+1 +let A1 = A0+1 +let B1 = A1+B0 +let C1 = C0+B1 +let D1 = D0+C1 +let E1 = E0+D1 +let F1 = F0+E1 +let G1 = G0+F1 +let A2 = A1+1 +let B2 = A2+B1 +let C2 = C1+B2 +let D2 = D1+C2 +let E2 = E1+D2 +let F2 = F1+E2 +let G2 = G1+F2 +let A3 = A2+1 +let B3 = A3+B2 +let C3 = C2+B3 +let D3 = D2+C3 +let E3 = E2+D3 +let F3 = F2+E3 +let G3 = G2+F3 +let A4 = A3+1 +let B4 = A4+B3 +let C4 = C3+B4 +let D4 = D3+C4 +let E4 = E3+D4 +let F4 = F3+E4 +let G4 = G3+F4 +let A5 = A4+1 +let B5 = A5+B4 +let C5 = C4+B5 +let D5 = D4+C5 +let E5 = E4+D5 +let F5 = F4+E5 +let G5 = G4+F5 +let A6 = A5+1 +let B6 = A6+B5 +let C6 = C5+B6 +let D6 = D5+C6 +let E6 = E5+D6 +let F6 = F5+E6 +let G6 = G5+F6 +let A7 = A6+1 +let B7 = A7+B6 +let C7 = C6+B7 +let D7 = D6+C7 +let E7 = E6+D7 +let F7 = F6+E7 +let G7 = G6+F7 +let A8 = A7+1 +let B8 = A8+B7 +let C8 = C7+B8 +let D8 = D7+C8 +let E8 = E7+D8 +let F8 = F7+E8 +let G8 = G7+F8 +let A9 = A8+1 +let B9 = A9+B8 +let C9 = C8+B9 +let D9 = D8+C9 +let E9 = E8+D9 +let F9 = F8+E9 +let G9 = G8+F9 +let A10 = A9+1 +let B10 = A10+B9 +let C10 = C9+B10 +let D10 = D9+C10 +let E10 = E9+D10 +let F10 = F9+E10 +let G10 = G9+F10 +let A11 = A10+1 +let B11 = A11+B10 +let C11 = C10+B11 +let D11 = D10+C11 +let E11 = E10+D11 +let F11 = F10+E11 +let G11 = G10+F11 +let A12 = A11+1 +let B12 = A12+B11 +let C12 = C11+B12 +let D12 = D11+C12 +let E12 = E11+D12 +let F12 = F11+E12 +let G12 = G11+F12 +let A13 = A12+1 +let B13 = A13+B12 +let C13 = C12+B13 +let D13 = D12+C13 +let E13 = E12+D13 +let F13 = F12+E13 +let G13 = G12+F13 +let A14 = A13+1 +let B14 = A14+B13 +let C14 = C13+B14 +let D14 = D13+C14 +let E14 = E13+D14 +let F14 = F13+E14 +let G14 = G13+F14 +let A15 = A14+1 +let B15 = A15+B14 +let C15 = C14+B15 +let D15 = D14+C15 +let E15 = E14+D15 +let F15 = F14+E15 +let G15 = G14+F15 +let A16 = A15+1 +let B16 = A16+B15 +let C16 = C15+B16 +let D16 = D15+C16 +let E16 = E15+D16 +let F16 = F15+E16 +let G16 = G15+F16 +let A17 = A16+1 +let B17 = A17+B16 +let C17 = C16+B17 +let D17 = D16+C17 +let E17 = E16+D17 +let F17 = F16+E17 +let G17 = G16+F17 +let A18 = A17+1 +let B18 = A18+B17 +let C18 = C17+B18 +let D18 = D17+C18 +let E18 = E17+D18 +let F18 = F17+E18 +let G18 = G17+F18 +let A19 = A18+1 +let B19 = A19+B18 +let C19 = C18+B19 +let D19 = D18+C19 +let E19 = E18+D19 +let F19 = F18+E19 +let G19 = G18+F19 +let A20 = A19+1 +let B20 = A20+B19 +let C20 = C19+B20 +let D20 = D19+C20 +let E20 = E19+D20 +let F20 = F19+E20 +let G20 = G19+F20 +goto A7 diff -Nru sc-im-0.8.2+ds/tests/test7.sh sc-im-0.8.3+ds/tests/test7.sh --- sc-im-0.8.2+ds/tests/test7.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test7.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test7 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh + +CMD='LET A7=90\nGETNUM A20\nGETNUM G20\nUNDO\nREDO\nGETNUM A20\nGETNUM G20' + +assert "echo -e '${CMD}' | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|Change'" "103\n954958\n103\n954958" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test8.sc sc-im-0.8.3+ds/tests/test8.sc --- sc-im-0.8.2+ds/tests/test8.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test8.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,74 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = 1 +let B0 = 2 +let C0 = 3 +let D0 = 4 +let E0 = 5 +let F0 = 6 +let G0 = 7 +let H0 = 8 +let I0 = 9 +let J0 = 10 +let K0 = 11 +let L0 = 12 +let M0 = 13 +let N0 = 14 +let O0 = 15 +let P0 = 16 +let Q0 = 17 +let R0 = 18 +let S0 = 29 +let T0 = 30 +let U0 = 31 +let V0 = 32 +let W0 = 33 +let A1 = 2 +let A2 = 3 +let A3 = 4 +let A4 = 5 +let A5 = 6 +let A6 = 7 +let A7 = 8 +let A8 = 9 +let A9 = 10 +let A10 = 11 +let A11 = 12 +let A12 = 13 +let A13 = 14 +let A14 = 15 +let A15 = 16 +let A16 = 17 +let A17 = 18 +let A18 = 19 +let A19 = 20 +let A20 = 21 +let A21 = 22 +let A22 = 23 +let A23 = 24 +let A24 = 25 +let A25 = 26 +let A26 = 27 +let A27 = 28 +let A28 = 29 +let A29 = 30 +let A30 = 31 +let A31 = 32 +let A32 = 33 +let A33 = 34 +let A34 = 35 +let A35 = 36 +let A36 = 37 +let A37 = 38 +let A38 = 39 +let A39 = 40 +let A40 = 41 +let A41 = 42 +let A42 = 43 +let A43 = 44 +let A44 = 45 +goto A1 diff -Nru sc-im-0.8.2+ds/tests/test8.sh sc-im-0.8.3+ds/tests/test8.sh --- sc-im-0.8.2+ds/tests/test8.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test8.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,28 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test8 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh + +CMD='DELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nDELETECOL B\nGETNUM B0\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nDELETEROW 2\nUNDO\nUNDO\nGETNUM A2' +assert "echo -e '${CMD}' | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|Change'" "14\n13" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/test9.sc sc-im-0.8.3+ds/tests/test9.sc --- sc-im-0.8.2+ds/tests/test9.sc 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test9.sc 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,74 @@ +# This data file was generated by the Spreadsheet Calculator Improvised (sc-im) +# You almost certainly shouldn't edit it. + +set external_functions +newsheet "Sheet1" +movetosheet "Sheet1" +let A0 = 1 +let B0 = 2 +let C0 = 3 +let D0 = 4 +let E0 = 5 +let F0 = 6 +let G0 = 7 +let H0 = 8 +let I0 = 9 +let J0 = 10 +let K0 = 11 +let L0 = 12 +let M0 = 13 +let N0 = 14 +let O0 = 15 +let P0 = 16 +let Q0 = 17 +let R0 = 18 +let S0 = 29 +let T0 = 30 +let U0 = 31 +let V0 = 32 +let W0 = 33 +let A1 = 2 +let A2 = 3 +let A3 = 4 +let A4 = 5 +let A5 = 6 +let A6 = 7 +let A7 = 8 +let A8 = 9 +let A9 = 10 +let A10 = 11 +let A11 = 12 +let A12 = 13 +let A13 = 14 +let A14 = 15 +let A15 = 16 +let A16 = 17 +let A17 = 18 +let A18 = 19 +let A19 = 20 +let A20 = 21 +let A21 = 22 +let A22 = 23 +let A23 = 24 +let A24 = 25 +let A25 = 26 +let A26 = 27 +let A27 = 28 +let A28 = 29 +let A29 = 30 +let A30 = 31 +let A31 = 32 +let A32 = 33 +let A33 = 34 +let A34 = 35 +let A35 = 36 +let A36 = 37 +let A37 = 38 +let A38 = 39 +let A39 = 40 +let A40 = 41 +let A41 = 42 +let A42 = 43 +let A43 = 44 +let A44 = 45 +goto A1 diff -Nru sc-im-0.8.2+ds/tests/test9.sh sc-im-0.8.3+ds/tests/test9.sh --- sc-im-0.8.2+ds/tests/test9.sh 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/test9.sh 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,28 @@ +#!/bin/bash +## SEE https://github.com/lehmannro/assert.sh for usage + +#Exit immediately if a command exits with a non-zero status. +set -e + +NAME=test9 + +VALGRIND_CMD='valgrind -v --log-file=${NAME}_vallog --tool=memcheck --track-origins=yes --leak-check=full --show-leak-kinds=all --show-reachable=no' +. assert.sh + +CMD='GOTO ZZ1\nLET ZZ1 = 23\nDELETECOL ZZ\nUNDO\nDELETECOL ZZ\nUNDO\nGETNUM ZZ1' +assert "echo -e '${CMD}' | $VALGRIND_CMD ../src/sc-im ${NAME}.sc --nocurses --nodebug --quit_afterload 2>&1 |grep -v '^$\|Interp\|Change\|wider'" "23" + +#we check valgrind log +assert_iffound_notcond ${NAME}_vallog "definitely lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "indirectly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "possibly lost.*bytes" "0 bytes" +assert_iffound_notcond ${NAME}_vallog "Uninitialised value was created by a heap allocation" +assert_iffound_notcond ${NAME}_vallog "Conditional jump or move depends on uninitialised value" +assert_iffound_notcond ${NAME}_vallog "Invalid read of size" +assert_iffound_notcond ${NAME}_vallog "Invalid write of size" +assert_iffound_notcond ${NAME}_vallog "Invalid free() / delete" +if [ "$1" != "keep-vallog" ];then + rm ${NAME}_vallog +fi + +assert_end ${NAME} diff -Nru sc-im-0.8.2+ds/tests/tests_to_add sc-im-0.8.3+ds/tests/tests_to_add --- sc-im-0.8.2+ds/tests/tests_to_add 1970-01-01 00:00:00.000000000 +0000 +++ sc-im-0.8.3+ds/tests/tests_to_add 2023-01-16 15:38:03.000000000 +0000 @@ -0,0 +1,16 @@ +DONE: +test1: multiple sheets that have formula dependency from one to another +test2: multiple sheets that have formula dependency from one to another (with undo/redo) +test3: multiple sheets that have formulas dependencies from one to another +test4: multiple sheets that have formulas dependencies from one to another (with undo/redo) +test5: yanking and pasting ents keeping references (Pc) - timing and memory usage +test6: yanking and pasting ents keeping references (Pc) - with undo +test8: delete columns and rows repeatedly with undo. +test9: delete last alloc'ed column (ZZ) with undo. + +TODO: ++ test7: yanking and pasting ents keeping references (Pc) (with undo and redo) +fails to restore some ents formulas. + ++ test10: copiar un rango de 10filas x 1 columna con +referencias y pegar en la misma ubicación con Pv daba segfault. crear prueba. diff -Nru sc-im-0.8.2+ds/themes/dracula.sc sc-im-0.8.3+ds/themes/dracula.sc --- sc-im-0.8.2+ds/themes/dracula.sc 2022-01-07 20:58:06.000000000 +0000 +++ sc-im-0.8.3+ds/themes/dracula.sc 2023-01-16 15:38:03.000000000 +0000 @@ -29,6 +29,9 @@ color "type=NUMB fg=MAGENTA bg=BLACK bold=0" color "type=CELL_NEGATIVE fg=RED bg=BLACK bold=0" color "type=EXPRESSION fg=YELLOW bg=BLACK bold=0" +color "type=SHEET fg=comment bg=BLACK bold=0" +color "type=CURRENT_SHEET fg=CYAN bg=BLACK bold=1" +color "type=FILENM fg=YELLOW bg=BLACK bold=0" # To not italicize strings, replace italic=1 with italic=0 on following line -color "type=STRG fg=CYAN bg=BLACK bold=0 italic=1" +color "type=STRG fg=CYAN bg=BLACK bold=0 italic=0" color "type=DATEF fg=YELLOW bg=BLACK"