├── .editorconfig ├── .github └── workflows │ └── linux.yml ├── .gitignore ├── LICENSE ├── Makefile ├── PDCurses.md ├── README.md ├── ToDo ├── aclocal.m4 ├── autogen.sh ├── bash-completion.sh ├── config.make.in ├── configure ├── configure.ac ├── pspg.1 ├── pspg.spec ├── screenshots ├── pspg-4.3.0-foxpro-111x34.png ├── pspg-4.3.0-green-search-111x34.png ├── pspg-4.3.0-mc-111x34.png ├── pspg-4.3.0-mc-export-111x34.png ├── pspg-4.3.0-tao-111x34.png ├── pspg-5.4.0-custom-theme.png ├── pspg-5.5-default.png ├── pspg-5.5-hideheaderline.png ├── pspg-5.5-oddrechighl-1.png ├── pspg-5.5-oddrechighl-2.png ├── pspg-5.5-oddrechighl-3.png ├── theme1.gif ├── theme3.gif └── video.png ├── scripts └── sqlcl │ └── pspg.sql ├── src ├── args.c ├── bscommands.c ├── commands.c ├── commands.h ├── config.c ├── config.h ├── export.c ├── infra.c ├── inputs.c ├── inputs.h ├── linebuffer.c ├── menu.c ├── pgclient.c ├── pretty-csv.c ├── print.c ├── pspg.c ├── pspg.h ├── readline.c ├── sort.c ├── st_curses.h ├── st_menu.c ├── st_menu.h ├── st_menu_styles.c ├── st_panel.h ├── string.c ├── table.c ├── theme_loader.c ├── themes.c ├── themes.h ├── unicode.c ├── unicode.h ├── unicode_east_asian_fw_table.h └── unicode_nonspacing_table.h ├── tests ├── ascii.txt ├── def.txt ├── err.txt ├── help.txt ├── monet-def.txt ├── monet.txt ├── multiline-a.txt ├── multiline-u.txt ├── mysql-ascii.txt ├── mysql.txt ├── nu.txt ├── oracle.txt ├── pg_class.txt ├── pg_class2.txt ├── pg_proc.txt ├── select1.txt ├── single.txt ├── small.txt ├── small2.txt ├── strange.txt ├── strange2.txt ├── tables.txt ├── test.sh ├── test10.csv ├── test11.csv ├── test12.csv ├── test13.csv ├── test2.csv ├── test2.sh ├── test3.csv ├── test4.csv ├── test5.csv ├── test6.csv ├── test7.csv ├── test8.csv ├── test9.csv └── vystup_explain_verbose.txt └── tools ├── ax_debug_cflags.m4 ├── ax_lib_readline.m4 ├── ax_require_defined.m4 ├── ax_with_curses.m4 ├── install.sh ├── m4_ax_compare_version.m4 ├── m4_ax_lib_postgresql.m4 └── m4_ax_with_curses_extra.m4 /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{c,h,l,y,pl,pm}] 4 | indent_style = tab 5 | indent_size = tab 6 | tab_width = 4 7 | 8 | [*.{sgml,xml}] 9 | indent_style = space 10 | indent_size = 1 11 | 12 | [*.xsl] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: build Linux 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: configure 17 | run: ./configure 18 | - name: make 19 | run: make 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | pspg 54 | 55 | /config.cache 56 | /config.log 57 | /config.status 58 | /config.make -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017-2023, Pavel Stehule 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | # Include setting from the configure script 4 | -include config.make 5 | 6 | # override CFLAGS += -g -O2 -Werror-implicit-function-declaration -D_POSIX_SOURCE=1 -std=c99 -Wextra -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion -Wshadow -pedantic -fstack-protector-all -fsanitize=address -fstack-protector -fstack-protector-strong 7 | 8 | # LDFLAGS += -fsanitize=address 9 | 10 | DEPS=$(wildcard *.d) 11 | PSPG_OFILES=csv.o print.o commands.o unicode.o themes.o pspg.o config.o sort.o pgclient.o args.o infra.o \ 12 | table.o string.o export.o linebuffer.o bscommands.o readline.o inputs.o theme_loader.o 13 | 14 | OBJS=$(PSPG_OFILES) 15 | 16 | ifdef COMPILE_MENU 17 | ST_MENU_OFILES=st_menu.o st_menu_styles.o menu.o 18 | OBJS+=$(ST_MENU_OFILES) 19 | endif 20 | 21 | all: pspg 22 | 23 | st_menu_styles.o: src/st_menu_styles.c config.make 24 | $(CC) src/st_menu_styles.c -c $(CPPFLAGS) $(CFLAGS) 25 | 26 | st_menu.o: src/st_menu.c config.make 27 | $(CC) src/st_menu.c -c $(CPPFLAGS) $(CFLAGS) 28 | 29 | csv.o: src/pspg.h src/unicode.h src/pretty-csv.c 30 | $(CC) -c src/pretty-csv.c -o csv.o $(CPPFLAGS) $(CFLAGS) 31 | 32 | args.o: src/pspg.h src/args.c 33 | $(CC) -c src/args.c -o args.o $(CPPFLAGS) $(CFLAGS) 34 | 35 | print.o: src/pspg.h src/unicode.h src/print.c 36 | $(CC) -c src/print.c -o print.o $(CPPFLAGS) $(CFLAGS) 37 | 38 | commands.o: src/pspg.h src/commands.h src/commands.c 39 | $(CC) -c src/commands.c -o commands.o $(CPPFLAGS) $(CFLAGS) 40 | 41 | config.o: src/config.h src/config.c 42 | $(CC) -c src/config.c -o config.o $(CPPFLAGS) $(CFLAGS) 43 | 44 | unicode.o: src/unicode.h src/unicode.c 45 | $(CC) -c src/unicode.c -o unicode.o $(CPPFLAGS) $(CFLAGS) 46 | 47 | themes.o: src/themes.h src/themes.c 48 | $(CC) -c src/themes.c -o themes.o $(CPPFLAGS) $(CFLAGS) 49 | 50 | sort.o: src/pspg.h src/sort.c 51 | $(CC) -c src/sort.c -o sort.o $(CPPFLAGS) $(CFLAGS) 52 | 53 | menu.o: src/pspg.h src/st_menu.h src/commands.h src/menu.c 54 | $(CC) -c src/menu.c -o menu.o $(CPPFLAGS) $(CFLAGS) 55 | 56 | pgclient.o: src/pspg.h src/pgclient.c 57 | $(CC) -c src/pgclient.c -o pgclient.o $(CPPFLAGS) $(CFLAGS) $(PG_CPPFLAGS) 58 | 59 | infra.o: src/pspg.h src/infra.c 60 | $(CC) -c src/infra.c -o infra.o $(CPPFLAGS) $(CFLAGS) 61 | 62 | table.o: src/pspg.h src/table.c 63 | $(CC) -c src/table.c -o table.o $(CPPFLAGS) $(CFLAGS) 64 | 65 | string.o: src/pspg.h src/string.c 66 | $(CC) -c src/string.c -o string.o $(CPPFLAGS) $(CFLAGS) 67 | 68 | export.o: src/pspg.h src/export.c 69 | $(CC) -c src/export.c -o export.o $(CPPFLAGS) $(CFLAGS) 70 | 71 | linebuffer.o: src/pspg.h src/linebuffer.c 72 | $(CC) -c src/linebuffer.c -o linebuffer.o $(CPPFLAGS) $(CFLAGS) 73 | 74 | readline.o: src/pspg.h src/readline.c 75 | $(CC) src/readline.c -c $(CPPFLAGS) $(CFLAGS) 76 | 77 | inputs.o: src/pspg.h src/inputs.h src/inputs.c 78 | $(CC) src/inputs.c -c $(CPPFLAGS) $(CFLAGS) 79 | 80 | bscommands.o: src/pspg.h src/bscommands.c 81 | $(CC) src/bscommands.c -c $(CPPFLAGS) $(CFLAGS) 82 | 83 | theme_loader.o: src/pspg.h src/themes.h src/theme_loader.c 84 | $(CC) src/theme_loader.c -c $(CPPFLAGS) $(CFLAGS) 85 | 86 | pspg.o: src/commands.h src/config.h src/unicode.h src/themes.h src/inputs.h src/pspg.c 87 | $(CC) -c src/pspg.c -o pspg.o $(CPPFLAGS) $(CFLAGS) 88 | 89 | pspg: $(PSPG_OFILES) $(ST_MENU_OFILES) config.make 90 | $(CC) $(PSPG_OFILES) $(ST_MENU_OFILES) -o pspg $(LDFLAGS) $(LDLIBS) $(PG_LFLAGS) $(PG_LDFLAGS) $(PG_LIBS) 91 | 92 | man: 93 | ronn --manual="pspg manual" --section=1 < README.md > pspg.1 94 | 95 | clean: 96 | $(RM) $(ST_MENU_OFILES) 97 | $(RM) $(PSPG_OFILES) 98 | $(RM) $(DEPS) 99 | $(RM) pspg 100 | 101 | distclean: clean 102 | $(RM) -r autom4te.cache 103 | $(RM) aclocal.m4 configure 104 | $(RM) config.h config.log config.make config.status config.h.in 105 | 106 | install: all 107 | tools/install.sh bin pspg "$(DESTDIR)$(bindir)" 108 | 109 | man-install: 110 | tools/install.sh data pspg.1 "$(mandir)/man1" 111 | 112 | strip-install: all 113 | strip pspg 114 | tools/install.sh bin pspg "$(DESTDIR)$(bindir)" 115 | 116 | # Pull-in dependencies generated by -MD 117 | -include $(OBJS:.o=.d) 118 | -------------------------------------------------------------------------------- /PDCurses.md: -------------------------------------------------------------------------------- 1 | Compilation 2 | ----------- 3 | I tested build and execution against pdcursesmod 4.3.5, and it works. In this moment 4 | (Thu Dec 22 05:22:51 CET 2022), pdcurses should be patched (https://github.com/Bill-Gray/PDCursesMod/issues/256), 5 | but with patch (or after fixing this issue), pspg can be compiled against pdcurses 6 | and works well. 7 | 8 | Compilation of pdcurses on Linux (pdcurses for VT) 9 | -------------------------------------------------- 10 | 11 | cd ~/src/PDCursesMod/vt 12 | make clean 13 | make DLL=Y WIDE=Y UTF8=Y DEBUG=Y 14 | sudo make DLL=Y WIDE=Y UTF8=Y DEBUG=Y install 15 | sudo cp libpdcurses.so /usr/lib 16 | sudo ldconfig /usr/lib 17 | 18 | Maybe can be necessary to copy header files to `/usr/local/include/pdcurses`. 19 | 20 | Note - the directory should be fresh after git sync without running cmake. 21 | 22 | Compilation of pspg on pdcurses 23 | ------------------------------- 24 | 25 | PANEL_LIBS=-lpdcurses CURSES_LIBS=-lpdcurses\ 26 | CURSES_CFLAGS="-I/usr/local/include/pdcurses -DPDC_WIDE=Y -DPDC_FORCE_UTF8=Y -L/usr/lib"\ 27 | ./configure -libdir=/usr/lib 28 | make 29 | 30 | -------------------------------------------------------------------------------- /ToDo: -------------------------------------------------------------------------------- 1 | ToDo 2 | ==== 3 | 4 | Known bugs 5 | ========== 6 | 7 | Possible ToDo 8 | ============= 9 | * fast scrolling - vertical scrolling based on table's rows 10 | * support fetched data - columns width can be different 11 | 12 | Similar projects 13 | ================ 14 | * tless 15 | * ngrid 16 | * muhmud/lessql 17 | * visidata 18 | * tabview 19 | -------------------------------------------------------------------------------- /aclocal.m4: -------------------------------------------------------------------------------- 1 | # generated automatically by aclocal 1.16.5 -*- Autoconf -*- 2 | 3 | # Copyright (C) 1996-2021 Free Software Foundation, Inc. 4 | 5 | # This file is free software; the Free Software Foundation 6 | # gives unlimited permission to copy and/or distribute it, 7 | # with or without modifications, as long as this notice is preserved. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 11 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 | # PARTICULAR PURPOSE. 13 | 14 | m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) 15 | # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- 16 | # serial 11 (pkg-config-0.29.1) 17 | 18 | dnl Copyright © 2004 Scott James Remnant . 19 | dnl Copyright © 2012-2015 Dan Nicholson 20 | dnl 21 | dnl This program is free software; you can redistribute it and/or modify 22 | dnl it under the terms of the GNU General Public License as published by 23 | dnl the Free Software Foundation; either version 2 of the License, or 24 | dnl (at your option) any later version. 25 | dnl 26 | dnl This program is distributed in the hope that it will be useful, but 27 | dnl WITHOUT ANY WARRANTY; without even the implied warranty of 28 | dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 29 | dnl General Public License for more details. 30 | dnl 31 | dnl You should have received a copy of the GNU General Public License 32 | dnl along with this program; if not, write to the Free Software 33 | dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 34 | dnl 02111-1307, USA. 35 | dnl 36 | dnl As a special exception to the GNU General Public License, if you 37 | dnl distribute this file as part of a program that contains a 38 | dnl configuration script generated by Autoconf, you may include it under 39 | dnl the same distribution terms that you use for the rest of that 40 | dnl program. 41 | 42 | dnl PKG_PREREQ(MIN-VERSION) 43 | dnl ----------------------- 44 | dnl Since: 0.29 45 | dnl 46 | dnl Verify that the version of the pkg-config macros are at least 47 | dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's 48 | dnl installed version of pkg-config, this checks the developer's version 49 | dnl of pkg.m4 when generating configure. 50 | dnl 51 | dnl To ensure that this macro is defined, also add: 52 | dnl m4_ifndef([PKG_PREREQ], 53 | dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) 54 | dnl 55 | dnl See the "Since" comment for each macro you use to see what version 56 | dnl of the macros you require. 57 | m4_defun([PKG_PREREQ], 58 | [m4_define([PKG_MACROS_VERSION], [0.29.1]) 59 | m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, 60 | [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) 61 | ])dnl PKG_PREREQ 62 | 63 | dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) 64 | dnl ---------------------------------- 65 | dnl Since: 0.16 66 | dnl 67 | dnl Search for the pkg-config tool and set the PKG_CONFIG variable to 68 | dnl first found in the path. Checks that the version of pkg-config found 69 | dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is 70 | dnl used since that's the first version where most current features of 71 | dnl pkg-config existed. 72 | AC_DEFUN([PKG_PROG_PKG_CONFIG], 73 | [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) 74 | m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) 75 | m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) 76 | AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) 77 | AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) 78 | AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) 79 | 80 | if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then 81 | AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) 82 | fi 83 | if test -n "$PKG_CONFIG"; then 84 | _pkg_min_version=m4_default([$1], [0.9.0]) 85 | AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) 86 | if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then 87 | AC_MSG_RESULT([yes]) 88 | else 89 | AC_MSG_RESULT([no]) 90 | PKG_CONFIG="" 91 | fi 92 | fi[]dnl 93 | ])dnl PKG_PROG_PKG_CONFIG 94 | 95 | dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 96 | dnl ------------------------------------------------------------------- 97 | dnl Since: 0.18 98 | dnl 99 | dnl Check to see whether a particular set of modules exists. Similar to 100 | dnl PKG_CHECK_MODULES(), but does not set variables or print errors. 101 | dnl 102 | dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) 103 | dnl only at the first occurence in configure.ac, so if the first place 104 | dnl it's called might be skipped (such as if it is within an "if", you 105 | dnl have to call PKG_CHECK_EXISTS manually 106 | AC_DEFUN([PKG_CHECK_EXISTS], 107 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 108 | if test -n "$PKG_CONFIG" && \ 109 | AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then 110 | m4_default([$2], [:]) 111 | m4_ifvaln([$3], [else 112 | $3])dnl 113 | fi]) 114 | 115 | dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) 116 | dnl --------------------------------------------- 117 | dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting 118 | dnl pkg_failed based on the result. 119 | m4_define([_PKG_CONFIG], 120 | [if test -n "$$1"; then 121 | pkg_cv_[]$1="$$1" 122 | elif test -n "$PKG_CONFIG"; then 123 | PKG_CHECK_EXISTS([$3], 124 | [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` 125 | test "x$?" != "x0" && pkg_failed=yes ], 126 | [pkg_failed=yes]) 127 | else 128 | pkg_failed=untried 129 | fi[]dnl 130 | ])dnl _PKG_CONFIG 131 | 132 | dnl _PKG_SHORT_ERRORS_SUPPORTED 133 | dnl --------------------------- 134 | dnl Internal check to see if pkg-config supports short errors. 135 | AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], 136 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) 137 | if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then 138 | _pkg_short_errors_supported=yes 139 | else 140 | _pkg_short_errors_supported=no 141 | fi[]dnl 142 | ])dnl _PKG_SHORT_ERRORS_SUPPORTED 143 | 144 | 145 | dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], 146 | dnl [ACTION-IF-NOT-FOUND]) 147 | dnl -------------------------------------------------------------- 148 | dnl Since: 0.4.0 149 | dnl 150 | dnl Note that if there is a possibility the first call to 151 | dnl PKG_CHECK_MODULES might not happen, you should be sure to include an 152 | dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac 153 | AC_DEFUN([PKG_CHECK_MODULES], 154 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 155 | AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl 156 | AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl 157 | 158 | pkg_failed=no 159 | AC_MSG_CHECKING([for $1]) 160 | 161 | _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) 162 | _PKG_CONFIG([$1][_LIBS], [libs], [$2]) 163 | 164 | m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS 165 | and $1[]_LIBS to avoid the need to call pkg-config. 166 | See the pkg-config man page for more details.]) 167 | 168 | if test $pkg_failed = yes; then 169 | AC_MSG_RESULT([no]) 170 | _PKG_SHORT_ERRORS_SUPPORTED 171 | if test $_pkg_short_errors_supported = yes; then 172 | $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` 173 | else 174 | $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` 175 | fi 176 | # Put the nasty error message in config.log where it belongs 177 | echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD 178 | 179 | m4_default([$4], [AC_MSG_ERROR( 180 | [Package requirements ($2) were not met: 181 | 182 | $$1_PKG_ERRORS 183 | 184 | Consider adjusting the PKG_CONFIG_PATH environment variable if you 185 | installed software in a non-standard prefix. 186 | 187 | _PKG_TEXT])[]dnl 188 | ]) 189 | elif test $pkg_failed = untried; then 190 | AC_MSG_RESULT([no]) 191 | m4_default([$4], [AC_MSG_FAILURE( 192 | [The pkg-config script could not be found or is too old. Make sure it 193 | is in your PATH or set the PKG_CONFIG environment variable to the full 194 | path to pkg-config. 195 | 196 | _PKG_TEXT 197 | 198 | To get pkg-config, see .])[]dnl 199 | ]) 200 | else 201 | $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS 202 | $1[]_LIBS=$pkg_cv_[]$1[]_LIBS 203 | AC_MSG_RESULT([yes]) 204 | $3 205 | fi[]dnl 206 | ])dnl PKG_CHECK_MODULES 207 | 208 | 209 | dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], 210 | dnl [ACTION-IF-NOT-FOUND]) 211 | dnl --------------------------------------------------------------------- 212 | dnl Since: 0.29 213 | dnl 214 | dnl Checks for existence of MODULES and gathers its build flags with 215 | dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags 216 | dnl and VARIABLE-PREFIX_LIBS from --libs. 217 | dnl 218 | dnl Note that if there is a possibility the first call to 219 | dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to 220 | dnl include an explicit call to PKG_PROG_PKG_CONFIG in your 221 | dnl configure.ac. 222 | AC_DEFUN([PKG_CHECK_MODULES_STATIC], 223 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 224 | _save_PKG_CONFIG=$PKG_CONFIG 225 | PKG_CONFIG="$PKG_CONFIG --static" 226 | PKG_CHECK_MODULES($@) 227 | PKG_CONFIG=$_save_PKG_CONFIG[]dnl 228 | ])dnl PKG_CHECK_MODULES_STATIC 229 | 230 | 231 | dnl PKG_INSTALLDIR([DIRECTORY]) 232 | dnl ------------------------- 233 | dnl Since: 0.27 234 | dnl 235 | dnl Substitutes the variable pkgconfigdir as the location where a module 236 | dnl should install pkg-config .pc files. By default the directory is 237 | dnl $libdir/pkgconfig, but the default can be changed by passing 238 | dnl DIRECTORY. The user can override through the --with-pkgconfigdir 239 | dnl parameter. 240 | AC_DEFUN([PKG_INSTALLDIR], 241 | [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) 242 | m4_pushdef([pkg_description], 243 | [pkg-config installation directory @<:@]pkg_default[@:>@]) 244 | AC_ARG_WITH([pkgconfigdir], 245 | [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, 246 | [with_pkgconfigdir=]pkg_default) 247 | AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) 248 | m4_popdef([pkg_default]) 249 | m4_popdef([pkg_description]) 250 | ])dnl PKG_INSTALLDIR 251 | 252 | 253 | dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) 254 | dnl -------------------------------- 255 | dnl Since: 0.27 256 | dnl 257 | dnl Substitutes the variable noarch_pkgconfigdir as the location where a 258 | dnl module should install arch-independent pkg-config .pc files. By 259 | dnl default the directory is $datadir/pkgconfig, but the default can be 260 | dnl changed by passing DIRECTORY. The user can override through the 261 | dnl --with-noarch-pkgconfigdir parameter. 262 | AC_DEFUN([PKG_NOARCH_INSTALLDIR], 263 | [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) 264 | m4_pushdef([pkg_description], 265 | [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) 266 | AC_ARG_WITH([noarch-pkgconfigdir], 267 | [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, 268 | [with_noarch_pkgconfigdir=]pkg_default) 269 | AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) 270 | m4_popdef([pkg_default]) 271 | m4_popdef([pkg_description]) 272 | ])dnl PKG_NOARCH_INSTALLDIR 273 | 274 | 275 | dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, 276 | dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 277 | dnl ------------------------------------------- 278 | dnl Since: 0.28 279 | dnl 280 | dnl Retrieves the value of the pkg-config variable for the given module. 281 | AC_DEFUN([PKG_CHECK_VAR], 282 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 283 | AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl 284 | 285 | _PKG_CONFIG([$1], [variable="][$3]["], [$2]) 286 | AS_VAR_COPY([$1], [pkg_cv_][$1]) 287 | 288 | AS_VAR_IF([$1], [""], [$5], [$4])dnl 289 | ])dnl PKG_CHECK_VAR 290 | 291 | dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, 292 | dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], 293 | dnl [DESCRIPTION], [DEFAULT]) 294 | dnl ------------------------------------------ 295 | dnl 296 | dnl Prepare a "--with-" configure option using the lowercase 297 | dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and 298 | dnl PKG_CHECK_MODULES in a single macro. 299 | AC_DEFUN([PKG_WITH_MODULES], 300 | [ 301 | m4_pushdef([with_arg], m4_tolower([$1])) 302 | 303 | m4_pushdef([description], 304 | [m4_default([$5], [build with ]with_arg[ support])]) 305 | 306 | m4_pushdef([def_arg], [m4_default([$6], [auto])]) 307 | m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) 308 | m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) 309 | 310 | m4_case(def_arg, 311 | [yes],[m4_pushdef([with_without], [--without-]with_arg)], 312 | [m4_pushdef([with_without],[--with-]with_arg)]) 313 | 314 | AC_ARG_WITH(with_arg, 315 | AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, 316 | [AS_TR_SH([with_]with_arg)=def_arg]) 317 | 318 | AS_CASE([$AS_TR_SH([with_]with_arg)], 319 | [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], 320 | [auto],[PKG_CHECK_MODULES([$1],[$2], 321 | [m4_n([def_action_if_found]) $3], 322 | [m4_n([def_action_if_not_found]) $4])]) 323 | 324 | m4_popdef([with_arg]) 325 | m4_popdef([description]) 326 | m4_popdef([def_arg]) 327 | 328 | ])dnl PKG_WITH_MODULES 329 | 330 | dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, 331 | dnl [DESCRIPTION], [DEFAULT]) 332 | dnl ----------------------------------------------- 333 | dnl 334 | dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES 335 | dnl check._[VARIABLE-PREFIX] is exported as make variable. 336 | AC_DEFUN([PKG_HAVE_WITH_MODULES], 337 | [ 338 | PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) 339 | 340 | AM_CONDITIONAL([HAVE_][$1], 341 | [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) 342 | ])dnl PKG_HAVE_WITH_MODULES 343 | 344 | dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, 345 | dnl [DESCRIPTION], [DEFAULT]) 346 | dnl ------------------------------------------------------ 347 | dnl 348 | dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after 349 | dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make 350 | dnl and preprocessor variable. 351 | AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], 352 | [ 353 | PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) 354 | 355 | AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], 356 | [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) 357 | ])dnl PKG_HAVE_DEFINE_WITH_MODULES 358 | 359 | m4_include([tools/ax_debug_cflags.m4]) 360 | m4_include([tools/ax_lib_readline.m4]) 361 | m4_include([tools/ax_require_defined.m4]) 362 | m4_include([tools/ax_with_curses.m4]) 363 | m4_include([tools/m4_ax_compare_version.m4]) 364 | m4_include([tools/m4_ax_lib_postgresql.m4]) 365 | m4_include([tools/m4_ax_with_curses_extra.m4]) 366 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export WARNINGS="all" 4 | set -e 5 | 6 | # Ideally, we could just do this: 7 | # 8 | #${AUTORECONF:-autoreconf} -v -I tools 9 | # 10 | # Unfortunately, Autoconf 2.61's autoreconf(1) (found in Mac OS X 10.5 11 | # Leopard) neglects to pass the -I on to aclocal(1), which is 12 | # precisely where we need it! So we do basically what it would have 13 | # done. 14 | 15 | run () { 16 | test "${V}" = 1 && echo $0: running: "$@" 17 | "$@" 18 | } 19 | 20 | run ${ACLOCAL:-aclocal} -I tools 21 | run ${AUTOCONF:-autoconf} --include=tools 22 | -------------------------------------------------------------------------------- /bash-completion.sh: -------------------------------------------------------------------------------- 1 | _pspg() 2 | { 3 | local cur prev words cword 4 | _init_completion || return 5 | 6 | case $prev in 7 | -f | --file | --log) 8 | _filedir 9 | return 10 | ;; 11 | --csv-header) 12 | COMPREPLY=($(compgen -W 'on off' -- "$cur")) 13 | return 14 | ;; 15 | --hold-stream) 16 | COMPREPLY=($(compgen -W '1 2 3' -- "$cur")) 17 | return 18 | ;; 19 | --border) 20 | COMPREPLY=($(compgen -W '0 1 2' -- "$cur")) 21 | return 22 | ;; 23 | esac 24 | 25 | if [[ $cur == -* ]]; then 26 | COMPREPLY=($(compgen -W '$(_parse_help "$1" --help)' -- "$cur")) 27 | return 28 | fi 29 | 30 | _filedir 31 | 32 | } && 33 | complete -F _pspg pspg 34 | -------------------------------------------------------------------------------- /config.make.in: -------------------------------------------------------------------------------- 1 | # -*- makefile-gmake -*- 2 | 3 | prefix = @prefix@ 4 | exec_prefix = @exec_prefix@ 5 | bindir = @bindir@ 6 | mandir = @mandir@ 7 | docdir = @docdir@ 8 | datarootdir = @datarootdir@ 9 | sysconfdir = @sysconfdir@ 10 | 11 | COMPILE_MENU = @COMPILE_MENU@ 12 | 13 | CC = @CC@ 14 | CFLAGS = @CFLAGS@ @COVERAGE_CFLAGS@ @DEBUG_CFLAGS@ @CURSES_CFLAGS@ @DEFS@ -Wall -MD 15 | LDFLAGS = @LDFLAGS@ 16 | LDLIBS = @LIBS@ @PANEL_LIBS@ @CURSES_LIBS@ 17 | 18 | PG_CPPFLAGS = @POSTGRESQL_CPPFLAGS@ 19 | PG_LDFLAGS = @POSTGRESQL_LDFLAGS@ 20 | PG_LIBS = @POSTGRESQL_LIBS@ 21 | 22 | config.status: configure 23 | ./config.status --recheck 24 | 25 | config.make: config.status 26 | ./config.status $@ 27 | 28 | config.make: config.make.in 29 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.70]) 2 | AC_INIT([pspg],[0],[pavel.stehule@gmail.com],[pspg]) 3 | 4 | AC_LANG([C]) 5 | AC_CONFIG_SRCDIR(src) 6 | 7 | dnl Document where we keep our .m4 file. 8 | AC_CONFIG_MACRO_DIR([tools]) 9 | dnl Make sure aclocal actually found it! 10 | m4_pattern_forbid([^AX_]) 11 | 12 | AC_PROG_CC 13 | AC_CHECK_INCLUDES_DEFAULT 14 | AC_PROG_EGREP 15 | 16 | AC_HEADER_TIOCGWINSZ 17 | AX_DEBUG_CFLAGS 18 | AX_WITH_CURSES 19 | AX_WITH_CURSES_PANEL 20 | AX_LIB_READLINE 21 | AX_LIB_POSTGRESQL([],[], AC_MSG_NOTICE([PostgreSQL library not found])) 22 | 23 | case "$ax_cv_ncurses" in "no") 24 | AC_MSG_ERROR([ncurses not found]) 25 | esac 26 | case "$ax_cv_ncursesw" in "no") 27 | AC_MSG_WARN([The found ncurses library does not support wide-char.]) 28 | AC_MSG_WARN([This means that pspg will not correctly render UTF-8.]) 29 | esac 30 | 31 | AC_CHECK_LIB([m],[roundl]) 32 | 33 | AC_SEARCH_LIBS([clock_gettime], [rt posix4], 34 | [], 35 | [AC_MSG_ERROR([Function clock_gettime not available.])] 36 | ) 37 | 38 | AC_SUBST(enable_debug) 39 | AC_SUBST(CURSES_LIBS) 40 | AC_SUBST(COVERAGE_CFLAGS) 41 | AC_SUBST(COVERAGE_LDFLAGS) 42 | AC_SUBST(COMPILE_MENU) 43 | AC_SUBST(POSTGRESQL_CFLAGS) 44 | AC_SUBST(POSTGRESQL_LDFLAGS) 45 | 46 | AC_SUBST([POSTGRESQL_VERSION]) 47 | AC_SUBST([POSTGRESQL_CPPFLAGS]) 48 | AC_SUBST([POSTGRESQL_LDFLAGS]) 49 | AC_SUBST([POSTGRESQL_LIBS]) 50 | 51 | AC_CONFIG_FILES([config.make]) 52 | 53 | AC_ARG_WITH([menu], 54 | AS_HELP_STRING([--without-menu]), 55 | [compile_menu=no], 56 | [compile_menu=yes]) 57 | 58 | if test "x$compile_menu" != "xyes"; then 59 | COMPILE_MENU=0 60 | else 61 | if test "$ax_cv_panel" != yes; then 62 | AC_MSG_ERROR([ncurses panel library not found]) 63 | fi 64 | AC_MSG_NOTICE([pspg will be compiled with menu]) 65 | CFLAGS="$CFLAGS -DCOMPILE_MENU" 66 | COMPILE_MENU=1 67 | fi 68 | 69 | # supply -g if --enable-debug 70 | if test "$enable_debug" = yes && test "$ac_cv_prog_cc_g" = yes; then 71 | CFLAGS="$CFLAGS -g" 72 | fi 73 | 74 | AC_CHECK_HEADERS([sys/inotify.h], have_inotify=yes, have_inotify=no) 75 | 76 | AC_ARG_WITH([inotify], 77 | [AS_HELP_STRING([--without-inotify], 78 | [(Linux only) do not build with inotify support (default is yes)])], 79 | [with_inotify=no], 80 | [with_inotify=yes]) 81 | 82 | if test "x$have_inotify" = "xyes"; then 83 | if test "x$with_inotify" != "xyes"; then 84 | have_inotify=no 85 | else 86 | AC_DEFINE(HAVE_INOTIFY, 1, [Define if you have inotify support (linux only)]) 87 | fi 88 | fi 89 | 90 | 91 | AC_CHECK_HEADERS([sys/event.h], have_kqueue=yes, have_kqueue=no) 92 | 93 | if test "x$have_kqueue" = "xyes"; then 94 | 95 | AC_CHECK_FUNCS(kqueue, have_kqueue=yes, have_kqueue=no) 96 | 97 | if test "x$have_kqueue" = "xyes"; then 98 | AC_DEFINE(HAVE_KQUEUE, 1, [Define if you have kqueue support (BSD only)]) 99 | fi 100 | fi 101 | 102 | AC_CHECK_HEADERS([sys/utsname.h]) 103 | 104 | AC_OUTPUT 105 | -------------------------------------------------------------------------------- /pspg.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: rpm-spec-mode; encoding: utf-8; -*- 2 | # Pass '--without docs' to rpmbuild if you don't want the documentation to be build 3 | 4 | Summary: pspg: a unix pager optimized for psql 5 | Name: pspg 6 | Version: 5.8.11 7 | Release: 0%{?dist} 8 | License: BSD 9 | Group: Development/Tools 10 | Vendor: Pavel Stehule 11 | URL: https://github.com/okbob/pspg 12 | Source: https://github.com/okbob/pspg/archive/%{version}.tar.gz 13 | BuildRequires: ncurses-devel readline-devel libpq-devel 14 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 15 | Requires: ncurses readline libpq 16 | 17 | %description 18 | psps is a unix pager optimized for psql. It can freeze rows, freeze 19 | columns, and lot of color themes are included. 20 | 21 | %prep 22 | %setup -q -n pspg 23 | 24 | %build 25 | %configure 26 | CFLAGS="$RPM_OPT_FLAGS" 27 | %{__make} %{_smp_mflags} \ 28 | prefix=%{_prefix} \ 29 | all 30 | 31 | %install 32 | [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT 33 | CFLAGS="$RPM_OPT_FLAGS" 34 | %{__make} %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT \ 35 | prefix=%{_prefix} bindir=%{_bindir} mandir=%{_mandir} \ 36 | install 37 | 38 | %clean 39 | [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT 40 | 41 | %files 42 | %defattr(-,root,root) 43 | %{_bindir}/* 44 | 45 | %changelog 46 | * Thu Dec 22 2022 Pavel Stehule 47 | - pspg can be compiled (and used) with pdcursesmod 48 | 49 | * Mon Nov 28 2022 Pavel Stehule 50 | - support direct true color mode 51 | 52 | * Fri Now 4 2022 Pavel Stehule 53 | - column scroll left, column scroll right 54 | 55 | * Tue Aug 2 2022 Pavel Stehule 56 | - allow to set esc delay interval 57 | 58 | * Tue Nov 2 2021 Pavel Stehule 59 | - new visual effects --highlight-odd-rec and --hide-header-line 60 | - possibility to read SQLcl (Oracle) tables in ANSICONSOLE format 61 | - support streaming mode over files on BSD like systems (kqueue support) 62 | - one char horizontal scrolling 63 | 64 | * Wed Oct 13 2021 Pavel Stehule 65 | - custom themes 66 | - fix pasting to clipboard on macos 67 | 68 | * Fri Jul 30 2021 Pavel Stehule 69 | - using stream mode as default for PIPE source was bad idea. 70 | I reverted it. 71 | 72 | * Thu Jul 29 2021 Pavel Stehule 73 | - the option --stream is implicit for PIPE. If you use 74 | pspg as page for PSQL_WATCH_PAGER, there is not necessity 75 | to explicitly use option --stream 76 | 77 | * Mon Jul 26 2021 Pavel Stehule 78 | - progressive load - instead complete load on start, now 79 | pspg loads 500 rows, 2000 rows, 2000 rows, ... so first 80 | rows can be displayed quickly. 81 | - now, pspg can format texts produced by psql's help 82 | - fix few bugs 83 | 84 | * Fri Jul 16 2021 Pavel Stehule 85 | - new functionality "Ctrl O" - temp switch to primary screen 86 | - total rewrite input events processing 87 | 88 | * Sat Jun 26 2021 Pavel Stehule 89 | - new option --no-last-row-search 90 | - code cleaning 91 | 92 | * Sun May 30 2021 Pavel Stehule 93 | - new light PaperColor theme 94 | - possibility to set nullstr used by export routines 95 | - introduction interactive command line and backslash commands 96 | - \save, \copy, \theme, \quit, \order, \orderd and \search commands 97 | - possibility to push export output to some program by using pipe 98 | 99 | * Sat Apr 17 2021 Pavel Stehule 100 | - --menu-always ensure active top bar menu all time 101 | - modify theme 9 102 | - fix detection of last row of table when border = 1 103 | 104 | * Tue Mar 23 2021 Pavel Stehule 105 | - fix stream mode on apple (/dev/tty dosn't work with poll function) 106 | - new query stream mode - queries for pg client are read from stream 107 | 108 | * Fri Mar 19 2021 Pavel Stehule 109 | - for some cases the multiline values are exported as one value 110 | 111 | * Sun Feb 7 2021 Pavel Stehule 112 | - main window has vertical scrollbar 113 | 114 | * Fri Jan 29 2021 Pavel Stehule 115 | - enhancing mouse usage by support xterm mouse mode 1002 116 | 117 | * Sat Jan 16 2021 Pavel Stehule 118 | - possibility to export to clipboard or file in CSV, TSVC, formatted text and INSERT formats 119 | 120 | * Tue May 19 2020 Pavel Stehule 121 | - code cleaning 122 | - option skip-columns-like 123 | - column names dynamic positioning 124 | 125 | * Mon Apr 6 2020 Pavel Stehule 126 | - streaming mode for file (requires inotify) 127 | - named pipe can be source stream 128 | 129 | * Fri Mar 27 2020 Pavel Stehule 130 | - integration inotify check of input file 131 | 132 | * Thu Dec 12 2019 Pavel Stehule 133 | - possibility to specify NULL string 134 | 135 | * Sun Nov 24 2019 Pavel Stehule 136 | - tsv format suppport 137 | 138 | * Fri Nov 15 2019 Pavel Stehule 139 | - fix entering string on CentOS 7.7 140 | - try to process -F without ncurses start 141 | - infrastructure cleaning 142 | 143 | * Mon Nov 4 2019 Pavel Stehule 144 | - materialize dependency on libpq 145 | - add internal performance diagnostics 146 | - few micro optimizations 147 | 148 | * Sun Oct 27 2019 Pavel Stehule 149 | - non interactive mode for csv 150 | - possibility to take data from query 151 | - watch mode 152 | 153 | * Wed Oct 9 2019 Pavel Stehule 154 | - better handling Escape and sigint signal 155 | - more comfortable usage of readline input 156 | 157 | * Wed Sep 25 2019 Pavel Stehule 158 | - pspg can be used as csv viewer 159 | 160 | * Sun Sep 8 2019 Pavel Stehule 161 | - complete support (with multilines) of sort over columns with numeric values 162 | 163 | * Thu Sep 5 2019 Pavel Stehule 164 | - initial possibility to sort by numeric column 165 | 166 | * Sun Sep 1 2019 Pavel Stehule 167 | - column search 168 | 169 | * Sat Aug 24 2019 Pavel Stehule 170 | - vertical (column) cursor support 171 | 172 | * Wed Jul 24 2019 Pavel Stehule 173 | - fix minor issues - left scrolling and theme changing 174 | 175 | * Mon Apr 8 2019 Pavel Stehule 176 | - fix minor issue related to draw menu, when terminal is resized 177 | 178 | * Thu Mar 21 2019 Pavel Stehule 179 | - use higher 8 colours when it is possible (fix Fodora 30 issue) 180 | - new themes 181 | - new options: bold labels, bold cursors 182 | 183 | * Mon Sep 10 2018 Pavel Stehule 184 | - possibility to show line numbers and hide cursor, menu and status bar 185 | - new themes 186 | - fix some bugs 187 | 188 | * Thu Jul 19 2018 Pavel Stehule 189 | - menu support 190 | - new themes 191 | 192 | * Thu Apr 26 2018 Pavel Stehule 193 | - compile with readline when it is available - history support 194 | - fix some bugs 195 | 196 | * Fri Mar 16 2018 Pavel Stehule 197 | - lot of bugfixes related to searching 198 | - code cleaning 199 | - 8bit encoding support 200 | 201 | * Sun Feb 11 2018 Pavel Stehule 202 | - fix few crash related when searching was used 203 | 204 | * Fri Jan 12 2017 Pavel Stehule 205 | - possibility to replace ascii art by unicode 206 | 207 | * Thu Dec 28 2017 Pavel Stehule 208 | - bookmarks 209 | - searching is much better now 210 | 211 | * Fri Dec 15 2017 Pavel Stehule 212 | - case insensitive searching 213 | 214 | * Fri Dec 1 2017 Pavel Stehule 215 | - less like status bar 216 | 217 | * Sat Nov 25 2017 Pavel Stehule 218 | - lot of fixes and new features 219 | 220 | * Wed Sep 13 2017 Pavel Stehule 221 | - initial version 222 | 223 | -------------------------------------------------------------------------------- /screenshots/pspg-4.3.0-foxpro-111x34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-4.3.0-foxpro-111x34.png -------------------------------------------------------------------------------- /screenshots/pspg-4.3.0-green-search-111x34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-4.3.0-green-search-111x34.png -------------------------------------------------------------------------------- /screenshots/pspg-4.3.0-mc-111x34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-4.3.0-mc-111x34.png -------------------------------------------------------------------------------- /screenshots/pspg-4.3.0-mc-export-111x34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-4.3.0-mc-export-111x34.png -------------------------------------------------------------------------------- /screenshots/pspg-4.3.0-tao-111x34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-4.3.0-tao-111x34.png -------------------------------------------------------------------------------- /screenshots/pspg-5.4.0-custom-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-5.4.0-custom-theme.png -------------------------------------------------------------------------------- /screenshots/pspg-5.5-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-5.5-default.png -------------------------------------------------------------------------------- /screenshots/pspg-5.5-hideheaderline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-5.5-hideheaderline.png -------------------------------------------------------------------------------- /screenshots/pspg-5.5-oddrechighl-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-5.5-oddrechighl-1.png -------------------------------------------------------------------------------- /screenshots/pspg-5.5-oddrechighl-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-5.5-oddrechighl-2.png -------------------------------------------------------------------------------- /screenshots/pspg-5.5-oddrechighl-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/pspg-5.5-oddrechighl-3.png -------------------------------------------------------------------------------- /screenshots/theme1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/theme1.gif -------------------------------------------------------------------------------- /screenshots/theme3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/theme3.gif -------------------------------------------------------------------------------- /screenshots/video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okbob/pspg/4bc6c1464b6ab5af774a2c20d8947b003de6119b/screenshots/video.png -------------------------------------------------------------------------------- /scripts/sqlcl/pspg.sql: -------------------------------------------------------------------------------- 1 | script 2 | var CommandRegistry = Java.type("oracle.dbtools.raptor.newscriptrunner.CommandRegistry"); 3 | var CommandListener = Java.type("oracle.dbtools.raptor.newscriptrunner.CommandListener") 4 | 5 | var Runtime = Java.type("java.lang.Runtime"); 6 | var Scanner = Java.type("java.util.Scanner"); 7 | var System = Java.type("java.lang.System"); 8 | 9 | var FileOutputStream = Java.type("java.io.FileOutputStream"); 10 | var ByteArrayOutputStream = Java.type("java.io.ByteArrayOutputStream"); 11 | var BufferedOutputStream = Java.type("java.io.BufferedOutputStream"); 12 | 13 | var Files = Java.type("java.nio.file.Files"); 14 | var Path = Java.type("java.nio.file.Path"); 15 | var File = Java.type("java.io.File"); 16 | 17 | var cmd = {}; 18 | 19 | cmd.handle = function (conn,ctx,cmd) { 20 | if (cmd.getSql().startsWith("pspg ")) { 21 | var tty = System.getenv("TTY"); 22 | if (tty == null) { 23 | print("\nIn order to use pspg to page results, make sure you pass in your tty as an environment variable."); 24 | print("For example, invoke sqlcl like this:\n"); 25 | print("$ TTY=$(tty) sqlcl ...\n"); 26 | 27 | return true; 28 | } 29 | 30 | var sql = cmd.getSql().substring(5); 31 | var tempPath = Files.createTempFile("sqlcl-result", ".data"); 32 | try { 33 | var bout = new ByteArrayOutputStream(); 34 | sqlcl.setOut(new BufferedOutputStream(bout)); 35 | 36 | // Set this to a big value so that we do not get repeating headers 37 | ctx.putProperty("script.runner.setpagesize", 1000000); 38 | sqlcl.setConn(conn); 39 | sqlcl.setStmt(sql); 40 | sqlcl.run(); 41 | 42 | var fileOutputStream = new FileOutputStream(tempPath.toFile()); 43 | bout.writeTo(fileOutputStream); 44 | fileOutputStream.close(); 45 | 46 | var pager = Runtime.getRuntime().exec( 47 | [ "sh", "-c", "pspg '" + tempPath.toString() + "' < " + tty + " > " + tty ] 48 | ); 49 | pager.waitFor(); 50 | } finally { 51 | Files.delete(tempPath); 52 | } 53 | 54 | // return TRUE to indicate the command was handled 55 | return true; 56 | } 57 | 58 | // return FALSE to indicate the command was not handled 59 | // and other commandListeners will be asked to handle it 60 | return false; 61 | } 62 | 63 | cmd.begin = function (conn,ctx,cmd) {} 64 | cmd.end = function (conn,ctx,cmd) {} 65 | 66 | var pspgCommand = Java.extend(CommandListener, { 67 | handleEvent: cmd.handle, 68 | beginEvent: cmd.begin, 69 | endEvent: cmd.end 70 | }); 71 | 72 | // Registering the new Command 73 | CommandRegistry.addForAllStmtsListener(pspgCommand.class); 74 | / 75 | 76 | -------------------------------------------------------------------------------- /src/commands.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * command.h 4 | * a list of commands and translations between keys and commands 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/commands.h 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #ifndef COMMANDS_H 15 | #define COMMANDS_H 16 | 17 | #include "config.h" 18 | 19 | /* 20 | * List of supported commands. Some these commands can be mapped to keys 21 | */ 22 | typedef enum PspgCommand 23 | { 24 | cmd_Invalid = 0, 25 | cmd_RESIZE_EVENT, 26 | cmd_MOUSE_EVENT, 27 | 28 | cmd_ReleaseCols = 100, 29 | cmd_FreezeOneCol, 30 | cmd_FreezeTwoCols, 31 | cmd_FreezeThreeCols, 32 | cmd_FreezeFourCols, 33 | cmd_FreezeFiveCols, 34 | cmd_FreezeSixCols, 35 | cmd_FreezeSevenCols, 36 | cmd_FreezeEightCols, 37 | cmd_FreezeNineCols, 38 | cmd_SoundToggle, 39 | cmd_MouseToggle, 40 | cmd_UtfArtToggle, 41 | cmd_MenuAsciiArtToggle, 42 | cmd_CSSearchSet, 43 | cmd_CISearchSet, 44 | cmd_USSearchSet, 45 | cmd_HighlightLines, 46 | cmd_HighlightValues, 47 | cmd_NoHighlight, 48 | 49 | cmd_SetTheme_MidnightBlack, 50 | cmd_SetTheme_Midnight, 51 | cmd_SetTheme_Foxpro, 52 | cmd_SetTheme_Pdmenu, 53 | cmd_SetTheme_White, 54 | cmd_SetTheme_Mutt, 55 | cmd_SetTheme_Pcfand, 56 | cmd_SetTheme_Green, 57 | cmd_SetTheme_Blue, 58 | cmd_SetTheme_WP, 59 | cmd_SetTheme_Lowcontrast, 60 | cmd_SetTheme_Darkcyan, 61 | cmd_SetTheme_Paradox, 62 | cmd_SetTheme_DBase, 63 | cmd_SetTheme_DBasemagenta, 64 | cmd_SetTheme_Red, 65 | cmd_SetTheme_Simple, 66 | cmd_SetTheme_SolarDark, 67 | cmd_SetTheme_SolarLight, 68 | cmd_SetTheme_GruvboxLight, 69 | cmd_SetTheme_TaoLight, 70 | cmd_SetTheme_Flatwhite, 71 | cmd_SetTheme_RelationalPipes, 72 | cmd_SetTheme_PaperColor, 73 | cmd_SetTheme, 74 | cmd_SetCustomTheme, 75 | cmd_SaveSetup, 76 | 77 | cmd_Escape, 78 | cmd_Quit, 79 | cmd_RawOutputQuit, 80 | cmd_ShowMenu, 81 | cmd_FlushBookmarks, 82 | cmd_ToggleBookmark, 83 | cmd_PrevBookmark, 84 | cmd_NextBookmark, 85 | cmd_CursorUp, 86 | cmd_CursorDown, 87 | cmd_ScrollUp, 88 | cmd_ScrollDown, 89 | cmd_ScrollUpHalfPage, 90 | cmd_ScrollDownHalfPage, 91 | cmd_MoveLeft, 92 | cmd_MoveRight, 93 | cmd_MoveCharLeft, 94 | cmd_MoveCharRight, 95 | cmd_MoveColumnLeft, 96 | cmd_MoveColumnRight, 97 | cmd_CursorFirstRow, 98 | cmd_CursorLastRow, 99 | cmd_CursorFirstRowPage, 100 | cmd_CursorLastRowPage, 101 | cmd_CursorHalfPage, 102 | cmd_PageUp, 103 | cmd_PageDown, 104 | cmd_ShowFirstCol, 105 | cmd_ShowLastCol, 106 | cmd_SaveData, 107 | cmd_SaveAsCSV, 108 | cmd_ForwardSearch, 109 | cmd_BackwardSearch, 110 | cmd_ForwardSearchInSelection, 111 | cmd_BackwardSearchInSelection, 112 | cmd_SearchNext, 113 | cmd_SearchPrev, 114 | cmd_SearchColumn, 115 | cmd_ShowTopBar, 116 | cmd_ShowBottomBar, 117 | cmd_RowNumToggle, 118 | cmd_GotoLine, 119 | cmd_GotoLineRel, 120 | cmd_ShowCursor, 121 | cmd_ShowVerticalCursor, 122 | cmd_BoldLabelsToggle, 123 | cmd_BoldCursorToggle, 124 | cmd_ShowScrollbar, 125 | cmd_SortAsc, 126 | cmd_SortDesc, 127 | cmd_OriginalSort, 128 | cmd_TogglePause, 129 | cmd_Refresh, 130 | cmd_SetCopyFile, 131 | cmd_SetCopyClipboard, 132 | cmd_UseClipboard_CSV, 133 | cmd_UseClipboard_TSVC, 134 | cmd_UseClipboard_SQL_values, 135 | cmd_UseClipboard_text, 136 | cmd_UseClipboard_pipe_separated, 137 | cmd_UseClipboard_INSERT, 138 | cmd_UseClipboard_INSERT_with_comments, 139 | cmd_TogleEmptyStringIsNULL, 140 | cmd_SetOwnNULLString, 141 | 142 | cmd_Copy, 143 | cmd_CopyAllLines, 144 | cmd_CopyTopLines, 145 | cmd_CopyBottomLines, 146 | cmd_CopyLine, 147 | cmd_CopyLineExtended, 148 | cmd_CopyColumn, 149 | cmd_CopyMarkedLines, 150 | cmd_CopySearchedLines, 151 | cmd_CopySelected, 152 | 153 | cmd_Mark, 154 | cmd_MarkColumn, 155 | cmd_MarkAll, 156 | cmd_Unmark, 157 | cmd_Mark_NestedCursorCommand, 158 | 159 | cmd_BsCommand, 160 | cmd_ShowPrimaryScreen, 161 | cmd_ToggleHighlightOddRec, 162 | cmd_ToggleHideHeaderLine, 163 | } PspgCommand; 164 | 165 | extern void initialize_special_keycodes(); 166 | extern const char *cmd_string(int cmd); 167 | extern int translate_event(int c, bool alt, Options *opts, int *nested_command); 168 | extern bool require_complete_load(int cmd); 169 | 170 | extern bool is_cmd_RowNumToggle(int c, bool alt); 171 | extern bool key_is_allowed_mark_mode_cursor(int c); 172 | 173 | 174 | extern int cmd_get_theme(int cmd); 175 | extern int theme_get_cmd(int theme); 176 | 177 | #endif 178 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * config.c 4 | * a routines for loading, saving configuration 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/config.c 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | #include "pspg.h" 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static int 25 | parse_cfg(char *line, char *key, bool *bool_val, int *int_val, char **str_val) 26 | { 27 | int key_length = 0; 28 | int len = strlen(line); 29 | 30 | if (len > 0 && line[len - 1] == '\n') 31 | line[len-1] = '\0'; 32 | 33 | /* skip initial spaces */ 34 | while (*line == ' ') 35 | line++; 36 | 37 | /* skip comments */ 38 | if (*line == '#') 39 | return 0; 40 | 41 | /* copy key to key array */ 42 | while (*line != ' ' && *line != '=' && *line != '\0') 43 | { 44 | if (key_length < 99) 45 | { 46 | key[key_length++] = *line++; 47 | } 48 | else 49 | break; 50 | } 51 | 52 | key[key_length] = '\0'; 53 | 54 | /* search '=' */ 55 | while (*line != '=' && *line != '\0') 56 | line++; 57 | 58 | if (key_length > 0 && *line == '=') 59 | { 60 | line += 1; 61 | 62 | /* skip spaces */ 63 | while (*line == ' ') 64 | line++; 65 | 66 | if (*line == '-' || (*line >= '0' && *line <= '9')) 67 | { 68 | *int_val = atoi(line); 69 | return 1; 70 | } 71 | else if (strncmp(line, "true", 4) == 0) 72 | { 73 | *bool_val = true; 74 | return 2; 75 | } 76 | else if (strncmp(line, "false", 5) == 0) 77 | { 78 | *bool_val = false; 79 | return 2; 80 | } 81 | else 82 | { 83 | int size; 84 | char *str; 85 | 86 | size = strlen(line); 87 | str = trim_quoted_str(line, &size); 88 | *str_val = str ? sstrndup(str, size) : NULL; 89 | return 3; 90 | } 91 | } 92 | 93 | if (key_length > 0) 94 | return -1; 95 | 96 | return 0; 97 | } 98 | 99 | #define SAFE_SAVE_BOOL_OPTION(name, opt) \ 100 | do { \ 101 | result = fprintf(f, "%s = %s\n", (name), (opt) ? "true" : "false"); \ 102 | if (result < 0) \ 103 | return false; \ 104 | } while (0) 105 | 106 | bool 107 | save_config(char *path, Options *opts) 108 | { 109 | FILE *f; 110 | int result; 111 | 112 | errno = 0; 113 | f = fopen(path, "w"); 114 | if (f == NULL) 115 | return false; 116 | 117 | if (chmod(path, 0644) != 0) 118 | { 119 | fclose(f); 120 | return false; 121 | } 122 | 123 | SAFE_SAVE_BOOL_OPTION("ascii_menu", opts->force_ascii_art); 124 | SAFE_SAVE_BOOL_OPTION("bold_labels", opts->bold_labels); 125 | SAFE_SAVE_BOOL_OPTION("bold_cursor", opts->bold_cursor); 126 | SAFE_SAVE_BOOL_OPTION("ignore_case", opts->ignore_case); 127 | SAFE_SAVE_BOOL_OPTION("ignore_lower_case", opts->ignore_lower_case); 128 | SAFE_SAVE_BOOL_OPTION("no_cursor", opts->no_cursor); 129 | SAFE_SAVE_BOOL_OPTION("no_sound", quiet_mode); 130 | SAFE_SAVE_BOOL_OPTION("no_mouse", opts->no_mouse); 131 | SAFE_SAVE_BOOL_OPTION("less_status_bar", opts->less_status_bar); 132 | SAFE_SAVE_BOOL_OPTION("no_highlight_search", opts->no_highlight_search); 133 | SAFE_SAVE_BOOL_OPTION("no_highlight_lines", opts->no_highlight_lines); 134 | SAFE_SAVE_BOOL_OPTION("force_uniborder", opts->force_uniborder); 135 | SAFE_SAVE_BOOL_OPTION("show_rownum", opts->show_rownum); 136 | SAFE_SAVE_BOOL_OPTION("without_commandbar", opts->no_commandbar); 137 | SAFE_SAVE_BOOL_OPTION("without_topbar", opts->no_topbar); 138 | SAFE_SAVE_BOOL_OPTION("vertical_cursor", opts->vertical_cursor); 139 | SAFE_SAVE_BOOL_OPTION("on_sigint_exit", opts->on_sigint_exit); 140 | SAFE_SAVE_BOOL_OPTION("no_sigint_search_reset", opts->no_sigint_search_reset); 141 | SAFE_SAVE_BOOL_OPTION("double_header", opts->double_header); 142 | SAFE_SAVE_BOOL_OPTION("quit_on_f3", opts->quit_on_f3); 143 | SAFE_SAVE_BOOL_OPTION("pgcli_fix", opts->pgcli_fix); 144 | SAFE_SAVE_BOOL_OPTION("xterm_mouse_mode", opts->xterm_mouse_mode); 145 | SAFE_SAVE_BOOL_OPTION("show_scrollbar", opts->show_scrollbar); 146 | SAFE_SAVE_BOOL_OPTION("menu_always", opts->menu_always); 147 | SAFE_SAVE_BOOL_OPTION("empty_string_is_null", opts->empty_string_is_null); 148 | SAFE_SAVE_BOOL_OPTION("last_row_search", opts->last_row_search); 149 | SAFE_SAVE_BOOL_OPTION("progressive_load_mode", opts->progressive_load_mode); 150 | SAFE_SAVE_BOOL_OPTION("highlight_odd_rec", opts->highlight_odd_rec); 151 | SAFE_SAVE_BOOL_OPTION("hide_header_line", opts->hide_header_line); 152 | SAFE_SAVE_BOOL_OPTION("on_exit_reset", opts->on_exit_reset); 153 | SAFE_SAVE_BOOL_OPTION("on_exit_clean", opts->on_exit_clean); 154 | SAFE_SAVE_BOOL_OPTION("on_exit_erase_line", opts->on_exit_erase_line); 155 | SAFE_SAVE_BOOL_OPTION("on_exit_sgr0", opts->on_exit_sgr0); 156 | SAFE_SAVE_BOOL_OPTION("direct_color", opts->direct_color); 157 | 158 | result = fprintf(f, "theme = %d\n", opts->theme); 159 | if (result < 0) 160 | return false; 161 | 162 | result = fprintf(f, "border_type = %d\n", opts->border_type); 163 | if (result < 0) 164 | return false; 165 | 166 | result = fprintf(f, "default_clipboard_format = %d\n", opts->clipboard_format); 167 | if (result < 0) 168 | return false; 169 | 170 | result = fprintf(f, "clipboard_app = %d\n", opts->clipboard_app); 171 | if (result < 0) 172 | return false; 173 | 174 | result = fprintf(f, "hist_size = %d\n", opts->hist_size); 175 | if (result < 0) 176 | return false; 177 | 178 | if (opts->nullstr) 179 | { 180 | result = fprintf(f, "nullstr = \"%s\"\n", opts->nullstr); 181 | if (result < 0) 182 | return false; 183 | } 184 | 185 | if (opts->custom_theme_name) 186 | { 187 | result = fprintf(f, "custom_theme_name = \"%s\"\n", opts->custom_theme_name); 188 | if (result < 0) 189 | return false; 190 | } 191 | 192 | result = fprintf(f, "esc_delay = %d\n", opts->esc_delay); 193 | if (result < 0) 194 | return false; 195 | 196 | result = fclose(f); 197 | if (result != 0) 198 | return false; 199 | 200 | return true; 201 | } 202 | 203 | static bool 204 | assign_bool(char *key, bool *target, bool value, int type) 205 | { 206 | if (type != 2) 207 | { 208 | log_row("The value of key \"%s\" is not boolean value", key); 209 | return false; 210 | } 211 | 212 | *target = value; 213 | 214 | return true; 215 | } 216 | 217 | static bool 218 | assign_int(char *key, int *target, int value, int type, int min, int max) 219 | { 220 | if (type != 1) 221 | { 222 | log_row("The value of key \"%s\" is not integer value", key); 223 | return false; 224 | } 225 | 226 | if (value < min && value > max) 227 | { 228 | log_row("value of key \"%s\" is out of range [%d, %d]", key, min, max); 229 | return false; 230 | } 231 | 232 | *target = value; 233 | 234 | return true; 235 | } 236 | 237 | static bool 238 | assign_str(char *key, char **target, char *value, int type) 239 | { 240 | if (type != 3) 241 | { 242 | log_row("The value of key \"%s\" is not string value", key); 243 | return false; 244 | } 245 | 246 | *target = value; 247 | 248 | return true; 249 | } 250 | 251 | /* 252 | * Simple parser of config file. I don't expect too much fields, so performance is 253 | * not significant. 254 | */ 255 | bool 256 | load_config(char *path, Options *opts) 257 | { 258 | FILE *f; 259 | char *line = NULL; 260 | ssize_t read; 261 | size_t len; 262 | bool is_valid = true; 263 | 264 | errno = 0; 265 | f = fopen(path, "r"); 266 | if (f == NULL) 267 | return false; 268 | 269 | while ((read = getline(&line, &len, f)) != -1) 270 | { 271 | char key[100]; 272 | bool bool_val = false; 273 | int int_val = -1; 274 | char *str_val = NULL; 275 | int res; 276 | 277 | if ((res = parse_cfg(line, key, &bool_val, &int_val, &str_val)) > 0) 278 | { 279 | if (strcmp(key, "ascii_menu") == 0) 280 | is_valid = assign_bool(key, &opts->force_ascii_art, bool_val, res); 281 | else if (strcmp(key, "bold_labels") == 0) 282 | is_valid = assign_bool(key, &opts->bold_labels, bool_val, res); 283 | else if (strcmp(key, "bold_cursor") == 0) 284 | is_valid = assign_bool(key, &opts->bold_cursor, bool_val, res); 285 | else if (strcmp(key, "ignore_case") == 0) 286 | is_valid = assign_bool(key, &opts->ignore_case, bool_val, res); 287 | else if (strcmp(key, "ignore_lower_case") == 0) 288 | is_valid = assign_bool(key, &opts->ignore_lower_case, bool_val, res); 289 | else if (strcmp(key, "no_sound") == 0) 290 | is_valid = assign_bool(key, &quiet_mode, bool_val, res); 291 | else if (strcmp(key, "no_cursor") == 0) 292 | is_valid = assign_bool(key, &opts->no_cursor, bool_val, res); 293 | else if (strcmp(key, "no_mouse") == 0) 294 | is_valid = assign_bool(key, &opts->no_mouse, bool_val, res); 295 | else if (strcmp(key, "less_status_bar") == 0) 296 | is_valid = assign_bool(key, &opts->less_status_bar, bool_val, res); 297 | else if (strcmp(key, "no_highlight_search") == 0) 298 | is_valid = assign_bool(key, &opts->no_highlight_search, bool_val, res); 299 | else if (strcmp(key, "no_highlight_lines") == 0) 300 | is_valid = assign_bool(key, &opts->no_highlight_lines, bool_val, res); 301 | else if (strcmp(key, "force_uniborder") == 0) 302 | is_valid = assign_bool(key, &opts->force_uniborder, bool_val, res); 303 | else if (strcmp(key, "show_rownum") == 0) 304 | is_valid = assign_bool(key, &opts->show_rownum, bool_val, res); 305 | else if (strcmp(key, "theme") == 0) 306 | is_valid = assign_int(key, &opts->theme, int_val, res, 0, MAX_STYLE); 307 | else if (strcmp(key, "without_commandbar") == 0) 308 | is_valid = assign_bool(key, &opts->no_commandbar, bool_val, res); 309 | else if (strcmp(key, "without_topbar") == 0) 310 | is_valid = assign_bool(key, &opts->no_topbar, bool_val, res); 311 | else if (strcmp(key, "vertical_cursor") == 0) 312 | is_valid = assign_bool(key, &opts->vertical_cursor, bool_val, res); 313 | else if (strcmp(key, "border_type") == 0) 314 | is_valid = assign_int(key, &opts->border_type, int_val, res, 0, 2); 315 | else if (strcmp(key, "double_header") == 0) 316 | is_valid = assign_bool(key, &opts->double_header, bool_val, res); 317 | else if (strcmp(key, "on_sigint_exit") == 0) 318 | is_valid = assign_bool(key, &opts->on_sigint_exit, bool_val, res); 319 | else if (strcmp(key, "no_sigint_search_reset") == 0) 320 | is_valid = assign_bool(key, &opts->no_sigint_search_reset, bool_val, res); 321 | else if (strcmp(key, "quit_on_f3") == 0) 322 | is_valid = assign_bool(key, &opts->quit_on_f3, bool_val, res); 323 | else if (strcmp(key, "pgcli_fix") == 0) 324 | is_valid = assign_bool(key, &opts->pgcli_fix, bool_val, res); 325 | else if (strcmp(key, "default_clipboard_format") == 0) 326 | is_valid = assign_int(key, (int *) &opts->clipboard_format, int_val, res, 0, CLIPBOARD_FORMAT_INSERT_WITH_COMMENTS); 327 | else if (strcmp(key, "clipboard_app") == 0) 328 | is_valid = assign_int(key, &opts->clipboard_app, int_val, res, 0, 3); 329 | else if (strcmp(key, "xterm_mouse_mode") == 0) 330 | is_valid = assign_bool(key, &opts->xterm_mouse_mode, bool_val, res); 331 | else if (strcmp(key, "show_scrollbar") == 0) 332 | is_valid = assign_bool(key, &opts->show_scrollbar, bool_val, res); 333 | else if (strcmp(key, "menu_always") == 0) 334 | is_valid = assign_bool(key, &opts->menu_always, bool_val, res); 335 | else if (strcmp(key, "nullstr") == 0) 336 | is_valid = assign_str(key, &opts->nullstr, str_val, res); 337 | else if (strcmp(key, "empty_string_is_null") == 0) 338 | is_valid = assign_bool(key, &opts->empty_string_is_null, bool_val, res); 339 | else if (strcmp(key, "last_row_search") == 0) 340 | is_valid = assign_bool(key, &opts->last_row_search, bool_val, res); 341 | else if (strcmp(key, "hist_size") == 0) 342 | is_valid = assign_int(key, (int *) &opts->hist_size, int_val, res, 0, INT_MAX); 343 | else if (strcmp(key, "progressive_load_mode") == 0) 344 | is_valid = assign_bool(key, &opts->progressive_load_mode, bool_val, res); 345 | else if (strcmp(key, "custom_theme_name") == 0) 346 | is_valid = assign_str(key, &opts->custom_theme_name, str_val, res); 347 | else if (strcmp(key, "highlight_odd_rec") == 0) 348 | is_valid = assign_bool(key, &opts->highlight_odd_rec, bool_val, res); 349 | else if (strcmp(key, "hide_header_line") == 0) 350 | is_valid = assign_bool(key, &opts->hide_header_line, bool_val, res); 351 | else if (strcmp(key, "esc_delay") == 0) 352 | is_valid = assign_int(key, &opts->esc_delay, int_val, res, -1, INT_MAX); 353 | else if (strcmp(key, "on_exit_reset") == 0) 354 | is_valid = assign_bool(key, &opts->on_exit_reset, bool_val, res); 355 | else if (strcmp(key, "on_exit_clean") == 0) 356 | is_valid = assign_bool(key, &opts->on_exit_clean, bool_val, res); 357 | else if (strcmp(key, "on_exit_erase_line") == 0) 358 | is_valid = assign_bool(key, &opts->on_exit_erase_line, bool_val, res); 359 | else if (strcmp(key, "on_exit_sgr0") == 0) 360 | is_valid = assign_bool(key, &opts->on_exit_sgr0, bool_val, res); 361 | else if (strcmp(key, "direct_color") == 0) 362 | is_valid = assign_bool(key, &opts->direct_color, bool_val, res); 363 | } 364 | 365 | if (!is_valid || res == -1) 366 | break; 367 | } 368 | 369 | free(line); 370 | 371 | fclose(f); 372 | 373 | return is_valid; 374 | } 375 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * config.h 4 | * load/save configuration 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/config.h 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #ifndef PSPG_CONFIG_H 15 | #define PSPG_CONFIG_H 16 | 17 | #include 18 | 19 | #define MAX_STYLE 23 20 | 21 | typedef enum 22 | { 23 | CLIPBOARD_FORMAT_CSV, 24 | CLIPBOARD_FORMAT_TSVC, 25 | CLIPBOARD_FORMAT_TEXT, 26 | CLIPBOARD_FORMAT_PIPE_SEPARATED, 27 | CLIPBOARD_FORMAT_SQL_VALUES, 28 | CLIPBOARD_FORMAT_INSERT, 29 | CLIPBOARD_FORMAT_INSERT_WITH_COMMENTS 30 | } ClipboardFormat; 31 | 32 | #define DSV_FORMAT_TYPE(f) (f == CLIPBOARD_FORMAT_CSV || f == CLIPBOARD_FORMAT_TSVC || f == CLIPBOARD_FORMAT_SQL_VALUES) 33 | #define INSERT_FORMAT_TYPE(f) (f == CLIPBOARD_FORMAT_INSERT || f == CLIPBOARD_FORMAT_INSERT_WITH_COMMENTS) 34 | 35 | typedef enum 36 | { 37 | COPY_TARGET_FILE, 38 | COPY_TARGET_CLIPBOARD 39 | } CopyTarget; 40 | 41 | typedef struct 42 | { 43 | char *pathname; 44 | char *log_pathname; 45 | bool ignore_case; 46 | bool ignore_lower_case; 47 | bool no_mouse; 48 | bool less_status_bar; 49 | bool no_highlight_search; 50 | bool no_highlight_lines; 51 | bool force_uniborder; 52 | bool no_commandbar; 53 | bool no_topbar; 54 | bool show_rownum; 55 | bool no_cursor; 56 | bool vertical_cursor; 57 | bool show_scrollbar; 58 | bool tabular_cursor; 59 | bool force_ascii_art; 60 | int theme; 61 | int freezed_cols; 62 | bool bold_labels; 63 | bool bold_cursor; 64 | bool tsv_format; 65 | bool csv_format; 66 | char csv_separator; 67 | char csv_header; /* a - auto, - off, + on */ 68 | unsigned int csv_trim_width; 69 | unsigned int csv_trim_rows; 70 | char *nullstr; 71 | char *csv_skip_columns_like; 72 | bool ignore_short_rows; 73 | bool pgcli_fix; /* hints for using from pgcli */ 74 | bool double_header; 75 | int border_type; 76 | bool on_sigint_exit; 77 | bool no_sigint_search_reset; 78 | char *query; 79 | int watch_time; 80 | char *host; 81 | char *username; 82 | char *port; 83 | bool force_password_prompt; 84 | char *password; 85 | char *dbname; 86 | bool watch_file; 87 | bool quit_on_f3; 88 | ClipboardFormat clipboard_format; 89 | CopyTarget copy_target; 90 | bool empty_string_is_null; 91 | bool xterm_mouse_mode; 92 | int clipboard_app; 93 | bool no_sleep; 94 | bool querystream; 95 | bool menu_always; 96 | bool last_row_search; 97 | int hist_size; 98 | bool progressive_load_mode; 99 | char *custom_theme_name; 100 | bool highlight_odd_rec; 101 | bool hide_header_line; 102 | int esc_delay; 103 | bool on_exit_clean; 104 | bool on_exit_reset; 105 | bool on_exit_erase_line; 106 | bool on_exit_sgr0; 107 | bool direct_color; 108 | } Options; 109 | 110 | extern bool save_config(char *path, Options *opts); 111 | extern bool load_config(char *path, Options *opts); 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/infra.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * infra.c 4 | * a routines for build a infrastructure 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/infra.c 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "pspg.h" 22 | #include "unicode.h" 23 | 24 | FILE *logfile = NULL; 25 | 26 | /* 27 | * Print entry to log file 28 | */ 29 | static void 30 | print_log_prefix(void) 31 | { 32 | time_t rawtime; 33 | struct tm *timeinfo; 34 | char outstr[200]; 35 | 36 | time(&rawtime); 37 | timeinfo = localtime(&rawtime); 38 | 39 | strftime(outstr, sizeof(outstr), "%a, %d %b %Y %T %z", timeinfo); 40 | 41 | fprintf(logfile, "%s [%ld] ", outstr, (long) getpid()); 42 | } 43 | 44 | void 45 | log_row(const char *fmt, ...) 46 | { 47 | va_list args; 48 | 49 | if (logfile) 50 | { 51 | print_log_prefix(); 52 | 53 | va_start(args, fmt); 54 | vfprintf(logfile, fmt, args); 55 | va_end(args); 56 | 57 | fputc('\n', logfile); 58 | } 59 | 60 | #ifdef DEBUG_PIPE 61 | 62 | if (debug_pipe) 63 | { 64 | va_start(args, fmt); 65 | vfprintf(debug_pipe, fmt, args); 66 | va_end(args); 67 | 68 | fputc('\n', debug_pipe); 69 | } 70 | 71 | #endif 72 | 73 | } 74 | 75 | void 76 | leave(const char *fmt, ...) 77 | { 78 | va_list args; 79 | 80 | /* close ncurses and input streams */ 81 | exit_handler(); 82 | 83 | if (!fmt) 84 | { 85 | if (logfile) 86 | { 87 | fclose(logfile); 88 | logfile = NULL; 89 | } 90 | 91 | exit(EXIT_FAILURE); 92 | } 93 | 94 | va_start(args, fmt); 95 | vfprintf(stderr, fmt, args); 96 | va_end(args); 97 | 98 | fputc('\n', stderr); 99 | 100 | if (logfile) 101 | { 102 | print_log_prefix(); 103 | 104 | va_start(args, fmt); 105 | vfprintf(logfile, fmt, args); 106 | va_end(args); 107 | 108 | fputc('\n', logfile); 109 | 110 | fclose(logfile); 111 | logfile = NULL; 112 | } 113 | 114 | #ifdef DEBUG_PIPE 115 | 116 | va_start(args, fmt); 117 | vfprintf(debug_pipe, fmt, args); 118 | va_end(args); 119 | 120 | fputc('\n', debug_pipe); 121 | 122 | #endif 123 | 124 | exit(EXIT_FAILURE); 125 | } 126 | 127 | void 128 | format_error(const char *fmt, ...) 129 | { 130 | va_list args; 131 | char *ptr; 132 | 133 | if (!current_state) 134 | leave("current_state is not initialized"); 135 | 136 | va_start(args, fmt); 137 | vsnprintf(pspg_errstr_buffer, PSPG_ERRSTR_BUFFER_SIZE, fmt, args); 138 | va_end(args); 139 | 140 | current_state->errstr = pspg_errstr_buffer; 141 | 142 | /* throw multilines strings */ 143 | for (ptr = pspg_errstr_buffer; *ptr; ptr++) 144 | { 145 | if (*ptr == '\n') 146 | { 147 | *ptr = '\0'; 148 | break; 149 | } 150 | } 151 | } 152 | 153 | /* 154 | * Safe memory operation. 155 | */ 156 | void * 157 | smalloc(int size) 158 | { 159 | void *result; 160 | 161 | result = malloc(size); 162 | 163 | if (!result) 164 | leave("out of memory"); 165 | 166 | memset(result, 0, size); 167 | 168 | return result; 169 | } 170 | 171 | void * 172 | srealloc(void *ptr, int size) 173 | { 174 | void *result; 175 | 176 | result = realloc(ptr, size); 177 | 178 | if (!result) 179 | leave("out of memory"); 180 | 181 | return result; 182 | } 183 | 184 | void * 185 | smalloc2(int size, char *debugstr) 186 | { 187 | void *result; 188 | 189 | result = malloc(size); 190 | if (!result) 191 | leave("out of memory while %s", debugstr); 192 | 193 | memset(result, 0, size); 194 | 195 | return result; 196 | } 197 | 198 | char * 199 | sstrdup(const char *str) 200 | { 201 | char *result = strdup(str); 202 | 203 | if (!result) 204 | leave("out of memory"); 205 | 206 | return result; 207 | } 208 | 209 | char * 210 | sstrdup2(const char *str, char *debugstr) 211 | { 212 | char *result = strdup(str); 213 | 214 | if (!result) 215 | leave("out of memory while %s", debugstr); 216 | 217 | return result; 218 | } 219 | 220 | char * 221 | sstrndup(const char *str, int bytes) 222 | { 223 | char *result, *ptr; 224 | 225 | result = ptr = smalloc(bytes + 1); 226 | 227 | while (*str && bytes-- > 0) 228 | *ptr++ = *str++; 229 | 230 | *ptr = '\0'; 231 | 232 | return result; 233 | } 234 | 235 | /* 236 | * Returns byte size of first char of string 237 | */ 238 | inline int 239 | charlen(const char *str) 240 | { 241 | return use_utf8 ? utf8charlen(*str) : 1; 242 | } 243 | 244 | inline int 245 | dsplen(const char *str) 246 | { 247 | return *str == ' ' ? 1 : (use_utf8 ? utf_dsplen(str) : 1); 248 | } 249 | 250 | /* 251 | * truncate spaces from both ends 252 | */ 253 | char * 254 | trim_str(const char *str, int *size) 255 | { 256 | char *result = NULL; 257 | int bytes = *size; 258 | 259 | while (*str == ' ' && bytes > 0) 260 | { 261 | str += 1; 262 | bytes -= 1; 263 | } 264 | 265 | if (bytes > 0) 266 | { 267 | const char *after_nspc_chr = NULL; 268 | 269 | result = (char *) str; 270 | 271 | while (bytes > 0) 272 | { 273 | int chrlen = charlen(str); 274 | 275 | if (*str != ' ') 276 | after_nspc_chr = str + chrlen; 277 | 278 | str = str + chrlen; 279 | bytes -= chrlen; 280 | } 281 | 282 | *size = after_nspc_chr - result; 283 | } 284 | else 285 | *size = 0; 286 | 287 | return result; 288 | } 289 | 290 | /* 291 | * truncate spaces from both ends, support quotes and double quotes 292 | */ 293 | char * 294 | trim_quoted_str(const char *str, int *size) 295 | { 296 | char *result; 297 | 298 | result = trim_str(str, size); 299 | 300 | /* check first and last char */ 301 | if (*size > 0) 302 | { 303 | if (*result == '"' || *result == '\'') 304 | { 305 | if (*result == *(result + *size - 1)) 306 | { 307 | result += 1; 308 | *size -= 2; 309 | } 310 | } 311 | } 312 | 313 | return result; 314 | } 315 | 316 | /* 317 | * Few simple functions for string concatetion 318 | */ 319 | void 320 | InitExtStr(ExtStr *estr) 321 | { 322 | estr->len = 0; 323 | estr->maxlen = 1024; 324 | estr->data = smalloc(estr->maxlen); 325 | *estr->data = '\0'; 326 | } 327 | 328 | void 329 | ResetExtStr(ExtStr *estr) 330 | { 331 | estr->len = 0; 332 | 333 | /* 334 | * Because the content self is still used, we should not to push 335 | * ending zero there. 336 | * DONT DO THIS *estr->data = '\0'; 337 | */ 338 | } 339 | 340 | void 341 | ExtStrAppendNewLine(ExtStr *estr, char *str) 342 | { 343 | int size = strlen(str); 344 | 345 | if (estr->len + size + 2 > estr->maxlen) 346 | { 347 | while (estr->len + size + 2 > estr->maxlen) 348 | estr->maxlen += 1024; 349 | 350 | estr->data = srealloc(estr->data, estr->maxlen); 351 | } 352 | 353 | if (estr->len > 0) 354 | estr->data[estr->len++] = '\n'; 355 | 356 | strncpy(&estr->data[estr->len], str, size + 1); 357 | estr->len += size; 358 | } 359 | 360 | /* 361 | * continuation_mark is related to new line symbol in text. 362 | * continuation_mark is related to line break created by 363 | * wrapped mode. continuation_mark2 is equal to previous 364 | * continuous_mark 365 | */ 366 | void 367 | ExtStrAppendLine(ExtStr *estr, 368 | char *str, 369 | int size, 370 | char linestyle, 371 | bool continuation_mark, 372 | bool continuation_mark2) 373 | { 374 | bool insert_nl = false; 375 | 376 | str = trim_str(str, &size); 377 | 378 | if (size == 0) 379 | return; 380 | 381 | if (continuation_mark) 382 | { 383 | int continuation_mark_size = 0; 384 | bool wrapped_mode = false; 385 | 386 | /* try to detect continuation marks at end of line */ 387 | if (linestyle == 'a') 388 | { 389 | if (str[size - 1] == '+') 390 | { 391 | continuation_mark_size = 1; 392 | insert_nl = true; 393 | } 394 | else if (str[size - 1] == '.') 395 | { 396 | continuation_mark_size = 1; 397 | wrapped_mode = true; 398 | } 399 | } 400 | else 401 | { 402 | 403 | if (size > 3) 404 | { 405 | const char *u1 = "\342\206\265"; /* ↵ */ 406 | const char *u2 = "\342\200\246"; /* … */ 407 | char *ptr = str + size - 3; 408 | 409 | if (strncmp(ptr, u1, 3) == 0) 410 | { 411 | continuation_mark_size = 3; 412 | insert_nl = true; 413 | } 414 | else if (strncmp(ptr, u2, 3) == 0) 415 | { 416 | continuation_mark_size = 3; 417 | wrapped_mode = true; 418 | } 419 | } 420 | } 421 | 422 | if (continuation_mark_size > 0) 423 | { 424 | size -= continuation_mark_size; 425 | 426 | /* 427 | * Trimming right end of string can eats spaces. In normal mode, it 428 | * should not be problem, because there is new line symbol, but in 429 | * wrapped mode we can trim space that is used as word separator. 430 | * So don't trim in wrapped mode. 431 | */ 432 | if (!wrapped_mode) 433 | str = trim_str(str, &size); 434 | } 435 | } 436 | 437 | /* 438 | * continuation mark can be on left side to (wrapped mode). 439 | * We should to skip it. 440 | */ 441 | if (continuation_mark2) 442 | { 443 | int cms = 0; /* continuation mark size */ 444 | 445 | if (linestyle == 'a') 446 | { 447 | if (*str == '.') 448 | cms = 1; 449 | } 450 | else 451 | { 452 | if (size > 3) 453 | { 454 | const char *u1 = "\342\200\246"; /* … */ 455 | 456 | if (strncmp(str, u1, 3) == 0) 457 | cms = 3; 458 | } 459 | } 460 | 461 | if (cms > 0) 462 | { 463 | str += cms; 464 | size -= cms; 465 | } 466 | } 467 | 468 | if (estr->len + size + 2 > estr->maxlen) 469 | { 470 | while (estr->len + size + 2 > estr->maxlen) 471 | estr->maxlen += 1024; 472 | 473 | estr->data = srealloc(estr->data, estr->maxlen); 474 | } 475 | 476 | strncpy(&estr->data[estr->len], str, size); 477 | estr->len += size; 478 | 479 | if (insert_nl) 480 | estr->data[estr->len++] = '\n'; 481 | 482 | estr->data[estr->len] = '\0'; 483 | } 484 | 485 | int 486 | ExtStrTrimEnd(ExtStr *estr, bool replace_nl) 487 | { 488 | char *ptr; 489 | char *last_nonwhite = NULL; 490 | 491 | ptr = estr->data; 492 | 493 | while (*ptr) 494 | { 495 | if (*ptr != ' ' && *ptr != '\n') 496 | last_nonwhite = ptr; 497 | 498 | if (*ptr == '\n' && replace_nl) 499 | *ptr = ' '; 500 | 501 | ptr += charlen(ptr); 502 | } 503 | 504 | if (last_nonwhite) 505 | { 506 | estr->len = last_nonwhite - estr->data + 1; 507 | estr->data[estr->len] = '\0'; 508 | } 509 | else 510 | ResetExtStr(estr); 511 | 512 | return estr->len; 513 | } 514 | 515 | /* 516 | * read write stderr poopen function 517 | */ 518 | int 519 | rwe_popen(char *command, int *fin, int *fout, int *ferr) 520 | { 521 | int in[2]; 522 | int out[2]; 523 | int err[2]; 524 | int rc; 525 | int saved_errno; 526 | 527 | errno = 0; 528 | saved_errno = 0; 529 | 530 | rc = pipe(in); 531 | if (rc == 0) 532 | { 533 | rc = pipe(out); 534 | if (rc == 0) 535 | { 536 | rc = pipe(err); 537 | if (rc == 0) 538 | { 539 | int pid = fork(); 540 | 541 | if (pid > 0) 542 | { 543 | /* parent */ 544 | close(in[0]); 545 | close(out[1]); 546 | close(err[1]); 547 | 548 | *fin = in[1]; 549 | *fout = out[0]; 550 | *ferr = err[0]; 551 | 552 | return pid; 553 | } 554 | else if (pid == 0) 555 | { 556 | /* child */ 557 | close(in[1]); 558 | close(out[0]); 559 | close(err[0]); 560 | 561 | dup2(in[0], 0); 562 | dup2(out[1], 1); 563 | dup2(err[1], 2); 564 | 565 | close(in[0]); 566 | close(out[1]); 567 | close(err[1]); 568 | 569 | execl("/bin/sh", "sh", "-c", command, NULL); 570 | exit(127); 571 | } 572 | else 573 | saved_errno = errno; 574 | 575 | close(err[0]); 576 | close(err[1]); 577 | } 578 | else 579 | saved_errno = errno; 580 | 581 | close(out[0]); 582 | close(out[1]); 583 | } 584 | else 585 | saved_errno = errno; 586 | 587 | close(in[0]); 588 | close(out[1]); 589 | } 590 | else 591 | saved_errno = errno; 592 | 593 | errno = saved_errno; 594 | 595 | return -1; 596 | } 597 | 598 | /* 599 | * Replace tilde by HOME dir 600 | */ 601 | char * 602 | tilde(char *dest, const char *path) 603 | { 604 | static char buffer[MAXPATHLEN]; 605 | 606 | int chars = 0; 607 | char *w; 608 | 609 | if (!dest) 610 | dest = buffer; 611 | 612 | w = dest; 613 | 614 | while (*path && chars < MAXPATHLEN - 1) 615 | { 616 | if (*path == '~') 617 | { 618 | char *home = getenv("HOME"); 619 | 620 | if (home == NULL) 621 | leave("HOME directory is not defined"); 622 | 623 | while (*home && chars < MAXPATHLEN - 1) 624 | { 625 | *w++ = *home++; 626 | chars += 1; 627 | } 628 | path++; 629 | } 630 | else 631 | { 632 | *w++ = *path++; 633 | chars += 1; 634 | } 635 | } 636 | 637 | *w = '\0'; 638 | 639 | return dest; 640 | } 641 | -------------------------------------------------------------------------------- /src/inputs.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * inputs.h 4 | * generic processing of input 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/inputs.h 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #ifndef PSPG_INPUT_H 15 | #define PSPG_INPUT_H 16 | 17 | #if defined HAVE_NCURSESW_CURSES_H 18 | #include 19 | #elif defined HAVE_NCURSESW_H 20 | #include 21 | #elif defined HAVE_NCURSES_CURSES_H 22 | #include 23 | #elif defined HAVE_NCURSES_H 24 | #include 25 | #elif defined HAVE_CURSES_H 26 | #include 27 | #else 28 | /* fallback */ 29 | #include 30 | #endif 31 | 32 | #include "pspg.h" 33 | 34 | /* 35 | * NCurses event - hold all data of ncurses event 36 | */ 37 | typedef struct 38 | { 39 | int keycode; 40 | bool alt; 41 | bool ignore_it; 42 | MEVENT mevent; 43 | } NCursesEventData; 44 | 45 | typedef enum 46 | { 47 | PSPG_NCURSES_EVENT, /* classic ncurses event - keyboard, mouse, resize terminal */ 48 | PSPG_READ_DATA_EVENT, /* signal of new data on input */ 49 | PSPG_TIMEOUT_EVENT, /* got a timeout */ 50 | PSPG_SIGINT_EVENT, /* got a sigint */ 51 | PSPG_SIGWINCH_EVENT, /* got a sigwinch */ 52 | PSPG_FATAL_EVENT, /* got a fatal error */ 53 | PSPG_ERROR_EVENT, /* got a error with error message */ 54 | PSPG_NOTHING_VALID_EVENT, /* got an error, but this error can be ignored */ 55 | } PspgEventType; 56 | 57 | enum 58 | { 59 | STREAM_IS_UNKNOWN = 0, 60 | STREAM_IS_FIFO = 1, /* can be FIFO or PIPE */ 61 | STREAM_IS_PIPE = 1 << 2, 62 | STREAM_IS_FILE = 1 << 3, 63 | STREAM_CAN_BE_CLOSED = 1 << 4, 64 | STREAM_CAN_BE_REOPENED = 1 << 5, 65 | STREAM_IS_IN_NONBLOCKING_MODE = 1 << 6, 66 | STREAM_HAS_NOTIFY_SUPPORT = 1 << 7, 67 | STREAM_IS_OPEN = 1 << 8, 68 | STREAM_IS_CLOSED = 1 << 9, 69 | }; 70 | 71 | extern FILE *f_data; 72 | extern FILE *f_tty; 73 | extern unsigned int f_data_opts; 74 | 75 | extern int pspg_esc_delay; 76 | 77 | extern int get_pspg_event(NCursesEventData *nced, bool only_tty_events, int timeout); 78 | extern void unget_pspg_event(NCursesEventData *nced); 79 | 80 | extern void detect_file_truncation(void); 81 | extern void save_file_position(void); 82 | extern bool open_data_stream(Options *opts); 83 | extern void close_data_stream(void); 84 | 85 | extern bool open_tty_stream(void); 86 | extern void close_tty_stream(void); 87 | 88 | extern int wait_on_press_any_key(void); 89 | extern const char *get_input_file_basename(void); 90 | 91 | #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 92 | 93 | extern void clean_notify_poll(void); 94 | 95 | #endif 96 | 97 | #endif 98 | 99 | -------------------------------------------------------------------------------- /src/linebuffer.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * linebuffer.c 4 | * a routines for iteration over stored lines 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/linebuffer.c 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #include "pspg.h" 15 | 16 | #include 17 | #include 18 | 19 | /* 20 | * Initialize line buffer iterator 21 | */ 22 | inline void 23 | init_lbi(LineBufferIter *lbi, 24 | LineBuffer *lb, 25 | MappedLine *order_map, 26 | int order_map_items, 27 | int init_pos) 28 | { 29 | lbi->start_lb = lb; 30 | 31 | lbi->order_map = order_map; 32 | lbi->order_map_items = order_map_items; 33 | 34 | lbi_set_lineno(lbi, init_pos); 35 | } 36 | 37 | /* 38 | * Common case - initialize line buffer iterator 39 | * for stored data. 40 | */ 41 | inline void 42 | init_lbi_ddesc(LineBufferIter *lbi, 43 | DataDesc *desc, 44 | int init_pos) 45 | { 46 | init_lbi(lbi, 47 | &desc->rows, 48 | desc->order_map, 49 | desc->order_map_items, 50 | init_pos); 51 | } 52 | 53 | /* 54 | * Set iterator to absolute position in line buffer 55 | */ 56 | bool 57 | lbi_set_lineno(LineBufferIter *lbi, int pos) 58 | { 59 | lbi->lineno = pos; 60 | 61 | if (lbi->order_map) 62 | { 63 | if (lbi->order_map_items > pos) 64 | { 65 | MappedLine *mpl = &lbi->order_map[pos]; 66 | 67 | lbi->current_lb = mpl->lnb; 68 | lbi->current_lb_rowno = mpl->lnb_row; 69 | 70 | return true; 71 | } 72 | 73 | /* set max lineno */ 74 | lbi->lineno = lbi->order_map_items; 75 | } 76 | else 77 | { 78 | int lineno_offset = 0; 79 | 80 | lbi->current_lb = lbi->start_lb; 81 | 82 | while (lbi->current_lb && pos >= LINEBUFFER_LINES) 83 | { 84 | pos -= LINEBUFFER_LINES; 85 | lineno_offset += lbi->current_lb->nrows; 86 | 87 | lbi->current_lb = lbi->current_lb->next; 88 | } 89 | 90 | if (lbi->current_lb) 91 | { 92 | if (pos < lbi->current_lb->nrows) 93 | { 94 | lbi->current_lb_rowno = pos; 95 | 96 | return true; 97 | } 98 | else 99 | lbi->lineno = lineno_offset + lbi->current_lb->nrows; 100 | } 101 | else 102 | lbi->lineno = lineno_offset; 103 | } 104 | 105 | lbi->current_lb = NULL; 106 | lbi->current_lb_rowno = 0; 107 | 108 | return false; 109 | } 110 | 111 | /* 112 | * Initialize line buffer mark to current position in 113 | * line buffer. 114 | */ 115 | inline void 116 | lbi_set_mark(LineBufferIter *lbi, LineBufferMark *lbm) 117 | { 118 | lbm->lb = lbi->current_lb; 119 | lbm->lb_rowno = lbi->current_lb_rowno; 120 | lbm->lineno = lbi->lineno; 121 | } 122 | 123 | /* 124 | * Initialize line buffer mark to current position in line 125 | * buffer. Increase current position in line buffer. Returns 126 | * true if line buffer mark is valid. 127 | */ 128 | bool 129 | lbi_set_mark_next(LineBufferIter *lbi, LineBufferMark *lbm) 130 | { 131 | lbi_set_mark(lbi, lbm); 132 | (void) lbi_next(lbi); 133 | 134 | return lbm->lb && lbm->lb_rowno < lbm->lb->nrows; 135 | } 136 | 137 | /* 138 | * Sets mark to line buffer specified by position. When false, 139 | * when position is not valid. 140 | */ 141 | bool 142 | ddesc_set_mark(LineBufferMark *lbm, DataDesc *desc, int pos) 143 | { 144 | lbm->lb = NULL; 145 | lbm->lineno = pos; 146 | 147 | if (desc->order_map) 148 | { 149 | if (pos >= 0 && pos < desc->order_map_items) 150 | { 151 | lbm->lb = desc->order_map[pos].lnb; 152 | lbm->lb_rowno = desc->order_map[pos].lnb_row; 153 | lbm->lineno = pos; 154 | 155 | return true; 156 | } 157 | } 158 | else 159 | { 160 | LineBuffer *lb = &desc->rows; 161 | 162 | while (lb && pos >= LINEBUFFER_LINES) 163 | { 164 | lb = lb->next; 165 | pos -= LINEBUFFER_LINES; 166 | } 167 | 168 | if (lb && pos < lb->nrows) 169 | { 170 | lbm->lb = lb; 171 | lbm->lb_rowno = pos; 172 | 173 | return true; 174 | } 175 | } 176 | 177 | return false; 178 | } 179 | 180 | void 181 | lbm_xor_mask(LineBufferMark *lbm, char mask) 182 | { 183 | if (!lbm->lb->lineinfo) 184 | { 185 | int i; 186 | 187 | /* smalloc returns zero fill memory already */ 188 | lbm->lb->lineinfo = smalloc(LINEBUFFER_LINES * sizeof(LineInfo)); 189 | 190 | for (i = 0; i < LINEBUFFER_LINES; i++) 191 | lbm->lb->lineinfo[i].recno_offset = SHRT_MIN; 192 | } 193 | 194 | lbm->lb->lineinfo[lbm->lb_rowno].mask ^= mask; 195 | } 196 | 197 | void 198 | lbm_recno_offset(LineBufferMark *lbm, short int recno_offset) 199 | { 200 | if (!lbm->lb->lineinfo) 201 | { 202 | int i; 203 | 204 | /* smalloc returns zero fill memory already */ 205 | lbm->lb->lineinfo = smalloc(LINEBUFFER_LINES * sizeof(LineInfo)); 206 | 207 | for (i = 0; i < LINEBUFFER_LINES; i++) 208 | lbm->lb->lineinfo[i].recno_offset = SHRT_MIN; 209 | } 210 | 211 | lbm->lb->lineinfo[lbm->lb_rowno].recno_offset = recno_offset; 212 | } 213 | 214 | 215 | /* 216 | * Working horse of lbm_get_line and lbi_get_line routines 217 | */ 218 | static bool 219 | lb_get_line(LineBuffer *lb, 220 | int rowno, 221 | int lineno, 222 | char **line, 223 | LineInfo **linfo, 224 | int *linenoptr) 225 | { 226 | if (linenoptr) 227 | *linenoptr = lineno; 228 | 229 | if (lb && rowno >= 0 && rowno < lb->nrows) 230 | { 231 | if (line) 232 | *line = lb->rows[rowno]; 233 | 234 | if (linfo) 235 | *linfo = lb->lineinfo ? &lb->lineinfo[rowno] : NULL; 236 | 237 | return true; 238 | } 239 | 240 | if (line) 241 | *line = NULL; 242 | 243 | if (linfo) 244 | *linfo = NULL; 245 | 246 | return false; 247 | } 248 | 249 | /* 250 | * Returns line related to line buffer mark 251 | */ 252 | bool 253 | lbm_get_line(LineBufferMark *lbm, 254 | char **line, 255 | LineInfo **linfo, 256 | int *lineno) 257 | { 258 | return lb_get_line(lbm->lb, 259 | lbm->lb_rowno, 260 | lbm->lineno, 261 | line, 262 | linfo, 263 | lineno); 264 | } 265 | 266 | /* 267 | * Returns true, when returns valid line from line buffer. 268 | */ 269 | inline bool 270 | lbi_get_line(LineBufferIter *lbi, 271 | char **line, 272 | LineInfo **linfo, 273 | int *lineno) 274 | { 275 | return lb_get_line(lbi->current_lb, 276 | lbi->current_lb_rowno, 277 | lbi->lineno, 278 | line, 279 | linfo, 280 | lineno); 281 | } 282 | 283 | /* 284 | * Returns true, when returns valid line from line buffer. 285 | * Increments position in linebuffer. 286 | */ 287 | inline bool 288 | lbi_get_line_next(LineBufferIter *lbi, 289 | char **line, 290 | LineInfo **linfo, 291 | int *lineno) 292 | { 293 | bool result; 294 | 295 | result = lbi_get_line(lbi, line, linfo, lineno); 296 | 297 | (void) lbi_next(lbi); 298 | 299 | return result; 300 | } 301 | 302 | 303 | /* 304 | * Returns true, when returns valid line from line buffer. 305 | * Decreases position in linebuffer. 306 | */ 307 | inline bool 308 | lbi_get_line_prev(LineBufferIter *lbi, 309 | char **line, 310 | LineInfo **linfo, 311 | int *lineno) 312 | { 313 | bool result; 314 | 315 | result = lbi_get_line(lbi, line, linfo, lineno); 316 | 317 | (void) lbi_prev(lbi); 318 | 319 | return result; 320 | } 321 | 322 | /* 323 | * Move to prev line in line buffer. Returns false, when there 324 | * is not valid line in buffer. 325 | */ 326 | bool 327 | lbi_prev(LineBufferIter *lbi) 328 | { 329 | if (lbi->order_map) 330 | { 331 | if (lbi->lineno > 0) 332 | { 333 | MappedLine *mpl; 334 | 335 | lbi->lineno -= 1; 336 | 337 | mpl = &lbi->order_map[lbi->lineno]; 338 | 339 | lbi->current_lb = mpl->lnb; 340 | lbi->current_lb_rowno = mpl->lnb_row; 341 | 342 | return true; 343 | } 344 | else 345 | lbi->lineno = -1; 346 | } 347 | else 348 | { 349 | if (lbi->current_lb) 350 | { 351 | lbi->lineno -= 1; 352 | 353 | lbi->current_lb_rowno -= 1; 354 | if (lbi->current_lb_rowno >= 0) 355 | return true; 356 | 357 | if (lbi->current_lb->prev) 358 | { 359 | lbi->current_lb = lbi->current_lb->prev; 360 | lbi->current_lb_rowno = LINEBUFFER_LINES - 1; 361 | 362 | return true; 363 | } 364 | } 365 | } 366 | 367 | lbi->current_lb = NULL; 368 | lbi->current_lb_rowno = 0; 369 | 370 | return false; 371 | } 372 | 373 | /* 374 | * Move on next line in line buffer. Returns false, when there 375 | * is not valid line in buffer. 376 | */ 377 | bool 378 | lbi_next(LineBufferIter *lbi) 379 | { 380 | if (lbi->order_map) 381 | { 382 | if (lbi->lineno + 1 < lbi->order_map_items) 383 | { 384 | MappedLine *mpl; 385 | 386 | lbi->lineno += 1; 387 | 388 | mpl = &lbi->order_map[lbi->lineno]; 389 | 390 | lbi->current_lb = mpl->lnb; 391 | lbi->current_lb_rowno = mpl->lnb_row; 392 | 393 | return true; 394 | } 395 | else 396 | lbi->lineno = lbi->order_map_items; 397 | } 398 | else 399 | { 400 | if (lbi->current_lb) 401 | { 402 | /* 403 | * Previous row must be valid, so we can increase 404 | * lineno without creating gap after last line lineno. 405 | */ 406 | lbi->lineno += 1; 407 | 408 | lbi->current_lb_rowno += 1; 409 | if (lbi->current_lb_rowno < lbi->current_lb->nrows) 410 | return true; 411 | 412 | if (lbi->current_lb->next) 413 | { 414 | lbi->current_lb = lbi->current_lb->next; 415 | lbi->current_lb_rowno = 0; 416 | 417 | return true; 418 | } 419 | } 420 | } 421 | 422 | lbi->current_lb = NULL; 423 | lbi->current_lb_rowno = 0; 424 | 425 | return false; 426 | } 427 | 428 | /* 429 | * Simple line buffer iterator allows just only forward 430 | * scan. 431 | */ 432 | SimpleLineBufferIter * 433 | init_slbi_ddesc(SimpleLineBufferIter *slbi, DataDesc *desc) 434 | { 435 | slbi->lb = &desc->rows; 436 | slbi->lb_rowno = 0; 437 | 438 | if (slbi->lb->nrows > 0) 439 | return slbi; 440 | else 441 | return NULL; 442 | 443 | } 444 | 445 | SimpleLineBufferIter * 446 | slbi_get_line_next(SimpleLineBufferIter *slbi, 447 | char **line, 448 | LineInfo **linfo) 449 | { 450 | if (slbi) 451 | { 452 | LineBuffer *lb = slbi->lb; 453 | 454 | /* 455 | * one line should be available every time. The possibility 456 | * is checked before 457 | */ 458 | if (linfo) 459 | *linfo = lb->lineinfo ? &lb->lineinfo[slbi->lb_rowno] : NULL; 460 | 461 | if (line) 462 | *line = lb->rows[slbi->lb_rowno]; 463 | 464 | slbi->lb_rowno += 1; 465 | 466 | /* check an possibility of next read */ 467 | if (slbi->lb_rowno < lb->nrows) 468 | return slbi; 469 | 470 | if (lb->next) 471 | { 472 | slbi->lb = lb->next; 473 | slbi->lb_rowno = 0; 474 | 475 | /* should not be possible */ 476 | if (slbi->lb->nrows == 0) 477 | return NULL; 478 | } 479 | else 480 | return NULL; 481 | } 482 | else 483 | *line = NULL; 484 | 485 | return slbi; 486 | } 487 | 488 | /* 489 | * Free all lines stored in line buffer. An argument is data desc, 490 | * because first chunk of line buffer is owned by data desc. 491 | */ 492 | void 493 | lb_free(DataDesc *desc) 494 | { 495 | LineBuffer *lb = &desc->rows; 496 | LineBuffer *next; 497 | int i; 498 | 499 | while (lb) 500 | { 501 | for (i = 0; i < lb->nrows; i++) 502 | free(lb->rows[i]); 503 | 504 | free(lb->lineinfo); 505 | next = lb->next; 506 | 507 | if (lb != &desc->rows) 508 | free(lb); 509 | 510 | lb = next; 511 | } 512 | } 513 | 514 | /* 515 | * Print all lines to stream 516 | */ 517 | void 518 | lb_print_all_ddesc(DataDesc *desc, FILE *f) 519 | { 520 | SimpleLineBufferIter slbi, *_slbi; 521 | 522 | _slbi = init_slbi_ddesc(&slbi, desc); 523 | 524 | while (_slbi) 525 | { 526 | char *line; 527 | int res; 528 | 529 | _slbi = slbi_get_line_next(_slbi, &line, NULL); 530 | 531 | res = fprintf(f, "%s\n", line); 532 | if (res < 0) 533 | break; 534 | } 535 | } 536 | 537 | const char * 538 | getline_ddesc(DataDesc *desc, int pos) 539 | { 540 | LineBufferIter lbi; 541 | char *result; 542 | 543 | init_lbi_ddesc(&lbi, desc, pos); 544 | if (lbi_get_line(&lbi, &result, NULL, NULL)) 545 | return result; 546 | 547 | return NULL; 548 | } 549 | -------------------------------------------------------------------------------- /src/pgclient.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * pgcliend.c 4 | * execute query and format result 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/pgclient.c 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "pspg.h" 20 | #include "unicode.h" 21 | 22 | #ifdef HAVE_POSTGRESQL 23 | 24 | #include 25 | 26 | char errmsg[1024]; 27 | 28 | static RowBucketType * 29 | push_row(RowBucketType *rb, RowType *row, bool is_multiline) 30 | { 31 | if (rb->nrows >= 1000) 32 | { 33 | RowBucketType *new = malloc(sizeof(RowBucketType)); 34 | 35 | if (!new) 36 | return NULL; 37 | 38 | new->nrows = 0; 39 | new->allocated = true; 40 | new->next_bucket = NULL; 41 | 42 | rb->next_bucket = new; 43 | rb = new; 44 | } 45 | 46 | rb->rows[rb->nrows] = row; 47 | rb->multilines[rb->nrows++] = is_multiline; 48 | 49 | return rb; 50 | } 51 | 52 | /* 53 | * Correct solution is importing header file catalog/pg_type_d.h, 54 | * but this file is not in basic libpq headers, so instead enhancing 55 | * dependency just copy these values that should be immutable. 56 | */ 57 | #define INT8OID 20 58 | #define INT2OID 21 59 | #define INT4OID 23 60 | #define FLOAT4OID 700 61 | #define FLOAT8OID 701 62 | #define XIDOID 28 63 | #define CIDOID 29 64 | #define CASHOID 790 65 | #define NUMERICOID 1700 66 | #define OIDOID 26 67 | 68 | static char 69 | column_type_class(Oid ftype) 70 | { 71 | char align; 72 | 73 | switch (ftype) 74 | { 75 | case INT2OID: 76 | case INT4OID: 77 | case INT8OID: 78 | case FLOAT4OID: 79 | case FLOAT8OID: 80 | case NUMERICOID: 81 | case OIDOID: 82 | case XIDOID: 83 | case CIDOID: 84 | case CASHOID: 85 | align = 'd'; 86 | break; 87 | default: 88 | align = 'a'; 89 | break; 90 | } 91 | return align; 92 | } 93 | 94 | 95 | #endif 96 | 97 | #define EXIT_OUT_OF_MEMORY() do { PQclear(result); PQfinish(conn); leave("out of memory"); } while (0) 98 | #define RELEASE_AND_LEAVE(s) do { PQclear(result); PQfinish(conn); *err = s; return false; } while (0) 99 | #define RELEASE_AND_EXIT(s) do { PQclear(result); PQfinish(conn); leave(s); } while (0) 100 | 101 | #ifdef HAVE_POSTGRESQL 102 | 103 | static int 104 | field_info(char *str, bool *multiline) 105 | { 106 | long int digits; 107 | long int others; 108 | 109 | if (!use_utf8) 110 | { 111 | int cw = 0; 112 | int width = 0; 113 | 114 | while (*str) 115 | { 116 | if (*str++ == '\n') 117 | { 118 | *multiline = true; 119 | width = cw > width ? cw : width; 120 | cw = 0; 121 | } 122 | else 123 | cw++; 124 | } 125 | 126 | return cw > width ? cw : width; 127 | } 128 | else 129 | return utf_string_dsplen_multiline(str, strlen(str), multiline, false, &digits, &others, 0); 130 | } 131 | 132 | /* 133 | * Returns true, when some column should be hidden. 134 | */ 135 | static int 136 | mark_hidden_columns(PGresult *result, 137 | int nfields, 138 | Options *opts, 139 | bool *hidden) 140 | { 141 | char *names; 142 | char *endnames; 143 | char *ptr; 144 | int i; 145 | int visible_columns = 0; 146 | 147 | for (i = 0; i < nfields; i++) 148 | hidden[i] = false; 149 | 150 | if (!opts->csv_skip_columns_like) 151 | return nfields; 152 | 153 | /* prepare list of hidden columns */ 154 | names = sstrdup(opts->csv_skip_columns_like); 155 | 156 | endnames = names + strlen(names); 157 | ptr = names; 158 | while (*ptr) 159 | { 160 | /* space is separator between words */ 161 | if (*ptr == ' ') 162 | *ptr = '\0'; 163 | ptr += 1; 164 | } 165 | 166 | for (i = 0; i < nfields; i++) 167 | { 168 | char *fieldname = PQfname(result, i); 169 | 170 | ptr = names; 171 | while (ptr < endnames) 172 | { 173 | if (*ptr) 174 | { 175 | size_t len = strlen(ptr); 176 | 177 | if (*ptr == '^') 178 | { 179 | if (strncmp(fieldname, ptr + 1, len - 1) == 0) 180 | hidden[i] = true; 181 | } 182 | else if (ptr[len - 1] == '$') 183 | { 184 | size_t len2 = strlen(fieldname); 185 | 186 | if (len2 > (len - 1) && 187 | strncmp(fieldname + len2 - len + 1, ptr, len - 1) == 0) 188 | hidden[i] = true; 189 | } 190 | else if (strstr(fieldname, ptr)) 191 | hidden[i] = true; 192 | } 193 | 194 | ptr += strlen(ptr) + 1; 195 | } 196 | 197 | if (!hidden[i]) 198 | visible_columns += 1; 199 | } 200 | 201 | free(names); 202 | 203 | return visible_columns; 204 | } 205 | 206 | 207 | #endif 208 | 209 | 210 | /* 211 | * exit on fatal error, or return error 212 | */ 213 | bool 214 | pg_exec_query(Options *opts, char *query, RowBucketType *rb, PrintDataDesc *pdesc, const char **err) 215 | { 216 | 217 | log_row("execute query \"%s\"", query); 218 | 219 | #ifdef HAVE_POSTGRESQL 220 | 221 | PGconn *conn = NULL; 222 | PGresult *result = NULL; 223 | 224 | int nfields; 225 | int size; 226 | int i, j; 227 | int n; 228 | char *locbuf; 229 | RowType *row; 230 | bool multiline_row; 231 | bool multiline_col; 232 | char *password; 233 | 234 | const char *keywords[8]; 235 | const char *values[8]; 236 | 237 | bool *hidden; 238 | 239 | rb->nrows = 0; 240 | rb->next_bucket = NULL; 241 | 242 | if (opts->force_password_prompt && !opts->password) 243 | { 244 | password = getpass("Password: "); 245 | opts->password = strdup(password); 246 | if (!opts->password) 247 | EXIT_OUT_OF_MEMORY(); 248 | } 249 | 250 | keywords[0] = "host"; values[0] = opts->host; 251 | keywords[1] = "port"; values[1] = opts->port; 252 | keywords[2] = "user"; values[2] = opts->username; 253 | keywords[3] = "password"; values[3] = opts->password; 254 | keywords[4] = "dbname"; values[4] = opts->dbname; 255 | keywords[5] = "fallback_application_name"; values[5] = "pspg"; 256 | keywords[6] = "client_encoding"; values[6] = getenv("PGCLIENTENCODING") ? NULL : "auto"; 257 | keywords[7] = NULL; values[7] = NULL; 258 | 259 | conn = PQconnectdbParams(keywords, values, true); 260 | 261 | if (PQstatus(conn) == CONNECTION_BAD && 262 | PQconnectionNeedsPassword(conn) && 263 | !opts->password) 264 | { 265 | password = getpass("Password: "); 266 | opts->password = strdup(password); 267 | if (!opts->password) 268 | EXIT_OUT_OF_MEMORY(); 269 | 270 | keywords[3] = "password"; values[3] = opts->password; 271 | 272 | conn = PQconnectdbParams(keywords, values, true); 273 | } 274 | 275 | /* Check to see that the backend connection was successfully made */ 276 | if (PQstatus(conn) != CONNECTION_OK) 277 | { 278 | snprintf(errmsg, sizeof(errmsg), 279 | "Connection to database failed: %s", PQerrorMessage(conn)); 280 | RELEASE_AND_LEAVE(errmsg); 281 | } 282 | 283 | /* 284 | * ToDo: Because data are copied to local memory, the result can be fetched. 285 | * It can save 1/2 memory. 286 | */ 287 | result = PQexec(conn, query); 288 | if (PQresultStatus(result) != PGRES_TUPLES_OK) 289 | { 290 | snprintf(errmsg, sizeof(errmsg), 291 | "Query doesn't return data: %s", PQerrorMessage(conn)); 292 | RELEASE_AND_LEAVE(errmsg); 293 | } 294 | 295 | if ((nfields = PQnfields(result)) > 1024) 296 | RELEASE_AND_EXIT("too much columns"); 297 | 298 | hidden = smalloc(1024 * sizeof(bool)); 299 | 300 | pdesc->nfields = mark_hidden_columns(result, nfields, opts, hidden); 301 | 302 | pdesc->has_header = true; 303 | n = 0; 304 | for (i = 0; i < nfields; i++) 305 | if (!hidden[i]) 306 | pdesc->types[n++] = column_type_class(PQftype(result, i)); 307 | 308 | /* calculate necessary size of header data */ 309 | size = 0; 310 | for (i = 0; i < nfields; i++) 311 | if (!hidden[i]) 312 | size += strlen(PQfname(result, i)) + 1; 313 | 314 | locbuf = malloc(size); 315 | if (!locbuf) 316 | EXIT_OUT_OF_MEMORY(); 317 | 318 | /* store header */ 319 | row = malloc(offsetof(RowType, fields) + (pdesc->nfields * sizeof(char *))); 320 | if (!row) 321 | EXIT_OUT_OF_MEMORY(); 322 | 323 | row->nfields = nfields; 324 | 325 | multiline_row = false; 326 | n = 0; 327 | for (i = 0; i < nfields; i++) 328 | { 329 | char *name = PQfname(result, i); 330 | 331 | if (hidden[i]) 332 | continue; 333 | 334 | strcpy(locbuf, name); 335 | row->fields[n] = locbuf; 336 | locbuf += strlen(name) + 1; 337 | 338 | pdesc->widths[n] = field_info(row->fields[n], &multiline_col); 339 | pdesc->multilines[n++] = multiline_col; 340 | 341 | multiline_row |= multiline_col; 342 | } 343 | 344 | rb = push_row(rb, row, multiline_row); 345 | if (!rb) 346 | EXIT_OUT_OF_MEMORY(); 347 | 348 | /* calculate size for any row and store it */ 349 | for (i = 0; i < PQntuples(result); i++) 350 | { 351 | size = 0; 352 | for (j = 0; j < nfields; j++) 353 | if (!hidden[j]) 354 | size += strlen(PQgetvalue(result, i, j)) + 1; 355 | 356 | locbuf = malloc(size); 357 | if (!locbuf) 358 | EXIT_OUT_OF_MEMORY(); 359 | 360 | /* store data */ 361 | row = malloc(offsetof(RowType, fields) + (pdesc->nfields * sizeof(char *))); 362 | if (!row) 363 | EXIT_OUT_OF_MEMORY(); 364 | 365 | row->nfields = pdesc->nfields; 366 | 367 | multiline_row = false; 368 | n = 0; 369 | for (j = 0; j < nfields; j++) 370 | { 371 | char *value; 372 | 373 | if (hidden[j]) 374 | continue; 375 | 376 | value = PQgetvalue(result, i, j); 377 | 378 | strcpy(locbuf, value); 379 | row->fields[n] = locbuf; 380 | locbuf += strlen(value) + 1; 381 | 382 | pdesc->widths[n] = max_int(pdesc->widths[n], 383 | field_info(row->fields[n], &multiline_col)); 384 | pdesc->multilines[n] |= multiline_col; 385 | multiline_row |= multiline_col; 386 | 387 | pdesc->columns_map[n] = n; 388 | n += 1; 389 | } 390 | 391 | rb = push_row(rb, row, multiline_row); 392 | if (!rb) 393 | EXIT_OUT_OF_MEMORY(); 394 | } 395 | 396 | free(hidden); 397 | 398 | PQclear(result); 399 | PQfinish(conn); 400 | 401 | *err = NULL; 402 | 403 | return true; 404 | 405 | #else 406 | 407 | (void) rb; 408 | (void) pdesc; 409 | (void) opts; 410 | 411 | *err = "Query cannot be executed. The Postgres library was not available at compile time."; 412 | 413 | return false; 414 | 415 | #endif 416 | 417 | } 418 | -------------------------------------------------------------------------------- /src/sort.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * sort.c 4 | * sort of data inside columns 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/sort.c 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | #include "pspg.h" 18 | 19 | static inline int 20 | signof(double n) 21 | { 22 | if (n < 0) 23 | return -1; 24 | else if (n > 0) 25 | return 1; 26 | else 27 | return 0; 28 | } 29 | 30 | static int 31 | compar_num_asc(const void *a, const void *b) 32 | { 33 | SortData *sda = (SortData *) a; 34 | SortData *sdb = (SortData *) b; 35 | 36 | if (sdb->info == INFO_DOUBLE) 37 | { 38 | if (sda->info == INFO_DOUBLE) 39 | /* 40 | * Without using signof function there is possible problem with 41 | * mapping of 8bytes double to 4bytes int (the sign of result value 42 | * after casting can be wrong). 43 | */ 44 | return signof(sda->d - sdb->d); 45 | else 46 | return 1; 47 | } 48 | else 49 | { 50 | if (sda->info == INFO_DOUBLE) 51 | return -1; 52 | else 53 | return 0; 54 | } 55 | } 56 | 57 | static int 58 | compar_num_desc(const void *a, const void *b) 59 | { 60 | SortData *sda = (SortData *) a; 61 | SortData *sdb = (SortData *) b; 62 | 63 | if (sdb->info == INFO_DOUBLE) 64 | { 65 | if (sda->info == INFO_DOUBLE) 66 | return signof(sdb->d - sda->d); 67 | else 68 | return 1; 69 | } 70 | else 71 | { 72 | if (sda->info == INFO_DOUBLE) 73 | return -1; 74 | else 75 | return 0; 76 | } 77 | } 78 | 79 | void 80 | sort_column_num(SortData *sortbuf, int rows, bool desc) 81 | { 82 | 83 | qsort(sortbuf, rows, sizeof(SortData), desc ? compar_num_desc : compar_num_asc); 84 | } 85 | 86 | static int 87 | compar_text_asc(const void *a, const void *b) 88 | { 89 | SortData *sda = (SortData *) a; 90 | SortData *sdb = (SortData *) b; 91 | 92 | if (sdb->info == INFO_STRXFRM) 93 | { 94 | if (sda->info == INFO_STRXFRM) 95 | return strcmp(sda->strxfrm, sdb->strxfrm); 96 | else 97 | return 1; 98 | } 99 | else 100 | { 101 | if (sda->info == INFO_STRXFRM) 102 | return -1; 103 | else 104 | return 0; 105 | } 106 | } 107 | 108 | static int 109 | compar_text_desc(const void *a, const void *b) 110 | { 111 | SortData *sda = (SortData *) a; 112 | SortData *sdb = (SortData *) b; 113 | 114 | if (sdb->info == INFO_STRXFRM) 115 | { 116 | if (sda->info == INFO_STRXFRM) 117 | return strcmp(sdb->strxfrm, sda->strxfrm); 118 | else 119 | return 1; 120 | } 121 | else 122 | { 123 | if (sda->info == INFO_STRXFRM) 124 | return -1; 125 | else 126 | return 0; 127 | } 128 | } 129 | 130 | void 131 | sort_column_text(SortData *sortbuf, int rows, bool desc) 132 | { 133 | qsort(sortbuf, rows, sizeof(SortData), desc ? compar_text_desc : compar_text_asc); 134 | } 135 | -------------------------------------------------------------------------------- /src/st_curses.h: -------------------------------------------------------------------------------- 1 | #if defined HAVE_NCURSESW_CURSES_H 2 | #include 3 | #elif defined HAVE_NCURSESW_H 4 | #include 5 | #elif defined HAVE_NCURSES_CURSES_H 6 | #include 7 | #elif defined HAVE_NCURSES_H 8 | #include 9 | #elif defined HAVE_CURSES_H 10 | #include 11 | #else 12 | /* fallback */ 13 | #include 14 | #endif 15 | 16 | #ifdef PDCURSES 17 | /* Add some APIs that are part of ncurses but not pdcurses */ 18 | #ifndef __PDCURSESMOD__ 19 | #define wgetparent(win) ((WINDOW*)win->_parent); 20 | #endif 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /src/st_menu.h: -------------------------------------------------------------------------------- 1 | #ifndef _ST_MENU_H 2 | 3 | #define _ST_MENU_H 4 | 5 | #include 6 | #include "st_curses.h" 7 | 8 | #define ST_MENU_STYLE_MCB 0 9 | #define ST_MENU_STYLE_MC 1 10 | #define ST_MENU_STYLE_VISION 2 11 | #define ST_MENU_STYLE_DOS 3 12 | #define ST_MENU_STYLE_FAND_1 4 13 | #define ST_MENU_STYLE_FAND_2 5 14 | #define ST_MENU_STYLE_FOXPRO 6 15 | #define ST_MENU_STYLE_PERFECT 7 16 | #define ST_MENU_STYLE_NOCOLOR 8 17 | #define ST_MENU_STYLE_ONECOLOR 9 18 | #define ST_MENU_STYLE_TURBO 10 19 | #define ST_MENU_STYLE_PDMENU 11 20 | #define ST_MENU_STYLE_OLD_TURBO 12 21 | #define ST_MENU_STYLE_FREE_DOS 13 22 | #define ST_MENU_STYLE_FREE_DOS_P 14 23 | #define ST_MENU_STYLE_MC46 15 24 | #define ST_MENU_STYLE_DBASE 16 25 | #define ST_MENU_STYLE_MENUWORKS 17 26 | #define ST_MENU_STYLE_TAO 18 27 | #define ST_MENU_STYLE_XGOLD 19 28 | #define ST_MENU_STYLE_XGOLD_BLACK 20 29 | #define ST_MENU_STYLE_FLATWHITE 21 30 | 31 | #define ST_MENU_LAST_STYLE ST_MENU_STYLE_FLATWHITE 32 | 33 | #define ST_MENU_ESCAPE 27 34 | 35 | #define ST_MENU_OPTION_DEFAULT 1 36 | #define ST_MENU_OPTION_DISABLED 2 37 | #define ST_MENU_OPTION_MARKED 4 38 | #define ST_MENU_OPTION_MARKED_REF 8 /* mark one from group */ 39 | #define ST_MENU_OPTION_SWITCH2_REF 16 /* two state switch: 0, 1*/ 40 | #define ST_MENU_OPTION_SWITCH3_REF 32 /* three state switch: -1, 0, 1 */ 41 | 42 | #define ST_MENU_FOCUS_FULL 0 /* all possible events can be processed */ 43 | #define ST_MENU_FOCUS_ALT_MOUSE 1 /* only mouse, ALT key events */ 44 | #define ST_MENU_FOCUS_MOUSE_ONLY 2 /* only mouse events are processed */ 45 | #define ST_MENU_FOCUS_NONE 3 /* menu has not any focus */ 46 | 47 | #define IS_REF_OPTION(o) (((o) & ST_MENU_OPTION_MARKED_REF) || ((o) & ST_MENU_OPTION_SWITCH2_REF) || ((o) & ST_MENU_OPTION_SWITCH3_REF)) 48 | 49 | /* 50 | * Uncomment it and set for your environment when you would to 51 | * use named pipe for debugging. 52 | * 53 | #define DEBUG_PIPE "/home/pavel/debug" 54 | */ 55 | 56 | #ifdef DEBUG_PIPE 57 | 58 | /* 59 | * When you would to use named pipe for debugging, then there should 60 | * be active reader from this pipe before start demo application. 61 | * In this case "tail -f ~/debug" inside other terminal. 62 | */ 63 | 64 | extern FILE *debug_pipe; 65 | extern int debug_eventno; 66 | 67 | #endif 68 | 69 | typedef struct st_ST_MENU_ITEM 70 | { 71 | char *text; /* text of menu item, possible specify accelerator by ~ */ 72 | int code; /* code of menu item (optional) */ 73 | char *shortcut; /* shortcut text, only printed (optional) */ 74 | int data; /* allow to assign some value to menu item (optional) */ 75 | char group; /* specify semantics of data value (optional) */ 76 | int options; /* locked, marked, ... (optional) */ 77 | struct st_ST_MENU_ITEM *submenu; /* reference to nested menu (optional) */ 78 | } ST_MENU_ITEM; 79 | 80 | typedef struct 81 | { 82 | bool force8bit; 83 | char *encoding; 84 | const char *language; 85 | bool wide_vborders; /* wide vertical menu borders like Turbo Vision */ 86 | bool wide_hborders; /* wide horizontal menu borders like custom menu mc */ 87 | bool draw_box; /* when true, then box is created */ 88 | bool left_alligned_shortcuts; /* when true, a shortcuts are left alligned */ 89 | bool funckey_bar_style; /* when true, menu bar is displayed as mc toolbar */ 90 | bool extra_inner_space; /* when true, then there 2 spaces between text and border */ 91 | bool force_ascii_art; /* use ascii chars for borders */ 92 | int shadow_width; /* when shadow_width is higher than zero, shadow is visible */ 93 | int menu_background_cpn; /* draw area color pair number */ 94 | attr_t menu_background_attr; /* draw area attributte */ 95 | int menu_unfocused_cpn; /* draw area color pair number when menu has not focus */ 96 | attr_t menu_unfocused_attr; /* draw area attribute when menu has not focus */ 97 | int menu_shadow_cpn; /* menu shadow color pair number */ 98 | attr_t menu_shadow_attr; /* menu shadow area attributte */ 99 | int accelerator_cpn; /* color pair of accelerators */ 100 | attr_t accelerator_attr; /* accelerator attributes */ 101 | int cursor_cpn; /* cursor color pair */ 102 | attr_t cursor_attr; /* cursor attributte */ 103 | int cursor_accel_cpn; /* color pair of accelerator on cursor row */ 104 | attr_t cursor_accel_attr; /* attributte of of accelerator on cursor row */ 105 | int disabled_cpn; /* color of disabled menu fields */ 106 | attr_t disabled_attr; /* attributes of disabled menu fields */ 107 | int shortcut_space; /* spaces between text and shortcut */ 108 | int text_space; /* spaces between text fields (menubar), when it is -1, then dynamic spaces (FAND) */ 109 | int init_text_space; /* initial space for menu bar */ 110 | int menu_bar_menu_offset; /* offset between menu bar and menu */ 111 | int inner_space; /* space between draw area and border, FAND uses 2 spaces */ 112 | int extern_accel_text_space; /* space between external accelerator and menu item text */ 113 | int submenu_tag; /* symbol used for submenu tag */ 114 | int submenu_offset_y; /* offset for submenu related to right border of parent menu window */ 115 | int submenu_offset_x; /* offset for submenu related to cursor in parent menu window */ 116 | int mark_tag; /* symbol used for mark tag */ 117 | int switch_tag_n1; /* symbol used for switch negative 1 */ 118 | int switch_tag_0; /* symbol used for switch 0 */ 119 | int switch_tag_1; /* symbol used for switch 1 */ 120 | int scroll_up_tag; /* symbol used for possibility to scroll up */ 121 | int scroll_down_tag; /* symbol used for possibility to scroll down */ 122 | } ST_MENU_CONFIG; 123 | 124 | struct ST_MENU; 125 | 126 | typedef struct 127 | { 128 | char *text; /* text of command bar field */ 129 | bool alt; /* should be used like Alt+FX */ 130 | int fkey; /* Func key number */ 131 | int code; /* code of command bar item */ 132 | int option; /* locked, marked, ... (optional) */ 133 | } ST_CMDBAR_ITEM; 134 | 135 | struct ST_CMDBAR; 136 | 137 | extern int st_menu_load_style(ST_MENU_CONFIG *config, int style, int start_from_cpn, bool force8bit, bool force_ascii_art); 138 | extern int st_menu_load_style_rgb(ST_MENU_CONFIG *config, int style, int start_from_cpn, int *start_from_rgb, bool force8bit, bool force_ascii_art); 139 | 140 | extern void st_menu_set_desktop_window(WINDOW *win); 141 | extern struct ST_MENU *st_menu_new(ST_MENU_CONFIG *config, ST_MENU_ITEM *items, int begin_y, int begin_x, char *title); 142 | extern struct ST_MENU *st_menu_new_menubar(ST_MENU_CONFIG *config, ST_MENU_ITEM *items); 143 | extern struct ST_MENU *st_menu_new_menubar2(ST_MENU_CONFIG *barcfg, ST_MENU_CONFIG *pdcfg, ST_MENU_ITEM *items); 144 | 145 | extern void st_menu_post(struct ST_MENU *menu); 146 | extern void st_menu_unpost(struct ST_MENU *menu, bool close_active_submenu); 147 | extern bool st_menu_driver(struct ST_MENU *menu, int c, bool alt, MEVENT *mevent); 148 | extern void st_menu_free(struct ST_MENU *menu); 149 | extern void st_menu_save(struct ST_MENU *menu, int *cursor_rows, int **refvals, int max_items); 150 | extern void st_menu_load(struct ST_MENU *menu, int *cursor_rows, int **refvals); 151 | 152 | extern int st_menu_get_focus(struct ST_MENU *menu); 153 | 154 | extern ST_MENU_ITEM *st_menu_selected_item(bool *activated); 155 | extern ST_CMDBAR_ITEM *st_menu_selected_command(bool *activated); 156 | 157 | extern bool st_menu_enable_option(struct ST_MENU *menu, int code, int option); 158 | extern bool st_menu_reset_option(struct ST_MENU *menu, int code, int option); 159 | extern bool st_menu_set_option(struct ST_MENU *menu, int code, int option, bool value); 160 | extern bool st_menu_reset_all_submenu_options(struct ST_MENU *menu, int menu_code, int option); 161 | extern bool st_menu_reset_all_options(struct ST_MENU *menu, int option); 162 | extern void st_menu_set_focus(struct ST_MENU *menu, int focus); 163 | 164 | extern bool st_menu_set_shortcut(struct ST_MENU *menu, int code, char *shortcut); 165 | 166 | extern bool st_menu_set_ref_option(struct ST_MENU *menu, int code, int option, int *refvalue); 167 | 168 | extern struct ST_CMDBAR *st_cmdbar_new(ST_MENU_CONFIG *config, ST_CMDBAR_ITEM *cmdbar_items); 169 | extern void st_cmdbar_post(struct ST_CMDBAR *cmdbar); 170 | extern void st_cmdbar_unpost(struct ST_CMDBAR *cmdbar); 171 | extern void st_cmdbar_free(struct ST_CMDBAR *cmdbar); 172 | 173 | extern void st_menu_set_direct_color(bool direct_color); 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /src/st_panel.h: -------------------------------------------------------------------------------- 1 | #if defined HAVE_NCURSESW_PANEL_H 2 | #include 3 | #elif defined HAVE_NCURSES_PANEL_H 4 | #include 5 | #elif defined HAVE_PANEL_H 6 | #include 7 | #else 8 | /* fallback */ 9 | #include 10 | #endif 11 | 12 | -------------------------------------------------------------------------------- /src/string.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * string.c 4 | * a routines for case insensitive string operations 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/string.c 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #include 15 | 16 | #include "pspg.h" 17 | 18 | /* 19 | * Case insensitive string comparation. 20 | */ 21 | bool 22 | nstreq(const char *str1, const char *str2) 23 | { 24 | while (*str1 != '\0') 25 | { 26 | if (*str2 == '\0') 27 | return false; 28 | 29 | if (toupper(*str1++) != toupper(*str2++)) 30 | return false; 31 | } 32 | 33 | return *str2 == '\0'; 34 | } 35 | 36 | /* 37 | * special case insensitive searching routines 38 | */ 39 | const char * 40 | nstrstr(const char *haystack, const char *needle) 41 | { 42 | const char *haystack_cur, *needle_cur, *needle_prev; 43 | int f1 = 0; 44 | 45 | needle_cur = needle; 46 | needle_prev = NULL; 47 | haystack_cur = haystack; 48 | 49 | while (*needle_cur != '\0') 50 | { 51 | int f2; 52 | 53 | if (*haystack_cur == '\0') 54 | return NULL; 55 | 56 | if (needle_prev != needle_cur) 57 | { 58 | needle_prev = needle_cur; 59 | f1 = toupper(*needle_cur); 60 | } 61 | 62 | f2 = toupper(*haystack_cur); 63 | if (f1 == f2) 64 | { 65 | needle_cur += 1; 66 | haystack_cur += 1; 67 | } 68 | else 69 | { 70 | needle_cur = needle; 71 | haystack_cur = haystack += 1; 72 | } 73 | } 74 | 75 | return haystack; 76 | } 77 | 78 | const char * 79 | nstrstr_with_sizes(const char *haystack, 80 | const int haystack_size, 81 | const char *needle, 82 | int needle_size) 83 | { 84 | const char *haystack_cur, *needle_cur, *needle_prev; 85 | const char *haystack_end, *needle_end; 86 | int f1 = 0; 87 | 88 | needle_cur = needle; 89 | needle_prev = NULL; 90 | haystack_cur = haystack; 91 | 92 | haystack_end = haystack + haystack_size; 93 | needle_end = needle + needle_size; 94 | 95 | while (needle_cur < needle_end) 96 | { 97 | int f2 = 0; 98 | 99 | if (haystack_cur == haystack_end) 100 | return NULL; 101 | 102 | if (needle_prev != needle_cur) 103 | { 104 | needle_prev = needle_cur; 105 | f1 = toupper(*needle_cur); 106 | } 107 | 108 | f2 = toupper(*haystack_cur); 109 | if (f1 == f2) 110 | { 111 | needle_cur += 1; 112 | haystack_cur += 1; 113 | } 114 | else 115 | { 116 | needle_cur = needle; 117 | haystack_cur = haystack += 1; 118 | } 119 | } 120 | 121 | return haystack; 122 | } 123 | 124 | /* 125 | * Returns true, when string str starts with pattern 126 | */ 127 | bool 128 | nstarts_with_with_sizes(const char *str, 129 | int str_size, 130 | const char *pattern, 131 | int pattern_size) 132 | { 133 | if (pattern_size > str_size) 134 | return false; 135 | 136 | while (pattern_size > 0) 137 | { 138 | if (toupper(*str++) != toupper(*pattern++)) 139 | return false; 140 | 141 | pattern_size -= 1; 142 | } 143 | 144 | return true; 145 | } 146 | 147 | /* 148 | * Special string searching, lower chars are case insensitive, 149 | * upper chars are case sensitive. 150 | */ 151 | const char * 152 | nstrstr_ignore_lower_case(const char *haystack, const char *needle) 153 | { 154 | const char *haystack_cur, *needle_cur, *needle_prev; 155 | int f1 = 0; 156 | bool needle_char_is_upper = false; /* be compiler quiet */ 157 | 158 | needle_cur = needle; 159 | needle_prev = NULL; 160 | haystack_cur = haystack; 161 | 162 | while (*needle_cur != '\0') 163 | { 164 | bool eq; 165 | 166 | if (*haystack_cur == '\0') 167 | return NULL; 168 | 169 | if (needle_prev != needle_cur) 170 | { 171 | needle_prev = needle_cur; 172 | needle_char_is_upper = isupper(*needle_cur); 173 | f1 = toupper(*needle_cur); 174 | } 175 | 176 | if (needle_char_is_upper) 177 | { 178 | /* case sensitive */ 179 | eq = *haystack_cur == *needle_cur; 180 | } 181 | else 182 | { 183 | /* case insensitive */ 184 | eq = f1 == toupper(*haystack_cur); 185 | } 186 | 187 | if (eq) 188 | { 189 | needle_cur += 1; 190 | haystack_cur += 1; 191 | } 192 | else 193 | { 194 | needle_cur = needle; 195 | haystack_cur = haystack += 1; 196 | } 197 | } 198 | 199 | return haystack; 200 | } 201 | -------------------------------------------------------------------------------- /src/themes.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * themes.h 4 | * themes initialization 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/themes.h 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #ifndef PSPG_THEMES_H 15 | #define PSPG_THEMES_H 16 | 17 | #include 18 | 19 | #if defined HAVE_NCURSESW_CURSES_H 20 | #include 21 | #elif defined HAVE_NCURSESW_H 22 | #include 23 | #elif defined HAVE_NCURSES_CURSES_H 24 | #include 25 | #elif defined HAVE_NCURSES_H 26 | #include 27 | #elif defined HAVE_CURSES_H 28 | #include 29 | #else 30 | /* fallback */ 31 | #include 32 | #endif 33 | 34 | typedef struct 35 | { 36 | attr_t background_attr; /* colors for background */ 37 | attr_t data_attr; /* colors for data (alphanums) */ 38 | attr_t line_attr; /* colors for borders */ 39 | attr_t expi_attr; /* colors for expanded headers */ 40 | attr_t cursor_data_attr; /* colors for cursor on data positions */ 41 | attr_t cursor_line_attr; /* colors for cursor on border position */ 42 | attr_t cursor_expi_attr; /* colors for cursor on expanded headers */ 43 | attr_t bookmark_data_attr; /* colors for bookmark */ 44 | attr_t bookmark_line_attr; /* colors for bookmark line art */ 45 | attr_t cursor_bookmark_attr; /* colors for cursor on bookmark line */ 46 | attr_t found_str_attr; /* colors for marked string */ 47 | attr_t pattern_data_attr; /* colors for pattern line data */ 48 | attr_t pattern_line_attr; /* colors for pattern line art */ 49 | attr_t cursor_pattern_attr; /* colors for pattern on cursor line */ 50 | attr_t title_attr; /* colors for title window */ 51 | attr_t info_attr; /* colors for bottom info text */ 52 | attr_t prompt_attr; /* less prompt color */ 53 | attr_t cursor_rownum_attr; /* colors for cursor rownum column */ 54 | attr_t cross_cursor_attr; /* colors for cross horizontal and vertical cursor (data) */ 55 | attr_t cross_cursor_line_attr; /* colors for cross horizontal and vertical cursor (border) */ 56 | attr_t pattern_vertical_cursor_attr; 57 | attr_t pattern_vertical_cursor_line_attr; 58 | attr_t error_attr; /* colors for display error */ 59 | attr_t input_attr; /* colors for input line */ 60 | attr_t scrollbar_arrow_attr; /* colors for scrollbar arrows symbols */ 61 | attr_t scrollbar_attr; /* colors for scrollbar background */ 62 | attr_t scrollbar_slider_attr; /* colors for scrollbar slider */ 63 | attr_t scrollbar_active_slider_attr; /* colors for active scrollbar slider */ 64 | chtype scrollbar_slider_symbol; 65 | bool scrollbar_use_arrows; 66 | attr_t selection_attr; 67 | attr_t selection_cursor_attr; 68 | attr_t status_bar_attr; 69 | } Theme; 70 | 71 | #define WINDOW_LUC 0 72 | #define WINDOW_FIX_ROWS 1 73 | #define WINDOW_FIX_COLS 2 74 | #define WINDOW_ROWS 3 75 | #define WINDOW_FOOTER 4 76 | #define WINDOW_TOP_BAR 5 77 | #define WINDOW_BOTTOM_BAR 6 78 | #define WINDOW_ROWNUM 7 79 | #define WINDOW_ROWNUM_LUC 8 80 | #define WINDOW_VSCROLLBAR 9 81 | #define WINDOW_ROWS_ODD 10 82 | #define WINDOW_FIX_COLS_ODD 11 83 | #define WINDOW_ROWNUM_ODD 12 84 | 85 | typedef enum 86 | { 87 | PSPG_BLACK_COLOR, 88 | PSPG_RED_COLOR, 89 | PSPG_GREEN_COLOR, 90 | PSPG_BROWN_COLOR, 91 | PSPG_BLUE_COLOR, 92 | PSPG_MAGENTA_COLOR, 93 | PSPG_CYAN_COLOR, 94 | PSPG_LIGHT_GRAY_COLOR, 95 | PSPG_GRAY_COLOR, 96 | PSPG_BRIGHT_RED_COLOR, 97 | PSPG_BRIGHT_GREEN_COLOR, 98 | PSPG_YELLOW_COLOR, 99 | PSPG_BRIGHT_BLUE_COLOR, 100 | PSPG_BRIGHT_MAGENTA_COLOR, 101 | PSPG_BRIGHT_CYAN_COLOR, 102 | PSPG_WHITE_COLOR, 103 | PSPG_DEFAULT_COLOR 104 | } PspgBasicColor; 105 | 106 | typedef enum 107 | { 108 | PSPG_COLOR_BASIC, 109 | PSPG_COLOR_256, 110 | PSPG_COLOR_RGB 111 | } PspgColorPallet; 112 | 113 | typedef enum 114 | { 115 | PSPG_INDEPENDENT = 0, 116 | PSPG_CURSOR_BOLD, 117 | PSPG_LABEL_BOLD, 118 | } PspgStyleDependency; 119 | 120 | typedef struct 121 | { 122 | PspgColorPallet cp; 123 | PspgBasicColor bc; 124 | unsigned int rgb; 125 | } PspgColor; 126 | 127 | extern const PspgColor PspgBlack; 128 | extern const PspgColor PspgRed; 129 | extern const PspgColor PspgGreen; 130 | extern const PspgColor PspgBrown; 131 | extern const PspgColor PspgBlue; 132 | extern const PspgColor PspgMagenta; 133 | extern const PspgColor PspgCyan; 134 | extern const PspgColor PspgLightGray; 135 | extern const PspgColor PspgGray; 136 | extern const PspgColor PspgBrightRed; 137 | extern const PspgColor PspgBrightGreen; 138 | extern const PspgColor PspgYellow; 139 | extern const PspgColor PspgBrightBlue; 140 | extern const PspgColor PspgBrightMagenta; 141 | extern const PspgColor PspgBrightCyan; 142 | extern const PspgColor PspgWhite; 143 | extern const PspgColor PspgDefault; 144 | 145 | typedef struct 146 | { 147 | PspgColor fg; 148 | PspgColor bg; 149 | int attr; 150 | } PspgThemeElement; 151 | 152 | typedef struct 153 | { 154 | bool used; 155 | PspgThemeElement te; 156 | } PspgThemeLoaderElement; 157 | 158 | typedef enum 159 | { 160 | PspgTheme_none = 0, 161 | PspgTheme_background, 162 | PspgTheme_data, 163 | PspgTheme_border, 164 | PspgTheme_label, 165 | PspgTheme_rownum, 166 | PspgTheme_recnum, 167 | PspgTheme_selection, 168 | PspgTheme_footer, 169 | PspgTheme_cursor_data, 170 | PspgTheme_cursor_border, 171 | PspgTheme_cursor_label, 172 | PspgTheme_cursor_rownum, 173 | PspgTheme_cursor_recnum, 174 | PspgTheme_cursor_selection, 175 | PspgTheme_cursor_footer, 176 | PspgTheme_scrollbar_arrows, 177 | PspgTheme_scrollbar_background, 178 | PspgTheme_scrollbar_slider, 179 | PspgTheme_scrollbar_active_slider, 180 | PspgTheme_title, 181 | PspgTheme_status_bar, 182 | PspgTheme_prompt_bar, 183 | PspgTheme_info_bar, 184 | PspgTheme_error_bar, 185 | PspgTheme_input_bar, 186 | PspgTheme_bookmark, 187 | PspgTheme_bookmark_border, 188 | PspgTheme_cursor_bookmark, 189 | PspgTheme_cross_cursor, 190 | PspgTheme_cross_cursor_border, 191 | PspgTheme_pattern, 192 | PspgTheme_pattern_nohl, 193 | PspgTheme_pattern_line, 194 | PspgTheme_pattern_line_border, 195 | PspgTheme_pattern_cursor, 196 | PspgTheme_pattern_line_vertical_cursor, 197 | PspgTheme_pattern_line_vertical_cursor_border, 198 | PspgTheme_error 199 | } PspgThemeElements; 200 | 201 | 202 | extern void initialize_color_pairs(int theme, bool direct_color); 203 | extern void initialize_theme(int theme, int window_identifier, bool is_tabular_fmt, bool no_highlight_lines, int themedef_bank, Theme *t); 204 | extern void applyCustomTheme(PspgThemeLoaderElement *tle, PspgThemeLoaderElement *tle2); 205 | extern attr_t ncurses_theme_attr(PspgThemeElements idx); 206 | 207 | extern bool theme_loader(FILE *theme, PspgThemeLoaderElement *tle, PspgThemeLoaderElement *tle2, int *template, int *menu, bool *is_warning); 208 | extern FILE *open_theme_desc(char *name); 209 | 210 | extern bool has_odd_themedef; 211 | 212 | #ifndef A_ITALIC 213 | #define A_ITALIC A_DIM 214 | #endif 215 | 216 | #define THEMEDEF_SIZE 50 217 | 218 | #endif 219 | -------------------------------------------------------------------------------- /src/unicode.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * unicode.h 4 | * unicode and wide chars routines 5 | * 6 | * Portions Copyright (c) 2017-2025 Pavel Stehule 7 | * 8 | * IDENTIFICATION 9 | * src/unicode.h 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #ifndef PSPG_UNICODE_H 15 | #define PSPG_UNICODE_H 16 | 17 | #include 18 | #include 19 | 20 | extern int utf8len(const char *s); 21 | extern size_t utf8len_start_stop(const char *start, const char *stop); 22 | extern int utf8charlen(char ch); 23 | extern int utf_dsplen(const char *s); 24 | extern int utf_string_dsplen(const char *s, int max_bytes); 25 | extern int readline_utf_string_dsplen(const char *s, size_t max_bytes, size_t offset); 26 | extern const char *utf8_nstrstr(const char *haystack, const char *needle); 27 | extern const char *utf8_nstrstr_with_sizes(const char *haystack, int haystack_size, const char *needle, int needle_size); 28 | extern const char *utf8_nstrstr_ignore_lower_case(const char *haystack, const char *needle); 29 | extern bool utf8_nstarts_with_with_sizes(const char *str, int str_size, const char *pattern, int pattern_size); 30 | extern bool utf8_isupper(const char *s); 31 | extern unsigned char *unicode_to_utf8(wchar_t c, unsigned char *utf8string, int *size); 32 | extern int utf8_tofold(const char *s); 33 | extern int utf2wchar_with_len(const unsigned char *from, wchar_t *to, int len); 34 | extern int utf_string_dsplen_multiline(const char *s, size_t max_bytes, bool *multiline, bool first_only, long int *digits, long int *others, int trim_rows); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/unicode_east_asian_fw_table.h: -------------------------------------------------------------------------------- 1 | /* generated by src/common/unicode/generate-unicode_east_asian_fw_table.pl, do not edit */ 2 | 3 | static const struct mbinterval east_asian_fw[] = { 4 | {0x1100, 0x115F}, 5 | {0x231A, 0x231B}, 6 | {0x2329, 0x232A}, 7 | {0x23E9, 0x23EC}, 8 | {0x23F0, 0x23F0}, 9 | {0x23F3, 0x23F3}, 10 | {0x25FD, 0x25FE}, 11 | {0x2614, 0x2615}, 12 | {0x2648, 0x2653}, 13 | {0x267F, 0x267F}, 14 | {0x2693, 0x2693}, 15 | {0x26A1, 0x26A1}, 16 | {0x26AA, 0x26AB}, 17 | {0x26BD, 0x26BE}, 18 | {0x26C4, 0x26C5}, 19 | {0x26CE, 0x26CE}, 20 | {0x26D4, 0x26D4}, 21 | {0x26EA, 0x26EA}, 22 | {0x26F2, 0x26F3}, 23 | {0x26F5, 0x26F5}, 24 | {0x26FA, 0x26FA}, 25 | {0x26FD, 0x26FD}, 26 | {0x2705, 0x2705}, 27 | {0x270A, 0x270B}, 28 | {0x2728, 0x2728}, 29 | {0x274C, 0x274C}, 30 | {0x274E, 0x274E}, 31 | {0x2753, 0x2755}, 32 | {0x2757, 0x2757}, 33 | {0x2795, 0x2797}, 34 | {0x27B0, 0x27B0}, 35 | {0x27BF, 0x27BF}, 36 | {0x2B1B, 0x2B1C}, 37 | {0x2B50, 0x2B50}, 38 | {0x2B55, 0x2B55}, 39 | {0x2E80, 0x2E99}, 40 | {0x2E9B, 0x2EF3}, 41 | {0x2F00, 0x2FD5}, 42 | {0x2FF0, 0x303E}, 43 | {0x3041, 0x3096}, 44 | {0x3099, 0x30FF}, 45 | {0x3105, 0x312F}, 46 | {0x3131, 0x318E}, 47 | {0x3190, 0x31E3}, 48 | {0x31EF, 0x321E}, 49 | {0x3220, 0x3247}, 50 | {0x3250, 0x4DBF}, 51 | {0x4E00, 0xA48C}, 52 | {0xA490, 0xA4C6}, 53 | {0xA960, 0xA97C}, 54 | {0xAC00, 0xD7A3}, 55 | {0xF900, 0xFAFF}, 56 | {0xFE10, 0xFE19}, 57 | {0xFE30, 0xFE52}, 58 | {0xFE54, 0xFE66}, 59 | {0xFE68, 0xFE6B}, 60 | {0xFF01, 0xFF60}, 61 | {0xFFE0, 0xFFE6}, 62 | {0x16FE0, 0x16FE4}, 63 | {0x16FF0, 0x16FF1}, 64 | {0x17000, 0x187F7}, 65 | {0x18800, 0x18CD5}, 66 | {0x18D00, 0x18D08}, 67 | {0x1AFF0, 0x1AFF3}, 68 | {0x1AFF5, 0x1AFFB}, 69 | {0x1AFFD, 0x1AFFE}, 70 | {0x1B000, 0x1B122}, 71 | {0x1B132, 0x1B132}, 72 | {0x1B150, 0x1B152}, 73 | {0x1B155, 0x1B155}, 74 | {0x1B164, 0x1B167}, 75 | {0x1B170, 0x1B2FB}, 76 | {0x1F004, 0x1F004}, 77 | {0x1F0CF, 0x1F0CF}, 78 | {0x1F18E, 0x1F18E}, 79 | {0x1F191, 0x1F19A}, 80 | {0x1F200, 0x1F202}, 81 | {0x1F210, 0x1F23B}, 82 | {0x1F240, 0x1F248}, 83 | {0x1F250, 0x1F251}, 84 | {0x1F260, 0x1F265}, 85 | {0x1F300, 0x1F320}, 86 | {0x1F32D, 0x1F335}, 87 | {0x1F337, 0x1F37C}, 88 | {0x1F37E, 0x1F393}, 89 | {0x1F3A0, 0x1F3CA}, 90 | {0x1F3CF, 0x1F3D3}, 91 | {0x1F3E0, 0x1F3F0}, 92 | {0x1F3F4, 0x1F3F4}, 93 | {0x1F3F8, 0x1F43E}, 94 | {0x1F440, 0x1F440}, 95 | {0x1F442, 0x1F4FC}, 96 | {0x1F4FF, 0x1F53D}, 97 | {0x1F54B, 0x1F54E}, 98 | {0x1F550, 0x1F567}, 99 | {0x1F57A, 0x1F57A}, 100 | {0x1F595, 0x1F596}, 101 | {0x1F5A4, 0x1F5A4}, 102 | {0x1F5FB, 0x1F64F}, 103 | {0x1F680, 0x1F6C5}, 104 | {0x1F6CC, 0x1F6CC}, 105 | {0x1F6D0, 0x1F6D2}, 106 | {0x1F6D5, 0x1F6D7}, 107 | {0x1F6DC, 0x1F6DF}, 108 | {0x1F6EB, 0x1F6EC}, 109 | {0x1F6F4, 0x1F6FC}, 110 | {0x1F7E0, 0x1F7EB}, 111 | {0x1F7F0, 0x1F7F0}, 112 | {0x1F90C, 0x1F93A}, 113 | {0x1F93C, 0x1F945}, 114 | {0x1F947, 0x1F9FF}, 115 | {0x1FA70, 0x1FA7C}, 116 | {0x1FA80, 0x1FA88}, 117 | {0x1FA90, 0x1FABD}, 118 | {0x1FABF, 0x1FAC5}, 119 | {0x1FACE, 0x1FADB}, 120 | {0x1FAE0, 0x1FAE8}, 121 | {0x1FAF0, 0x1FAF8}, 122 | {0x20000, 0x2FFFD}, 123 | {0x30000, 0x3FFFD}, 124 | }; 125 | -------------------------------------------------------------------------------- /src/unicode_nonspacing_table.h: -------------------------------------------------------------------------------- 1 | /* generated by src/common/unicode/generate-unicode_nonspacing_table.pl, do not edit */ 2 | 3 | static const struct mbinterval nonspacing[] = { 4 | {0x00AD, 0x00AD}, 5 | {0x0300, 0x036F}, 6 | {0x0483, 0x0489}, 7 | {0x0591, 0x05BD}, 8 | {0x05BF, 0x05BF}, 9 | {0x05C1, 0x05C2}, 10 | {0x05C4, 0x05C5}, 11 | {0x05C7, 0x05C7}, 12 | {0x0600, 0x0605}, 13 | {0x0610, 0x061A}, 14 | {0x061C, 0x061C}, 15 | {0x064B, 0x065F}, 16 | {0x0670, 0x0670}, 17 | {0x06D6, 0x06DD}, 18 | {0x06DF, 0x06E4}, 19 | {0x06E7, 0x06E8}, 20 | {0x06EA, 0x06ED}, 21 | {0x070F, 0x070F}, 22 | {0x0711, 0x0711}, 23 | {0x0730, 0x074A}, 24 | {0x07A6, 0x07B0}, 25 | {0x07EB, 0x07F3}, 26 | {0x07FD, 0x07FD}, 27 | {0x0816, 0x0819}, 28 | {0x081B, 0x0823}, 29 | {0x0825, 0x0827}, 30 | {0x0829, 0x082D}, 31 | {0x0859, 0x085B}, 32 | {0x0890, 0x089F}, 33 | {0x08CA, 0x0902}, 34 | {0x093A, 0x093A}, 35 | {0x093C, 0x093C}, 36 | {0x0941, 0x0948}, 37 | {0x094D, 0x094D}, 38 | {0x0951, 0x0957}, 39 | {0x0962, 0x0963}, 40 | {0x0981, 0x0981}, 41 | {0x09BC, 0x09BC}, 42 | {0x09C1, 0x09C4}, 43 | {0x09CD, 0x09CD}, 44 | {0x09E2, 0x09E3}, 45 | {0x09FE, 0x0A02}, 46 | {0x0A3C, 0x0A3C}, 47 | {0x0A41, 0x0A51}, 48 | {0x0A70, 0x0A71}, 49 | {0x0A75, 0x0A75}, 50 | {0x0A81, 0x0A82}, 51 | {0x0ABC, 0x0ABC}, 52 | {0x0AC1, 0x0AC8}, 53 | {0x0ACD, 0x0ACD}, 54 | {0x0AE2, 0x0AE3}, 55 | {0x0AFA, 0x0B01}, 56 | {0x0B3C, 0x0B3C}, 57 | {0x0B3F, 0x0B3F}, 58 | {0x0B41, 0x0B44}, 59 | {0x0B4D, 0x0B56}, 60 | {0x0B62, 0x0B63}, 61 | {0x0B82, 0x0B82}, 62 | {0x0BC0, 0x0BC0}, 63 | {0x0BCD, 0x0BCD}, 64 | {0x0C00, 0x0C00}, 65 | {0x0C04, 0x0C04}, 66 | {0x0C3C, 0x0C3C}, 67 | {0x0C3E, 0x0C40}, 68 | {0x0C46, 0x0C56}, 69 | {0x0C62, 0x0C63}, 70 | {0x0C81, 0x0C81}, 71 | {0x0CBC, 0x0CBC}, 72 | {0x0CBF, 0x0CBF}, 73 | {0x0CC6, 0x0CC6}, 74 | {0x0CCC, 0x0CCD}, 75 | {0x0CE2, 0x0CE3}, 76 | {0x0D00, 0x0D01}, 77 | {0x0D3B, 0x0D3C}, 78 | {0x0D41, 0x0D44}, 79 | {0x0D4D, 0x0D4D}, 80 | {0x0D62, 0x0D63}, 81 | {0x0D81, 0x0D81}, 82 | {0x0DCA, 0x0DCA}, 83 | {0x0DD2, 0x0DD6}, 84 | {0x0E31, 0x0E31}, 85 | {0x0E34, 0x0E3A}, 86 | {0x0E47, 0x0E4E}, 87 | {0x0EB1, 0x0EB1}, 88 | {0x0EB4, 0x0EBC}, 89 | {0x0EC8, 0x0ECE}, 90 | {0x0F18, 0x0F19}, 91 | {0x0F35, 0x0F35}, 92 | {0x0F37, 0x0F37}, 93 | {0x0F39, 0x0F39}, 94 | {0x0F71, 0x0F7E}, 95 | {0x0F80, 0x0F84}, 96 | {0x0F86, 0x0F87}, 97 | {0x0F8D, 0x0FBC}, 98 | {0x0FC6, 0x0FC6}, 99 | {0x102D, 0x1030}, 100 | {0x1032, 0x1037}, 101 | {0x1039, 0x103A}, 102 | {0x103D, 0x103E}, 103 | {0x1058, 0x1059}, 104 | {0x105E, 0x1060}, 105 | {0x1071, 0x1074}, 106 | {0x1082, 0x1082}, 107 | {0x1085, 0x1086}, 108 | {0x108D, 0x108D}, 109 | {0x109D, 0x109D}, 110 | {0x135D, 0x135F}, 111 | {0x1712, 0x1714}, 112 | {0x1732, 0x1733}, 113 | {0x1752, 0x1753}, 114 | {0x1772, 0x1773}, 115 | {0x17B4, 0x17B5}, 116 | {0x17B7, 0x17BD}, 117 | {0x17C6, 0x17C6}, 118 | {0x17C9, 0x17D3}, 119 | {0x17DD, 0x17DD}, 120 | {0x180B, 0x180F}, 121 | {0x1885, 0x1886}, 122 | {0x18A9, 0x18A9}, 123 | {0x1920, 0x1922}, 124 | {0x1927, 0x1928}, 125 | {0x1932, 0x1932}, 126 | {0x1939, 0x193B}, 127 | {0x1A17, 0x1A18}, 128 | {0x1A1B, 0x1A1B}, 129 | {0x1A56, 0x1A56}, 130 | {0x1A58, 0x1A60}, 131 | {0x1A62, 0x1A62}, 132 | {0x1A65, 0x1A6C}, 133 | {0x1A73, 0x1A7F}, 134 | {0x1AB0, 0x1B03}, 135 | {0x1B34, 0x1B34}, 136 | {0x1B36, 0x1B3A}, 137 | {0x1B3C, 0x1B3C}, 138 | {0x1B42, 0x1B42}, 139 | {0x1B6B, 0x1B73}, 140 | {0x1B80, 0x1B81}, 141 | {0x1BA2, 0x1BA5}, 142 | {0x1BA8, 0x1BA9}, 143 | {0x1BAB, 0x1BAD}, 144 | {0x1BE6, 0x1BE6}, 145 | {0x1BE8, 0x1BE9}, 146 | {0x1BED, 0x1BED}, 147 | {0x1BEF, 0x1BF1}, 148 | {0x1C2C, 0x1C33}, 149 | {0x1C36, 0x1C37}, 150 | {0x1CD0, 0x1CD2}, 151 | {0x1CD4, 0x1CE0}, 152 | {0x1CE2, 0x1CE8}, 153 | {0x1CED, 0x1CED}, 154 | {0x1CF4, 0x1CF4}, 155 | {0x1CF8, 0x1CF9}, 156 | {0x1DC0, 0x1DFF}, 157 | {0x200B, 0x200F}, 158 | {0x202A, 0x202E}, 159 | {0x2060, 0x206F}, 160 | {0x20D0, 0x20F0}, 161 | {0x2CEF, 0x2CF1}, 162 | {0x2D7F, 0x2D7F}, 163 | {0x2DE0, 0x2DFF}, 164 | {0x302A, 0x302D}, 165 | {0x3099, 0x309A}, 166 | {0xA66F, 0xA672}, 167 | {0xA674, 0xA67D}, 168 | {0xA69E, 0xA69F}, 169 | {0xA6F0, 0xA6F1}, 170 | {0xA802, 0xA802}, 171 | {0xA806, 0xA806}, 172 | {0xA80B, 0xA80B}, 173 | {0xA825, 0xA826}, 174 | {0xA82C, 0xA82C}, 175 | {0xA8C4, 0xA8C5}, 176 | {0xA8E0, 0xA8F1}, 177 | {0xA8FF, 0xA8FF}, 178 | {0xA926, 0xA92D}, 179 | {0xA947, 0xA951}, 180 | {0xA980, 0xA982}, 181 | {0xA9B3, 0xA9B3}, 182 | {0xA9B6, 0xA9B9}, 183 | {0xA9BC, 0xA9BD}, 184 | {0xA9E5, 0xA9E5}, 185 | {0xAA29, 0xAA2E}, 186 | {0xAA31, 0xAA32}, 187 | {0xAA35, 0xAA36}, 188 | {0xAA43, 0xAA43}, 189 | {0xAA4C, 0xAA4C}, 190 | {0xAA7C, 0xAA7C}, 191 | {0xAAB0, 0xAAB0}, 192 | {0xAAB2, 0xAAB4}, 193 | {0xAAB7, 0xAAB8}, 194 | {0xAABE, 0xAABF}, 195 | {0xAAC1, 0xAAC1}, 196 | {0xAAEC, 0xAAED}, 197 | {0xAAF6, 0xAAF6}, 198 | {0xABE5, 0xABE5}, 199 | {0xABE8, 0xABE8}, 200 | {0xABED, 0xABED}, 201 | {0xFB1E, 0xFB1E}, 202 | {0xFE00, 0xFE0F}, 203 | {0xFE20, 0xFE2F}, 204 | {0xFEFF, 0xFEFF}, 205 | {0xFFF9, 0xFFFB}, 206 | {0x101FD, 0x101FD}, 207 | {0x102E0, 0x102E0}, 208 | {0x10376, 0x1037A}, 209 | {0x10A01, 0x10A0F}, 210 | {0x10A38, 0x10A3F}, 211 | {0x10AE5, 0x10AE6}, 212 | {0x10D24, 0x10D27}, 213 | {0x10EAB, 0x10EAC}, 214 | {0x10EFD, 0x10EFF}, 215 | {0x10F46, 0x10F50}, 216 | {0x10F82, 0x10F85}, 217 | {0x11001, 0x11001}, 218 | {0x11038, 0x11046}, 219 | {0x11070, 0x11070}, 220 | {0x11073, 0x11074}, 221 | {0x1107F, 0x11081}, 222 | {0x110B3, 0x110B6}, 223 | {0x110B9, 0x110BA}, 224 | {0x110BD, 0x110BD}, 225 | {0x110C2, 0x110CD}, 226 | {0x11100, 0x11102}, 227 | {0x11127, 0x1112B}, 228 | {0x1112D, 0x11134}, 229 | {0x11173, 0x11173}, 230 | {0x11180, 0x11181}, 231 | {0x111B6, 0x111BE}, 232 | {0x111C9, 0x111CC}, 233 | {0x111CF, 0x111CF}, 234 | {0x1122F, 0x11231}, 235 | {0x11234, 0x11234}, 236 | {0x11236, 0x11237}, 237 | {0x1123E, 0x1123E}, 238 | {0x11241, 0x11241}, 239 | {0x112DF, 0x112DF}, 240 | {0x112E3, 0x112EA}, 241 | {0x11300, 0x11301}, 242 | {0x1133B, 0x1133C}, 243 | {0x11340, 0x11340}, 244 | {0x11366, 0x11374}, 245 | {0x11438, 0x1143F}, 246 | {0x11442, 0x11444}, 247 | {0x11446, 0x11446}, 248 | {0x1145E, 0x1145E}, 249 | {0x114B3, 0x114B8}, 250 | {0x114BA, 0x114BA}, 251 | {0x114BF, 0x114C0}, 252 | {0x114C2, 0x114C3}, 253 | {0x115B2, 0x115B5}, 254 | {0x115BC, 0x115BD}, 255 | {0x115BF, 0x115C0}, 256 | {0x115DC, 0x115DD}, 257 | {0x11633, 0x1163A}, 258 | {0x1163D, 0x1163D}, 259 | {0x1163F, 0x11640}, 260 | {0x116AB, 0x116AB}, 261 | {0x116AD, 0x116AD}, 262 | {0x116B0, 0x116B5}, 263 | {0x116B7, 0x116B7}, 264 | {0x1171D, 0x1171F}, 265 | {0x11722, 0x11725}, 266 | {0x11727, 0x1172B}, 267 | {0x1182F, 0x11837}, 268 | {0x11839, 0x1183A}, 269 | {0x1193B, 0x1193C}, 270 | {0x1193E, 0x1193E}, 271 | {0x11943, 0x11943}, 272 | {0x119D4, 0x119DB}, 273 | {0x119E0, 0x119E0}, 274 | {0x11A01, 0x11A0A}, 275 | {0x11A33, 0x11A38}, 276 | {0x11A3B, 0x11A3E}, 277 | {0x11A47, 0x11A47}, 278 | {0x11A51, 0x11A56}, 279 | {0x11A59, 0x11A5B}, 280 | {0x11A8A, 0x11A96}, 281 | {0x11A98, 0x11A99}, 282 | {0x11C30, 0x11C3D}, 283 | {0x11C3F, 0x11C3F}, 284 | {0x11C92, 0x11CA7}, 285 | {0x11CAA, 0x11CB0}, 286 | {0x11CB2, 0x11CB3}, 287 | {0x11CB5, 0x11CB6}, 288 | {0x11D31, 0x11D45}, 289 | {0x11D47, 0x11D47}, 290 | {0x11D90, 0x11D91}, 291 | {0x11D95, 0x11D95}, 292 | {0x11D97, 0x11D97}, 293 | {0x11EF3, 0x11EF4}, 294 | {0x11F00, 0x11F01}, 295 | {0x11F36, 0x11F3A}, 296 | {0x11F40, 0x11F40}, 297 | {0x11F42, 0x11F42}, 298 | {0x13430, 0x13440}, 299 | {0x13447, 0x13455}, 300 | {0x16AF0, 0x16AF4}, 301 | {0x16B30, 0x16B36}, 302 | {0x16F4F, 0x16F4F}, 303 | {0x16F8F, 0x16F92}, 304 | {0x16FE4, 0x16FE4}, 305 | {0x1BC9D, 0x1BC9E}, 306 | {0x1BCA0, 0x1CF46}, 307 | {0x1D167, 0x1D169}, 308 | {0x1D173, 0x1D182}, 309 | {0x1D185, 0x1D18B}, 310 | {0x1D1AA, 0x1D1AD}, 311 | {0x1D242, 0x1D244}, 312 | {0x1DA00, 0x1DA36}, 313 | {0x1DA3B, 0x1DA6C}, 314 | {0x1DA75, 0x1DA75}, 315 | {0x1DA84, 0x1DA84}, 316 | {0x1DA9B, 0x1DAAF}, 317 | {0x1E000, 0x1E02A}, 318 | {0x1E08F, 0x1E08F}, 319 | {0x1E130, 0x1E136}, 320 | {0x1E2AE, 0x1E2AE}, 321 | {0x1E2EC, 0x1E2EF}, 322 | {0x1E4EC, 0x1E4EF}, 323 | {0x1E8D0, 0x1E8D6}, 324 | {0x1E944, 0x1E94A}, 325 | {0xE0001, 0xE01EF}, 326 | }; 327 | -------------------------------------------------------------------------------- /tests/def.txt: -------------------------------------------------------------------------------- 1 | Table "pg_catalog.pg_class" 2 | ┌─────────────────────┬──────────────┬───────────┬──────────┬─────────┐ 3 | │ Column │ Type │ Collation │ Nullable │ Default │ 4 | ╞═════════════════════╪══════════════╪═══════════╪══════════╪═════════╡ 5 | │ oid │ oid │ │ not null │ │ 6 | │ relname │ name │ │ not null │ │ 7 | │ relnamespace │ oid │ │ not null │ │ 8 | │ reltype │ oid │ │ not null │ │ 9 | │ reloftype │ oid │ │ not null │ │ 10 | │ relowner │ oid │ │ not null │ │ 11 | │ relam │ oid │ │ not null │ │ 12 | │ relfilenode │ oid │ │ not null │ │ 13 | │ reltablespace │ oid │ │ not null │ │ 14 | │ relpages │ integer │ │ not null │ │ 15 | │ reltuples │ real │ │ not null │ │ 16 | │ relallvisible │ integer │ │ not null │ │ 17 | │ reltoastrelid │ oid │ │ not null │ │ 18 | │ relhasindex │ boolean │ │ not null │ │ 19 | │ relisshared │ boolean │ │ not null │ │ 20 | │ relpersistence │ "char" │ │ not null │ │ 21 | │ relkind │ "char" │ │ not null │ │ 22 | │ relnatts │ smallint │ │ not null │ │ 23 | │ relchecks │ smallint │ │ not null │ │ 24 | │ relhasrules │ boolean │ │ not null │ │ 25 | │ relhastriggers │ boolean │ │ not null │ │ 26 | │ relhassubclass │ boolean │ │ not null │ │ 27 | │ relrowsecurity │ boolean │ │ not null │ │ 28 | │ relforcerowsecurity │ boolean │ │ not null │ │ 29 | │ relispopulated │ boolean │ │ not null │ │ 30 | │ relreplident │ "char" │ │ not null │ │ 31 | │ relispartition │ boolean │ │ not null │ │ 32 | │ relrewrite │ oid │ │ not null │ │ 33 | │ relfrozenxid │ xid │ │ not null │ │ 34 | │ relminmxid │ xid │ │ not null │ │ 35 | │ relacl │ aclitem[] │ │ │ │ 36 | │ reloptions │ text[] │ C │ │ │ 37 | │ relpartbound │ pg_node_tree │ C │ │ │ 38 | └─────────────────────┴──────────────┴───────────┴──────────┴─────────┘ 39 | Indexes: 40 | "pg_class_oid_index" UNIQUE, btree (oid) 41 | "pg_class_relname_nsp_index" UNIQUE, btree (relname, relnamespace) 42 | "pg_class_tblspc_relfilenode_index" btree (reltablespace, relfilenode) 43 | 44 | -------------------------------------------------------------------------------- /tests/err.txt: -------------------------------------------------------------------------------- 1 | +-[ RECORD 1 ]-----+ 2 | | ?column? | ahoj +| 3 | | | svete+| 4 | | | xxxx | 5 | +----------+-------+ 6 | 7 | -------------------------------------------------------------------------------- /tests/help.txt: -------------------------------------------------------------------------------- 1 | General 2 | \copyright show PostgreSQL usage and distribution terms 3 | \crosstabview [COLUMNS] execute query and display results in crosstab 4 | \errverbose show most recent error message at maximum verbosity 5 | \g [FILE] or ; execute query (and send results to file or |pipe) 6 | \gdesc describe result of query, without executing it 7 | \gexec execute query, then execute each value in its result 8 | \gset [PREFIX] execute query and store results in psql variables 9 | \gx [FILE] as \g, but forces expanded output mode 10 | \q quit psql 11 | \watch [SEC] execute query every SEC seconds 12 | 13 | Help 14 | \? [commands] show help on backslash commands 15 | \? options show help on psql command-line options 16 | \? variables show help on special variables 17 | \h [NAME] help on syntax of SQL commands, * for all commands 18 | 19 | Query Buffer 20 | \e [FILE] [LINE] edit the query buffer (or file) with external editor 21 | \ef [FUNCNAME [LINE]] edit function definition with external editor 22 | \ev [VIEWNAME [LINE]] edit view definition with external editor 23 | \p show the contents of the query buffer 24 | \r reset (clear) the query buffer 25 | \s [FILE] display history or save it to file 26 | \w FILE write query buffer to file 27 | 28 | Input/Output 29 | \copy ... perform SQL COPY with data stream to the client host 30 | \echo [STRING] write string to standard output 31 | \i FILE execute commands from file 32 | \ir FILE as \i, but relative to location of current script 33 | \o [FILE] send all query results to file or |pipe 34 | \qecho [STRING] write string to query output stream (see \o) 35 | 36 | Conditional 37 | \if EXPR begin conditional block 38 | \elif EXPR alternative within current conditional block 39 | \else final alternative within current conditional block 40 | \endif end conditional block 41 | 42 | Informational 43 | (options: S = show system objects, + = additional detail) 44 | \d[S+] list tables, views, and sequences 45 | \d[S+] NAME describe table, view, sequence, or index 46 | \da[S] [PATTERN] list aggregates 47 | \dA[+] [PATTERN] list access methods 48 | \db[+] [PATTERN] list tablespaces 49 | \dc[S+] [PATTERN] list conversions 50 | \dC[+] [PATTERN] list casts 51 | \dd[S] [PATTERN] show object descriptions not displayed elsewhere 52 | \dD[S+] [PATTERN] list domains 53 | \ddp [PATTERN] list default privileges 54 | \dE[S+] [PATTERN] list foreign tables 55 | \det[+] [PATTERN] list foreign tables 56 | \des[+] [PATTERN] list foreign servers 57 | \deu[+] [PATTERN] list user mappings 58 | \dew[+] [PATTERN] list foreign-data wrappers 59 | \df[anptw][S+] [PATRN] list [only agg/normal/procedures/trigger/window] functions 60 | \dF[+] [PATTERN] list text search configurations 61 | \dFd[+] [PATTERN] list text search dictionaries 62 | \dFp[+] [PATTERN] list text search parsers 63 | \dFt[+] [PATTERN] list text search templates 64 | \dg[S+] [PATTERN] list roles 65 | \di[S+] [PATTERN] list indexes 66 | \dl list large objects, same as \lo_list 67 | \dL[S+] [PATTERN] list procedural languages 68 | \dm[S+] [PATTERN] list materialized views 69 | \dn[S+] [PATTERN] list schemas 70 | \do[S] [PATTERN] list operators 71 | \dO[S+] [PATTERN] list collations 72 | \dp [PATTERN] list table, view, and sequence access privileges 73 | \drds [PATRN1 [PATRN2]] list per-database role settings 74 | \dRp[+] [PATTERN] list replication publications 75 | \dRs[+] [PATTERN] list replication subscriptions 76 | \ds[S+] [PATTERN] list sequences 77 | \dt[S+] [PATTERN] list tables 78 | \dT[S+] [PATTERN] list data types 79 | \du[S+] [PATTERN] list roles 80 | \dv[S+] [PATTERN] list views 81 | \dx[+] [PATTERN] list extensions 82 | \dy [PATTERN] list event triggers 83 | \l[+] [PATTERN] list databases 84 | \sf[+] FUNCNAME show a function's definition 85 | \sv[+] VIEWNAME show a view's definition 86 | \z [PATTERN] same as \dp 87 | 88 | Formatting 89 | \a toggle between unaligned and aligned output mode 90 | \C [STRING] set table title, or unset if none 91 | \f [STRING] show or set field separator for unaligned query output 92 | \H toggle HTML output mode (currently off) 93 | \pset [NAME [VALUE]] set table output option 94 | (border|columns|csv_fieldsep|expanded|fieldsep| 95 | fieldsep_zero|footer|format|linestyle|null| 96 | numericlocale|pager|pager_min_lines|recordsep| 97 | recordsep_zero|tableattr|title|tuples_only| 98 | unicode_border_linestyle|unicode_column_linestyle| 99 | unicode_header_linestyle) 100 | \t [on|off] show only rows (currently off) 101 | \T [STRING] set HTML tag attributes, or unset if none 102 | \x [on|off|auto] toggle expanded output (currently off) 103 | 104 | Connection 105 | \c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo} 106 | connect to new database (currently "postgres") 107 | \conninfo display information about current connection 108 | \encoding [ENCODING] show or set client encoding 109 | \password [USERNAME] securely change the password for a user 110 | 111 | Operating System 112 | \cd [DIR] change the current working directory 113 | \setenv NAME [VALUE] set or unset environment variable 114 | \timing [on|off] toggle timing of commands (currently off) 115 | \! [COMMAND] execute command in shell or start interactive shell 116 | 117 | Variables 118 | \prompt [TEXT] NAME prompt user to set internal variable 119 | \set [NAME [VALUE]] set internal variable, or list all if no parameters 120 | \unset NAME unset (delete) internal variable 121 | 122 | Large Objects 123 | \lo_export LOBOID FILE 124 | \lo_import FILE [COMMENT] 125 | \lo_list 126 | \lo_unlink LOBOID large object operations 127 | -------------------------------------------------------------------------------- /tests/monet-def.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "import"."import_template" ( 2 | "id" BIGINT NOT NULL DEFAULT next value for "import"."seq_8886", 3 | "created_by" VARCHAR(128) NOT NULL, 4 | "created_timestamp" TIMESTAMP NOT NULL DEFAULT "sys"."current_timestamp"(), 5 | "modified_by" VARCHAR(128) NOT NULL, 6 | "modified_timestamp" TIMESTAMP NOT NULL DEFAULT "sys"."current_timestamp"(), 7 | "import_name" VARCHAR(128) NOT NULL, 8 | "template_name" VARCHAR(128) NOT NULL, 9 | "server_name" VARCHAR(256) NOT NULL, 10 | "database_name" VARCHAR(256) NOT NULL, 11 | "sort_order" INTEGER NOT NULL, 12 | CONSTRAINT "import_template_id_pkey" PRIMARY KEY ("id"), 13 | CONSTRAINT "import_template_import_name_fkey" FOREIGN KEY ("import_name") REFERENCES "import"."import" ("name"), 14 | CONSTRAINT "import_template_server_name_fkey" FOREIGN KEY ("server_name") REFERENCES "import"."server" ("name"), 15 | CONSTRAINT "import_template_template_name_fkey" FOREIGN KEY ("template_name") REFERENCES "import"."database_template" ("name") 16 | ); 17 | -------------------------------------------------------------------------------- /tests/multiline-a.txt: -------------------------------------------------------------------------------- 1 | +---+---+---+ 2 | | a | b | c | 3 | +---+---+---+ 4 | | 1 | a+| a+| 5 | | | b | b+| 6 | | | | c | 7 | | 3 | a+| a+| 8 | | | b | b+| 9 | | | | c | 10 | | 2 | a+| a+| 11 | | | b | b+| 12 | | | | c | 13 | +---+---+---+ 14 | (3 rows) 15 | 16 | -------------------------------------------------------------------------------- /tests/multiline-u.txt: -------------------------------------------------------------------------------- 1 | ┌───┬───┬───┐ 2 | │ a │ b │ c │ 3 | ╞═══╪═══╪═══╡ 4 | │ 1 │ a↵│ a↵│ 5 | │ │ b │ b↵│ 6 | │ │ │ c │ 7 | │ 3 │ a↵│ a↵│ 8 | │ │ b │ b↵│ 9 | │ │ │ c │ 10 | │ 2 │ a↵│ a↵│ 11 | │ │ b │ b↵│ 12 | │ │ │ c │ 13 | └───┴───┴───┘ 14 | (3 rows) 15 | 16 | -------------------------------------------------------------------------------- /tests/mysql-ascii.txt: -------------------------------------------------------------------------------- 1 | +------+------------------+-----------------------------------------------------------------------------------------------------------------------+-------------+-------+--------+--------+------------------------------------------------------------------------------------------------------------------------------------------------+ 2 | | FID | title | description | category | price | length | rating | actors | 3 | +------+------------------+-----------------------------------------------------------------------------------------------------------------------+-------------+-------+--------+--------+------------------------------------------------------------------------------------------------------------------------------------------------+ 4 | | 1 | ACADEMY DINOSAUR | A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies | Documentary | 0.99 | 86 | PG | Penelope Guiness, Christian Gable, Lucille Tracy, Sandra Peck, Johnny Cage, Mena Temple, Warren Nolte, Oprah Kilmer, Rock Dukakis, Mary Keitel | 5 | | 2 | ACE GOLDFINGER | A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China | Horror | 4.99 | 48 | G | Bob Fawcett, Minnie Zellweger, Sean Guiness, Chris Depp | 6 | | 3 | ADAPTATION HOLES | A Astounding Reflection of a Lumberjack And a Car who must Sink a Lumberjack in A Baloon Factory | Documentary | 2.99 | 50 | NC-17 | Nick Wahlberg, Bob Fawcett, Cameron Streep, Ray Johansson, Julianne Dench | 7 | | 4 | AFFAIR PREJUDICE | A Fanciful Documentary of a Frisbee And a Lumberjack who must Chase a Monkey in A Shark Tank | Horror | 2.99 | 117 | G | Jodie Degeneres, Scarlett Damon, Kenneth Pesci, Fay Winslet, Oprah Kilmer | 8 | | 5 | AFRICAN EGG | A Fast-Paced Documentary of a Pastry Chef And a Dentist who must Pursue a Forensic Psychologist in The Gulf of Mexico | Family | 2.99 | 130 | G | Gary Phoenix, Dustin Tautou, Matthew Leigh, Matthew Carrey, Thora Temple | 9 | | 6 | AGENT TRUMAN | A Intrepid Panorama of a Robot And a Boy who must Escape a Sumo Wrestler in Ancient China | Foreign | 2.99 | 169 | PG | Kirsten Paltrow, Sandra Kilmer, Jayne Neeson, Warren Nolte, Morgan Williams, Kenneth Hoffman, Reese West | 10 | | 7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet Boat | Comedy | 4.99 | 62 | PG-13 | Jim Mostel, Richard Penn, Oprah Kilmer, Mena Hopper, Michael Bolger | 11 | | 8 | AIRPORT POLLOCK | A Epic Tale of a Moose And a Girl who must Confront a Monkey in Ancient India | Horror | 4.99 | 54 | R | Fay Kilmer, Gene Willis, Susan Davis, Lucille Dee | 12 | | 9 | ALABAMA DEVIL | A Thoughtful Panorama of a Database Administrator And a Mad Scientist who must Outgun a Mad Scientist in A Jet Boat | Horror | 2.99 | 114 | PG-13 | Christian Gable, Elvis Marx, Rip Crawford, Mena Temple, Rip Winslet, Warren Nolte, Greta Keitel, William Hackman, Meryl Allen | 13 | | 10 | ALADDIN CALENDAR | A Action-Packed Tale of a Man And a Lumberjack who must Reach a Feminist in Ancient China | Sports | 4.99 | 63 | NC-17 | Alec Wayne, Judy Dean, Val Bolger, Ray Johansson, Renee Tracy, Jada Ryder, Greta Malden, Rock Dukakis | 14 | +------+------------------+-----------------------------------------------------------------------------------------------------------------------+-------------+-------+--------+--------+------------------------------------------------------------------------------------------------------------------------------------------------+ 15 | 10 rows in set (0.06 sec) 16 | 17 | MariaDB [sakila]> -------------------------------------------------------------------------------- /tests/mysql.txt: -------------------------------------------------------------------------------- 1 | +------+------------------+ 2 | | fid | title | 3 | +------+------------------+ 4 | | 1 | ACADEMY DINOSAUR | 5 | | 2 | ACE GOLDFINGER | 6 | | 3 | ADAPTATION HOLES | 7 | | 4 | AFFAIR PREJUDICE | 8 | | 5 | AFRICAN EGG | 9 | | 6 | AGENT TRUMAN | 10 | | 7 | AIRPLANE SIERRA | 11 | | 8 | AIRPORT POLLOCK | 12 | | 9 | ALABAMA DEVIL | 13 | | 10 | ALADDIN CALENDAR | 14 | +------+------------------+ 15 | (10 rows) in set (0.06 sec) -------------------------------------------------------------------------------- /tests/nu.txt: -------------------------------------------------------------------------------- 1 | ╭───┬──────┬───────────────────────────────────────────┬──────┬───────────┬──────────────────┬──────────────╮ 2 | │ # │ name │ brand │ freq │ cpu_usage │ load_average │ vendor_id │ 3 | ├───┼──────┼───────────────────────────────────────────┼──────┼───────────┼──────────────────┼──────────────┤ 4 | │ 0 │ cpu0 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 5 | │ 1 │ cpu1 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 6 | │ 2 │ cpu2 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 7 | │ 3 │ cpu3 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 8 | │ 4 │ cpu4 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 9 | │ 5 │ cpu5 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 10 | │ 6 │ cpu6 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 11 | │ 7 │ cpu7 │ Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz │ 4 │ 0.00 │ 0.82, 0.86, 0.91 │ GenuineIntel │ 12 | ╰───┴──────┴───────────────────────────────────────────┴──────┴───────────┴──────────────────┴──────────────╯ 13 | 14 | -------------------------------------------------------------------------------- /tests/pg_class2.txt: -------------------------------------------------------------------------------- 1 | oid | relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | relallvisible | reltoastrelid | relhasindex | relisshared | relpersistence | relkind | relnatts | relchecks | relhasrules | relhastriggers | relhassubclass | relrowsecurity | relforcerowsecurity | relispopulated | relreplident | relispartition | relrewrite | relfrozenxid | relminmxid | relacl | reloptions | relpartbound 2 | -------+----------------------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---------------+---------------+-------------+-------------+----------------+---------+----------+-----------+-------------+----------------+----------------+----------------+---------------------+----------------+--------------+----------------+------------+--------------+------------+-----------------------------------------+------------+-------------- 3 | 16402 | pg_toast_16399 | 99 | 16403 | 0 | 16384 | 2 | 16402 | 0 | 0 | 0 | 0 | 0 | t | f | p | t | 3 | 0 | f | f | f | f | f | t | n | f | 0 | 497 | 1 | ∅ | ∅ | ∅ 4 | 16404 | pg_toast_16399_index | 99 | 0 | 0 | 16384 | 403 | 16404 | 0 | 1 | 0 | 0 | 0 | f | f | p | i | 2 | 0 | f | f | f | f | f | t | n | f | 0 | 0 | 0 | ∅ | ∅ | ∅ 5 | 16399 | foo | 2200 | 16401 | 0 | 16384 | 2 | 16399 | 0 | 0 | 0 | 0 | 16402 | f | f | p | r | 1 | 0 | f | f | f | f | f | t | d | f | 0 | 497 | 1 | ∅ | ∅ | ∅ 6 | 2619 | pg_statistic | 11 | 12016 | 0 | 10 | 2 | 2619 | 0 | 19 | 410 | 19 | 2840 | t | f | p | r | 31 | 0 | f | f | f | f | f | t | n | f | 0 | 481 | 1 | {postgres=arwdDxt/postgres} | ∅ | ∅ 7 | 1247 | pg_type | 11 | 71 | 0 | 10 | 2 | 0 | 0 | 10 | 401 | 10 | 4171 | t | f | p | r | 31 | 0 | f | f | f | f | f | t | n | f | 0 | 481 | 1 | {postgres=arwdDxt/postgres,=r/postgres} | ∅ | ∅ 8 | 4159 | pg_toast_2600 | 99 | 12054 | 0 | 10 | 2 | 4159 | 0 | 0 | 0 | 0 | 0 | t | f | p | t | 3 | 0 | f | f | f | f | f | t | n | f | 0 | 481 | 1 | ∅ | ∅ | ∅ 9 | 4160 | pg_toast_2600_index | 99 | 0 | 0 | 10 | 403 | 4160 | 0 | 1 | 0 | 0 | 0 | f | f | p | i | 2 | 0 | f | f | f | f | f | t | n | f | 0 | 0 | 0 | ∅ | ∅ | ∅ 10 | 2830 | pg_toast_2604 | 99 | 12055 | 0 | 10 | 2 | 2830 | 0 | 0 | 0 | 0 | 0 | t | f | p | t | 3 | 0 | f | f | f | f | f | t | n | f | 0 | 481 | 1 | ∅ | ∅ | ∅ 11 | 2831 | pg_toast_2604_index | 99 | 0 | 0 | 10 | 403 | 2831 | 0 | 1 | 0 | 0 | 0 | f | f | p | i | 2 | 0 | f | f | f | f | f | t | n | f | 0 | 0 | 0 | ∅ | ∅ | ∅ 12 | 4161 | pg_toast_3456 | 99 | 12056 | 0 | 10 | 2 | 4161 | 0 | 0 | 0 | 0 | 0 | t | f | p | t | 3 | 0 | f | f | f | f | f | t | n | f | 0 | 481 | 1 | ∅ | ∅ | ∅ 13 | (10 rows) 14 | 15 | -------------------------------------------------------------------------------- /tests/select1.txt: -------------------------------------------------------------------------------- 1 | +------------+ 2 | | ?column? | 3 | |------------| 4 | | 1 | 5 | +------------+ 6 | SELECT 1 7 | 8 | -------------------------------------------------------------------------------- /tests/single.txt: -------------------------------------------------------------------------------- 1 | ┌─────────┐ 2 | │ column1 │ 3 | ╞═════════╡ 4 | │ 1 │ 5 | │ 3 │ 6 | └─────────┘ 7 | (2 rows) 8 | 9 | -------------------------------------------------------------------------------- /tests/small.txt: -------------------------------------------------------------------------------- 1 | ┌─────────────┬───────┬───────┐ 2 | │ a │ b │ c │ 3 | ╞═════════════╪═══════╪═══════╡ 4 | │ tomas │ tomas │ tomas │ 5 | │ pavel pavel │ tomas │ tomas │ 6 | │ petr │ tomas │ tomas │ 7 | └─────────────┴───────┴───────┘ 8 | (3 rows) 9 | 10 | -------------------------------------------------------------------------------- /tests/small2.txt: -------------------------------------------------------------------------------- 1 | +--------------+-------+-------+ 2 | | a | b | c | 3 | +--------------+-------+-------+ 4 | | tomas | tomas | tomas | 5 | | pavel a petr | tomas | tomas | 6 | | pavel | tomas | tomas | 7 | +--------------+-------+-------+ 8 | (3 rows) 9 | 10 | -------------------------------------------------------------------------------- /tests/strange.txt: -------------------------------------------------------------------------------- 1 | ┌──────┬───────┬───────────────┬───────────────────────────┬───────┐ 2 | │ 1995 │ Opel │ Vectra │ klimatizace, střešní okno │ 45000 │ 3 | │ 1998 │ Škoda │ Felicia "Fun" │ │ 80000 │ 4 | │ 2002 │ Škoda │ Octavia │ klimatizace, ABS bouraná │ 70000 │ 5 | └──────┴───────┴───────────────┴───────────────────────────┴───────┘ 6 | (3 rows) 7 | -------------------------------------------------------------------------------- /tests/strange2.txt: -------------------------------------------------------------------------------- 1 | OWNER TABLE_NAME COLUMN_NAME DATA_TYPE DATA_TYPE_MOD DATA_TYPE_OWNER DATA_LENGTH DATA_PRECISION DATA_SCALE NULLABLE COLUMN_ID DEFAULT_LENGTH DATA_DEFAULT NUM_DISTINCT LOW_VALUE HIGH_VALUE DENSITY NUM_NULLS NUM_BUCKETS LAST_ANALYZED SAMPLE_SIZE CHARACTER_SET_NAME CHAR_COL_DECL_LENGTH GLOBAL_STATS USER_STATS AVG_COL_LEN CHAR_LENGTH CHAR_USED V80_FMT_IMAGE DATA_UPGRADED HISTOGRAM DEFAULT_ON_NULL IDENTITY_COLUMN EVALUATION_EDITION UNUSABLE_BEFORE UNUSABLE_BEGINNING COLLATION 2 | --------- ------------- -------------- ------------ ---------------- ------------------ -------------- ----------------- ------------- ----------- ------------ ----------------- --------------- --------------- ------------ ------------- ---------- ------------ -------------- ---------------- -------------- --------------------- ----------------------- --------------- ------------- -------------- -------------- ------------ ---------------- ---------------- ------------ ------------------ ------------------ --------------------- ------------------ --------------------- ------------ 3 | SYSTEM T2 A NUMBER 22 0 Y 1 1 C102 C102 1 0 1 28-OCT-21 2 YES NO 3 0 NO YES NONE NO NO 4 | SYSTEM T2 B NUMBER 22 0 Y 2 1 C103 C103 1 0 1 28-OCT-21 2 YES NO 3 0 NO YES NONE NO NO 5 | 6 | -------------------------------------------------------------------------------- /tests/tables.txt: -------------------------------------------------------------------------------- 1 | List of relations 2 | ┌────────────┬─────────────────────────┬───────┬──────────┬─────────────┬────────────┬─────────────┐ 3 | │ Schema │ Name │ Type │ Owner │ Persistence │ Size │ Description │ 4 | ╞════════════╪═════════════════════════╪═══════╪══════════╪═════════════╪════════════╪═════════════╡ 5 | │ pg_catalog │ pg_aggregate │ table │ postgres │ permanent │ 56 kB │ │ 6 | │ pg_catalog │ pg_am │ table │ postgres │ permanent │ 40 kB │ │ 7 | │ pg_catalog │ pg_amop │ table │ postgres │ permanent │ 80 kB │ │ 8 | │ pg_catalog │ pg_amproc │ table │ postgres │ permanent │ 56 kB │ │ 9 | │ pg_catalog │ pg_attrdef │ table │ postgres │ permanent │ 8192 bytes │ │ 10 | │ pg_catalog │ pg_attribute │ table │ postgres │ permanent │ 464 kB │ │ 11 | │ pg_catalog │ pg_auth_members │ table │ postgres │ permanent │ 40 kB │ │ 12 | │ pg_catalog │ pg_authid │ table │ postgres │ permanent │ 48 kB │ │ 13 | │ pg_catalog │ pg_cast │ table │ postgres │ permanent │ 48 kB │ │ 14 | │ pg_catalog │ pg_class │ table │ postgres │ permanent │ 136 kB │ │ 15 | │ pg_catalog │ pg_collation │ table │ postgres │ permanent │ 296 kB │ │ 16 | │ pg_catalog │ pg_constraint │ table │ postgres │ permanent │ 48 kB │ │ 17 | │ pg_catalog │ pg_conversion │ table │ postgres │ permanent │ 48 kB │ │ 18 | │ pg_catalog │ pg_database │ table │ postgres │ permanent │ 48 kB │ │ 19 | │ pg_catalog │ pg_db_role_setting │ table │ postgres │ permanent │ 8192 bytes │ │ 20 | │ pg_catalog │ pg_default_acl │ table │ postgres │ permanent │ 8192 bytes │ │ 21 | │ pg_catalog │ pg_depend │ table │ postgres │ permanent │ 488 kB │ │ 22 | │ pg_catalog │ pg_description │ table │ postgres │ permanent │ 320 kB │ │ 23 | │ pg_catalog │ pg_enum │ table │ postgres │ permanent │ 0 bytes │ │ 24 | │ pg_catalog │ pg_event_trigger │ table │ postgres │ permanent │ 8192 bytes │ │ 25 | │ pg_catalog │ pg_extension │ table │ postgres │ permanent │ 48 kB │ │ 26 | │ pg_catalog │ pg_foreign_data_wrapper │ table │ postgres │ permanent │ 8192 bytes │ │ 27 | │ pg_catalog │ pg_foreign_server │ table │ postgres │ permanent │ 8192 bytes │ │ 28 | │ pg_catalog │ pg_foreign_table │ table │ postgres │ permanent │ 8192 bytes │ │ 29 | │ pg_catalog │ pg_index │ table │ postgres │ permanent │ 64 kB │ │ 30 | │ pg_catalog │ pg_inherits │ table │ postgres │ permanent │ 0 bytes │ │ 31 | │ pg_catalog │ pg_init_privs │ table │ postgres │ permanent │ 56 kB │ │ 32 | │ pg_catalog │ pg_language │ table │ postgres │ permanent │ 48 kB │ │ 33 | │ pg_catalog │ pg_largeobject │ table │ postgres │ permanent │ 0 bytes │ │ 34 | │ pg_catalog │ pg_largeobject_metadata │ table │ postgres │ permanent │ 0 bytes │ │ 35 | │ pg_catalog │ pg_namespace │ table │ postgres │ permanent │ 48 kB │ │ 36 | │ pg_catalog │ pg_opclass │ table │ postgres │ permanent │ 48 kB │ │ 37 | │ pg_catalog │ pg_operator │ table │ postgres │ permanent │ 144 kB │ │ 38 | │ pg_catalog │ pg_opfamily │ table │ postgres │ permanent │ 48 kB │ │ 39 | │ pg_catalog │ pg_partitioned_table │ table │ postgres │ permanent │ 8192 bytes │ │ 40 | │ pg_catalog │ pg_pltemplate │ table │ postgres │ permanent │ 48 kB │ │ 41 | │ pg_catalog │ pg_policy │ table │ postgres │ permanent │ 8192 bytes │ │ 42 | │ pg_catalog │ pg_proc │ table │ postgres │ permanent │ 672 kB │ │ 43 | │ pg_catalog │ pg_publication │ table │ postgres │ permanent │ 0 bytes │ │ 44 | │ pg_catalog │ pg_publication_rel │ table │ postgres │ permanent │ 0 bytes │ │ 45 | │ pg_catalog │ pg_range │ table │ postgres │ permanent │ 40 kB │ │ 46 | │ pg_catalog │ pg_replication_origin │ table │ postgres │ permanent │ 8192 bytes │ │ 47 | │ pg_catalog │ pg_rewrite │ table │ postgres │ permanent │ 632 kB │ │ 48 | │ pg_catalog │ pg_seclabel │ table │ postgres │ permanent │ 8192 bytes │ │ 49 | │ pg_catalog │ pg_sequence │ table │ postgres │ permanent │ 0 bytes │ │ 50 | │ pg_catalog │ pg_shdepend │ table │ postgres │ permanent │ 40 kB │ │ 51 | │ pg_catalog │ pg_shdescription │ table │ postgres │ permanent │ 48 kB │ │ 52 | │ pg_catalog │ pg_shseclabel │ table │ postgres │ permanent │ 8192 bytes │ │ 53 | │ pg_catalog │ pg_statistic │ table │ postgres │ permanent │ 256 kB │ │ 54 | │ pg_catalog │ pg_statistic_ext │ table │ postgres │ permanent │ 8192 bytes │ │ 55 | │ pg_catalog │ pg_statistic_ext_data │ table │ postgres │ permanent │ 8192 bytes │ │ 56 | │ pg_catalog │ pg_subscription │ table │ postgres │ permanent │ 8192 bytes │ │ 57 | │ pg_catalog │ pg_subscription_rel │ table │ postgres │ permanent │ 0 bytes │ │ 58 | │ pg_catalog │ pg_tablespace │ table │ postgres │ permanent │ 48 kB │ │ 59 | │ pg_catalog │ pg_transform │ table │ postgres │ permanent │ 0 bytes │ │ 60 | │ pg_catalog │ pg_trigger │ table │ postgres │ permanent │ 8192 bytes │ │ 61 | │ pg_catalog │ pg_ts_config │ table │ postgres │ permanent │ 40 kB │ │ 62 | │ pg_catalog │ pg_ts_config_map │ table │ postgres │ permanent │ 56 kB │ │ 63 | │ pg_catalog │ pg_ts_dict │ table │ postgres │ permanent │ 48 kB │ │ 64 | │ pg_catalog │ pg_ts_parser │ table │ postgres │ permanent │ 40 kB │ │ 65 | │ pg_catalog │ pg_ts_template │ table │ postgres │ permanent │ 40 kB │ │ 66 | │ pg_catalog │ pg_type │ table │ postgres │ permanent │ 120 kB │ │ 67 | │ pg_catalog │ pg_user_mapping │ table │ postgres │ permanent │ 8192 bytes │ │ 68 | │ public │ bigtable │ table │ pavel │ permanent │ 35 MB │ │ 69 | └────────────┴─────────────────────────┴───────┴──────────┴─────────────┴────────────┴─────────────┘ 70 | (64 rows) 71 | 72 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | for i in {1..100} 2 | do 3 | echo `date` 4 | echo 5 | cat << END 6 | ┌──────────┬──────────┐ 7 | │ ?column? │ ?column? │ 8 | ╞══════════╪══════════╡ 9 | │ 1 │ 2 │ 10 | │ 1 │ 2 │ 11 | └──────────┴──────────┘ 12 | (2 rows) 13 | END 14 | 15 | echo 16 | 17 | sleep 1 18 | 19 | done; -------------------------------------------------------------------------------- /tests/test10.csv: -------------------------------------------------------------------------------- 1 | col1,col2,col3 2 | dat1,dat2,dat3 3 | dat1,dat2,dat3 4 | dat1 ,dat2 ,dat3 5 | dat1 ,dat2 x,dat3 6 | dat1 ,dat2muex,dat3 7 | dat1 ,dat2 ,dat3 8 | dat1 ,dat2,dat3 9 | dat1 ,dat2 ,dat3 10 | dat1 ,dat2,dat3 11 | dat1 ,dat2,dat3 12 | dat1 ,dat2,dat3 13 | dat1 ,dat2,dat3 14 | dat1, dat2,dat3 15 | dat1, dat2,dat3 16 | dat1,dat2,dat3 17 | dat1,da t2,dat3 18 | dat1,d at2,dat3 19 | dat1,d a,dat3 20 | dat1,dat2,dat3 21 | -------------------------------------------------------------------------------- /tests/test11.csv: -------------------------------------------------------------------------------- 1 | Name,Owner,Encoding,Collate,Ctype,ICU Locale,Locale Provider,Access privileges,Size,Tablespace,Description 2 | postgres,postgres,UTF8,cs_CZ.UTF-8,cs_CZ.UTF-8,,libc,,7693 kB,pg_default,default administrative connection database 3 | template0,postgres,UTF8,cs_CZ.UTF-8,cs_CZ.UTF-8,,libc,"=c/postgres 4 | postgres=CTc/postgres",7537 kB,pg_default,unmodifiable empty database 5 | template1,postgres,UTF8,cs_CZ.UTF-8,cs_CZ.UTF-8,,libc,"=c/postgres 6 | postgres=CTc/postgres",7765 kB,pg_default,default template for new databases 7 | -------------------------------------------------------------------------------- /tests/test12.csv: -------------------------------------------------------------------------------- 1 | abcd, abcd, abcd, abcd 2 | 1,2,3,4 3 | abc,abc,abc,abc 4 | abc,ab,abc,abc 5 | abc,"abcd 6 | abcd 7 | abcdef",ab,ab 8 | -------------------------------------------------------------------------------- /tests/test13.csv: -------------------------------------------------------------------------------- 1 | col1,col2,col3 2 | data,abcdefgh, dat3 3 | dat1,da ta,dat3 4 | dat1,data,dat3 5 | -------------------------------------------------------------------------------- /tests/test2.csv: -------------------------------------------------------------------------------- 1 | s1, s2, s3, s4, s5 2 | 1, 2, 3, 4, 5 3 | 6, 7, 8, 9, 10 4 | 11, 12, 13, 14, 15 5 | 16, 17, 18, 19, 20 6 | Horní Libochová , 100, Dlouhé , Dobrá voda 7 | 10,,20,30,,40 -------------------------------------------------------------------------------- /tests/test2.sh: -------------------------------------------------------------------------------- 1 | for i in {1..100} 2 | do 3 | echo `date` 4 | echo 5 | cat << END 6 | ┌──────────┬──────────┐ 7 | │ ?column? │ ?column? │ 8 | ╞══════════╪══════════╡ 9 | │ 1 │ 2 │ 10 | │ 1 │ 2 │ 11 | └──────────┴──────────┘ 12 | (2 rows) 13 | END 14 | 15 | echo 16 | echo -n -e '\x05' 17 | 18 | sleep 1 19 | 20 | done; -------------------------------------------------------------------------------- /tests/test3.csv: -------------------------------------------------------------------------------- 1 | rok,firma,typ, poznamka,najezd 2 | 1995,Opel,Vectra,"klimatizace, střešní okno",45000 3 | 1998,Škoda,"Felicia ""Fun""",,80000 4 | 2002,Škoda,Octavia,"klimatizace, ABS bouraná",70000 5 | 6 | -------------------------------------------------------------------------------- /tests/test4.csv: -------------------------------------------------------------------------------- 1 | rok,firma,typ, poznamka,najezd 2 | 1995,Opel,Vectra,"klimatizace, střešní okno",45000 3 | 1998,Škoda,"Felicia ""Fun""",,80000 4 | 2002, Škoda, Octavia,"klimatizace, ABS 5 | bouraná",70000 6 | 7 | -------------------------------------------------------------------------------- /tests/test5.csv: -------------------------------------------------------------------------------- 1 | rok,firma,typ, poznamka 2 | 1995,Opel,Vectra,"klimatizace, střešní okno" 3 | 1998,Škoda,"Felicia ""Fun""",ss 4 | 2002,Škoda,Octavia,"klimatizace, 5 | ABS" 6 | -------------------------------------------------------------------------------- /tests/test6.csv: -------------------------------------------------------------------------------- 1 | rok,firma,typ, poznamka 2 | 1995,Opel,Vectra,"klimatizace, střešní okno" 3 | 1998,Škoda,"Felicia ""Fun""", ss 4 | 2002,Škoda,Octavia,"klimatizace, ABS 5 | bourana" 6 | -------------------------------------------------------------------------------- /tests/test7.csv: -------------------------------------------------------------------------------- 1 | 1995,Opel,Vectra,"klimatizace, střešní okno",45000 2 | 1998,Škoda,"Felicia ""Fun""",,80000 3 | 2002,Škoda,Octavia,"klimatizace, ABS bouraná",70000 4 | 5 | -------------------------------------------------------------------------------- /tests/test8.csv: -------------------------------------------------------------------------------- 1 | 10,20,20,40,50 2 | 1,20,3 3 | 1,2 4 | 5 | -------------------------------------------------------------------------------- /tests/test9.csv: -------------------------------------------------------------------------------- 1 | a, b, c 2 | d, e, f 3 | g, h, i 4 | 5 | -------------------------------------------------------------------------------- /tests/vystup_explain_verbose.txt: -------------------------------------------------------------------------------- 1 | QUERY PLAN 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | Seq Scan on pg_temp_3.t1 (cost=0.00..11.00 rows=100 width=735) 4 | Output: call_id, call_start, call_end, caller_num, caller_name, caller_agent_id, dialed_num, disposition, direction, diverted_num, answering_exten, answering_name, answering_agent_id, answering_queue, outgoing_cid_num, billsec, billsec_interval, duration, duration_interval, dial_duration, dial_interval, ringing_extens, abandoned_queues, call_type, fop_call, channel, technology, record_name, record_start, hangup_cause, pickuped, finished, dials, records, queues, bridges, created 5 | (2 řádky) 6 | 7 | -------------------------------------------------------------------------------- /tools/ax_debug_cflags.m4: -------------------------------------------------------------------------------- 1 | # gcc default/debug CFLAGS handling respecting user's CFLAGS 2 | # avoid AC_PROG_CC setting -O2 CFLAGS which will override DEBUG_CFLAGS' -O0 3 | # must be used right after AC_INIT 4 | 5 | AC_DEFUN([AX_DEBUG_CFLAGS], [ 6 | 7 | # ensure CFLAGS are set 8 | AS_IF([test "${CFLAGS+set}"], [ 9 | USE_DEFAULT_CFLAGS=false 10 | ], [ 11 | USE_DEFAULT_CFLAGS=true 12 | CFLAGS="" 13 | ]) 14 | AC_PROG_CC 15 | 16 | # add --enable-debug arg 17 | AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [enable debug build]), [], []) 18 | AS_IF([test "$enable_debug" = "yes"], [ 19 | # add the DEBUG pre-processor define 20 | AC_DEFINE([DEBUG], [1], [debug build]) 21 | # gcc/gdb debug options 22 | AS_IF([test "$GCC" = "yes"], [ 23 | DEBUG_CFLAGS="-ggdb -O0" 24 | ], [ 25 | ACX_DEBUG_CFLAGS_G 26 | ]) 27 | ], [ 28 | # what AC_PROG_CC would have done if CFLAGS were not set 29 | AS_IF([$USE_DEFAULT_CFLAGS], [ 30 | ACX_DEBUG_CFLAGS_G 31 | AS_IF([test "$GCC" = "yes"], [ 32 | DEBUG_CFLAGS="$DEBUG_CFLAGS -O2" 33 | ]) 34 | ]) 35 | ]) 36 | AC_SUBST([DEBUG_CFLAGS], [$DEBUG_CFLAGS]) 37 | 38 | ]) 39 | 40 | AC_DEFUN([ACX_DEBUG_CFLAGS_G], [ 41 | # default to -g 42 | AS_IF([test "$ac_cv_prog_cc_g" = "yes"], [ 43 | DEBUG_CFLAGS="-g" 44 | ], [ 45 | DEBUG_CFLAGS="" 46 | ]) 47 | ]) 48 | 49 | -------------------------------------------------------------------------------- /tools/ax_lib_readline.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_lib_readline.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_LIB_READLINE 8 | # 9 | # DESCRIPTION 10 | # 11 | # Searches for a readline compatible library. If found, defines 12 | # `HAVE_LIBREADLINE'. If the found library has the `add_history' function, 13 | # sets also `HAVE_READLINE_HISTORY'. Also checks for the locations of the 14 | # necessary include files and sets `HAVE_READLINE_H' or 15 | # `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or 16 | # 'HAVE_HISTORY_H' if the corresponding include files exists. 17 | # 18 | # The libraries that may be readline compatible are `libedit', 19 | # `libeditline' and `libreadline'. Sometimes we need to link a termcap 20 | # library for readline to work, this macro tests these cases too by trying 21 | # to link with `libtermcap', `libcurses' or `libncurses' before giving up. 22 | # 23 | # Here is an example of how to use the information provided by this macro 24 | # to perform the necessary includes or declarations in a C file: 25 | # 26 | # #ifdef HAVE_LIBREADLINE 27 | # # if defined(HAVE_READLINE_READLINE_H) 28 | # # include 29 | # # elif defined(HAVE_READLINE_H) 30 | # # include 31 | # # else /* !defined(HAVE_READLINE_H) */ 32 | # extern char *readline (); 33 | # # endif /* !defined(HAVE_READLINE_H) */ 34 | # char *cmdline = NULL; 35 | # #else /* !defined(HAVE_READLINE_READLINE_H) */ 36 | # /* no readline */ 37 | # #endif /* HAVE_LIBREADLINE */ 38 | # 39 | # #ifdef HAVE_READLINE_HISTORY 40 | # # if defined(HAVE_READLINE_HISTORY_H) 41 | # # include 42 | # # elif defined(HAVE_HISTORY_H) 43 | # # include 44 | # # else /* !defined(HAVE_HISTORY_H) */ 45 | # extern void add_history (); 46 | # extern int write_history (); 47 | # extern int read_history (); 48 | # # endif /* defined(HAVE_READLINE_HISTORY_H) */ 49 | # /* no history */ 50 | # #endif /* HAVE_READLINE_HISTORY */ 51 | # 52 | # LICENSE 53 | # 54 | # Copyright (c) 2008 Ville Laurikari 55 | # 56 | # Copying and distribution of this file, with or without modification, are 57 | # permitted in any medium without royalty provided the copyright notice 58 | # and this notice are preserved. This file is offered as-is, without any 59 | # warranty. 60 | 61 | #serial 7 62 | 63 | AU_ALIAS([VL_LIB_READLINE], [AX_LIB_READLINE]) 64 | AC_DEFUN([AX_LIB_READLINE], [ 65 | AC_CACHE_CHECK([for a readline compatible library], 66 | ax_cv_lib_readline, [ 67 | ORIG_LIBS="$LIBS" 68 | for readline_lib in readline edit editline; do 69 | for termcap_lib in "" termcap curses ncurses; do 70 | if test -z "$termcap_lib"; then 71 | TRY_LIB="-l$readline_lib" 72 | else 73 | TRY_LIB="-l$readline_lib -l$termcap_lib" 74 | fi 75 | LIBS="$ORIG_LIBS $TRY_LIB" 76 | AC_TRY_LINK_FUNC(readline, ax_cv_lib_readline="$TRY_LIB") 77 | if test -n "$ax_cv_lib_readline"; then 78 | break 79 | fi 80 | done 81 | if test -n "$ax_cv_lib_readline"; then 82 | break 83 | fi 84 | done 85 | if test -z "$ax_cv_lib_readline"; then 86 | ax_cv_lib_readline="no" 87 | fi 88 | LIBS="$ORIG_LIBS" 89 | ]) 90 | 91 | if test "$ax_cv_lib_readline" != "no"; then 92 | LIBS="$LIBS $ax_cv_lib_readline" 93 | AC_DEFINE(HAVE_LIBREADLINE, 1, 94 | [Define if you have a readline compatible library]) 95 | AC_CHECK_HEADERS(readline.h readline/readline.h) 96 | AC_CACHE_CHECK([whether readline supports history], 97 | ax_cv_lib_readline_history, [ 98 | ax_cv_lib_readline_history="no" 99 | AC_TRY_LINK_FUNC(add_history, ax_cv_lib_readline_history="yes") 100 | ]) 101 | if test "$ax_cv_lib_readline_history" = "yes"; then 102 | AC_DEFINE(HAVE_READLINE_HISTORY, 1, 103 | [Define if your readline library has \`add_history']) 104 | AC_CHECK_HEADERS(history.h readline/history.h) 105 | fi 106 | fi 107 | ])dnl 108 | 109 | -------------------------------------------------------------------------------- /tools/ax_require_defined.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_require_defined.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_REQUIRE_DEFINED(MACRO) 8 | # 9 | # DESCRIPTION 10 | # 11 | # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have 12 | # been defined and thus are available for use. This avoids random issues 13 | # where a macro isn't expanded. Instead the configure script emits a 14 | # non-fatal: 15 | # 16 | # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found 17 | # 18 | # It's like AC_REQUIRE except it doesn't expand the required macro. 19 | # 20 | # Here's an example: 21 | # 22 | # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) 23 | # 24 | # LICENSE 25 | # 26 | # Copyright (c) 2014 Mike Frysinger 27 | # 28 | # Copying and distribution of this file, with or without modification, are 29 | # permitted in any medium without royalty provided the copyright notice 30 | # and this notice are preserved. This file is offered as-is, without any 31 | # warranty. 32 | 33 | #serial 1 34 | 35 | AC_DEFUN([AX_REQUIRE_DEFINED], [dnl 36 | m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) 37 | ])dnl AX_REQUIRE_DEFINED 38 | -------------------------------------------------------------------------------- /tools/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Install data or executable file. 4 | # 5 | # Usage: $0 {data|bin} src dest 6 | # 7 | # Copyright (c) 2014 Jonas Fonseca 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License as 11 | # published by the Free Software Foundation; either version 2 of 12 | # the License, or (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | set -e 20 | 21 | data="$1" 22 | src="$2" 23 | dest="$3" 24 | mode=0755 25 | trash= 26 | 27 | case "$data" in data) 28 | mode=0644 29 | esac 30 | 31 | install -d "$dest" 32 | 33 | if [ "$V" = "@" ]; then 34 | echo "$src -> $dest" 35 | fi 36 | 37 | # Replace fake /etc-path 38 | case "$src" in doc/*) 39 | dest="$dest/$(basename "$src")" 40 | sed "s#++SYSCONFDIR++#${sysconfdir}#" < "$src" > "$src+" 41 | trash="$src+" 42 | src="$src+" 43 | esac 44 | 45 | install -p -m "$mode" "$src" "$dest" 46 | 47 | if [ -n "$trash" ]; then 48 | rm -f "$trash" 49 | fi 50 | -------------------------------------------------------------------------------- /tools/m4_ax_compare_version.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_compare_version.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro compares two version strings. Due to the various number of 12 | # minor-version numbers that can exist, and the fact that string 13 | # comparisons are not compatible with numeric comparisons, this is not 14 | # necessarily trivial to do in a autoconf script. This macro makes doing 15 | # these comparisons easy. 16 | # 17 | # The six basic comparisons are available, as well as checking equality 18 | # limited to a certain number of minor-version levels. 19 | # 20 | # The operator OP determines what type of comparison to do, and can be one 21 | # of: 22 | # 23 | # eq - equal (test A == B) 24 | # ne - not equal (test A != B) 25 | # le - less than or equal (test A <= B) 26 | # ge - greater than or equal (test A >= B) 27 | # lt - less than (test A < B) 28 | # gt - greater than (test A > B) 29 | # 30 | # Additionally, the eq and ne operator can have a number after it to limit 31 | # the test to that number of minor versions. 32 | # 33 | # eq0 - equal up to the length of the shorter version 34 | # ne0 - not equal up to the length of the shorter version 35 | # eqN - equal up to N sub-version levels 36 | # neN - not equal up to N sub-version levels 37 | # 38 | # When the condition is true, shell commands ACTION-IF-TRUE are run, 39 | # otherwise shell commands ACTION-IF-FALSE are run. The environment 40 | # variable 'ax_compare_version' is always set to either 'true' or 'false' 41 | # as well. 42 | # 43 | # Examples: 44 | # 45 | # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) 46 | # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) 47 | # 48 | # would both be true. 49 | # 50 | # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) 51 | # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) 52 | # 53 | # would both be false. 54 | # 55 | # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) 56 | # 57 | # would be true because it is only comparing two minor versions. 58 | # 59 | # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) 60 | # 61 | # would be true because it is only comparing the lesser number of minor 62 | # versions of the two values. 63 | # 64 | # Note: The characters that separate the version numbers do not matter. An 65 | # empty string is the same as version 0. OP is evaluated by autoconf, not 66 | # configure, so must be a string, not a variable. 67 | # 68 | # The author would like to acknowledge Guido Draheim whose advice about 69 | # the m4_case and m4_ifvaln functions make this macro only include the 70 | # portions necessary to perform the specific comparison specified by the 71 | # OP argument in the final configure script. 72 | # 73 | # LICENSE 74 | # 75 | # Copyright (c) 2008 Tim Toolan 76 | # 77 | # Copying and distribution of this file, with or without modification, are 78 | # permitted in any medium without royalty provided the copyright notice 79 | # and this notice are preserved. This file is offered as-is, without any 80 | # warranty. 81 | 82 | #serial 13 83 | 84 | dnl ######################################################################### 85 | AC_DEFUN([AX_COMPARE_VERSION], [ 86 | AC_REQUIRE([AC_PROG_AWK]) 87 | 88 | # Used to indicate true or false condition 89 | ax_compare_version=false 90 | 91 | # Convert the two version strings to be compared into a format that 92 | # allows a simple string comparison. The end result is that a version 93 | # string of the form 1.12.5-r617 will be converted to the form 94 | # 0001001200050617. In other words, each number is zero padded to four 95 | # digits, and non digits are removed. 96 | AS_VAR_PUSHDEF([A],[ax_compare_version_A]) 97 | A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ 98 | -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ 99 | -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 100 | -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 101 | -e 's/[[^0-9]]//g'` 102 | 103 | AS_VAR_PUSHDEF([B],[ax_compare_version_B]) 104 | B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ 105 | -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ 106 | -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 107 | -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 108 | -e 's/[[^0-9]]//g'` 109 | 110 | dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary 111 | dnl # then the first line is used to determine if the condition is true. 112 | dnl # The sed right after the echo is to remove any indented white space. 113 | m4_case(m4_tolower($2), 114 | [lt],[ 115 | ax_compare_version=`echo "x$A 116 | x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` 117 | ], 118 | [gt],[ 119 | ax_compare_version=`echo "x$A 120 | x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` 121 | ], 122 | [le],[ 123 | ax_compare_version=`echo "x$A 124 | x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` 125 | ], 126 | [ge],[ 127 | ax_compare_version=`echo "x$A 128 | x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` 129 | ],[ 130 | dnl Split the operator from the subversion count if present. 131 | m4_bmatch(m4_substr($2,2), 132 | [0],[ 133 | # A count of zero means use the length of the shorter version. 134 | # Determine the number of characters in A and B. 135 | ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` 136 | ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` 137 | 138 | # Set A to no more than B's length and B to no more than A's length. 139 | A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` 140 | B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` 141 | ], 142 | [[0-9]+],[ 143 | # A count greater than zero means use only that many subversions 144 | A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` 145 | B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` 146 | ], 147 | [.+],[ 148 | AC_WARNING( 149 | [invalid OP numeric parameter: $2]) 150 | ],[]) 151 | 152 | # Pad zeros at end of numbers to make same length. 153 | ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" 154 | B="$B`echo $A | sed 's/./0/g'`" 155 | A="$ax_compare_version_tmp_A" 156 | 157 | # Check for equality or inequality as necessary. 158 | m4_case(m4_tolower(m4_substr($2,0,2)), 159 | [eq],[ 160 | test "x$A" = "x$B" && ax_compare_version=true 161 | ], 162 | [ne],[ 163 | test "x$A" != "x$B" && ax_compare_version=true 164 | ],[ 165 | AC_WARNING([invalid OP parameter: $2]) 166 | ]) 167 | ]) 168 | 169 | AS_VAR_POPDEF([A])dnl 170 | AS_VAR_POPDEF([B])dnl 171 | 172 | dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. 173 | if test "$ax_compare_version" = "true" ; then 174 | m4_ifvaln([$4],[$4],[:])dnl 175 | m4_ifvaln([$5],[else $5])dnl 176 | fi 177 | ]) dnl AX_COMPARE_VERSION 178 | -------------------------------------------------------------------------------- /tools/m4_ax_lib_postgresql.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_lib_postgresql.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_LIB_POSTGRESQL([MINIMUM-VERSION],[ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro provides tests of availability of PostgreSQL 'libpq' library 12 | # of particular version or newer. 13 | # 14 | # AX_LIB_POSTGRESQL macro takes only one argument which is optional. If 15 | # there is no required version passed, then macro does not run version 16 | # test. 17 | # 18 | # The --with-postgresql option takes one of three possible values: 19 | # 20 | # no - do not check for PostgreSQL client library 21 | # 22 | # yes - do check for PostgreSQL library in standard locations (pg_config 23 | # should be in the PATH) 24 | # 25 | # path - complete path to pg_config utility, use this option if pg_config 26 | # can't be found in the PATH (You could set also PG_CONFIG variable) 27 | # 28 | # This macro calls: 29 | # 30 | # AC_SUBST(POSTGRESQL_CPPFLAGS) 31 | # AC_SUBST(POSTGRESQL_LDFLAGS) 32 | # AC_SUBST(POSTGRESQL_LIBS) 33 | # AC_SUBST(POSTGRESQL_VERSION) 34 | # 35 | # And sets: 36 | # 37 | # HAVE_POSTGRESQL 38 | # 39 | # It execute if found ACTION-IF-FOUND (empty by default) and 40 | # ACTION-IF-NOT-FOUND (AC_MSG_FAILURE by default) if not found. 41 | # 42 | # LICENSE 43 | # 44 | # Copyright (c) 2008 Mateusz Loskot 45 | # Copyright (c) 2014 Sree Harsha Totakura 46 | # Copyright (c) 2018 Bastien Roucaries 47 | # 48 | # Copying and distribution of this file, with or without modification, are 49 | # permitted in any medium without royalty provided the copyright notice 50 | # and this notice are preserved. This file is offered as-is, without any 51 | # warranty. 52 | 53 | #serial 22 54 | 55 | AC_DEFUN([_AX_LIB_POSTGRESQL_OLD],[ 56 | found_postgresql="no" 57 | _AX_LIB_POSTGRESQL_OLD_fail="no" 58 | while true; do 59 | AC_CACHE_CHECK([for the pg_config program], [ac_cv_path_PG_CONFIG], 60 | [AC_PATH_PROGS_FEATURE_CHECK([PG_CONFIG], [pg_config], 61 | [[ac_cv_path_PG_CONFIG="";$ac_path_PG_CONFIG --includedir > /dev/null \ 62 | && ac_cv_path_PG_CONFIG=$ac_path_PG_CONFIG ac_path_PG_CONFIG_found=:]], 63 | [ac_cv_path_PG_CONFIG=""])]) 64 | PG_CONFIG=$ac_cv_path_PG_CONFIG 65 | AS_IF([test "X$PG_CONFIG" = "X"],[break]) 66 | 67 | AC_CACHE_CHECK([for the PostgreSQL libraries CPPFLAGS],[ac_cv_POSTGRESQL_CPPFLAGS], 68 | [ac_cv_POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes]) 69 | AS_IF([test "X$_AX_LIB_POSTGRESQL_OLD_fail" = "Xyes"],[break]) 70 | POSTGRESQL_CPPFLAGS="$ac_cv_POSTGRESQL_CPPFLAGS" 71 | 72 | AC_CACHE_CHECK([for the PostgreSQL libraries LDFLAGS],[ac_cv_POSTGRESQL_LDFLAGS], 73 | [ac_cv_POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes]) 74 | AS_IF([test "X$_AX_LIB_POSTGRESQL_OLD_fail" = "Xyes"],[break]) 75 | POSTGRESQL_LDFLAGS="$ac_cv_POSTGRESQL_LDFLAGS" 76 | 77 | AC_CACHE_CHECK([for the PostgreSQL libraries LIBS],[ac_cv_POSTGRESQL_LIBS], 78 | [ac_cv_POSTGRESQL_LIBS="-lpq"]) 79 | POSTGRESQL_LIBS="$ac_cv_POSTGRESQL_LIBS" 80 | 81 | AC_CACHE_CHECK([for the PostgreSQL version],[ac_cv_POSTGRESQL_VERSION], 82 | [ 83 | ac_cv_POSTGRESQL_VERSION=`$PG_CONFIG --version | sed "s/^PostgreSQL[[[:space:]]][[[:space:]]]*\([[0-9.]][[0-9.]]*\).*/\1/"` \ 84 | || _AX_LIB_POSTGRESQL_OLD_fail=yes 85 | ]) 86 | AS_IF([test "X$_AX_LIB_POSTGRESQL_OLD_fail" = "Xyes"],[break]) 87 | POSTGRESQL_VERSION="$ac_cv_POSTGRESQL_VERSION" 88 | 89 | 90 | dnl 91 | dnl Check if required version of PostgreSQL is available 92 | dnl 93 | AS_IF([test X"$postgresql_version_req" != "X"],[ 94 | AC_MSG_CHECKING([if PostgreSQL version $POSTGRESQL_VERSION is >= $postgresql_version_req]) 95 | AX_COMPARE_VERSION([$POSTGRESQL_VERSION],[ge],[$postgresql_version_req], 96 | [found_postgresql_req_version=yes],[found_postgresql_req_version=no]) 97 | AC_MSG_RESULT([$found_postgresql_req_version]) 98 | ]) 99 | AS_IF([test "Xfound_postgresql_req_version" = "Xno"],[break]) 100 | 101 | found_postgresql="yes" 102 | break 103 | done 104 | ]) 105 | 106 | AC_DEFUN([_AX_LIB_POSTGRESQL_PKG_CONFIG], 107 | [ 108 | AC_REQUIRE([PKG_PROG_PKG_CONFIG]) 109 | found_postgresql=no 110 | 111 | while true; do 112 | PKG_PROG_PKG_CONFIG 113 | AS_IF([test X$PKG_CONFIG = X],[break]) 114 | 115 | _AX_LIB_POSTGRESQL_PKG_CONFIG_fail=no; 116 | AS_IF([test "X$postgresql_version_req" = "X"], 117 | [PKG_CHECK_EXISTS([libpq],[found_postgresql_pkg_config=yes],[found_postgresql=no])], 118 | [PKG_CHECK_EXISTS([libpq >= "$postgresql_version_req"], 119 | [found_postgresql=yes],[found_postgresql=no])]) 120 | AS_IF([test "X$found_postgresql" = "no"],[break]) 121 | 122 | AC_CACHE_CHECK([for the PostgreSQL libraries CPPFLAGS],[ac_cv_POSTGRESQL_CPPFLAGS], 123 | [ac_cv_POSTGRESQL_CPPFLAGS="`$PKG_CONFIG libpq --cflags-only-I`" || _AX_LIB_POSTGRESQL_PKG_CONFIG_fail=yes]) 124 | AS_IF([test "X$_AX_LIB_POSTGRESQL_PKG_CONFIG_fail" = "Xyes"],[break]) 125 | POSTGRESQL_CPPFLAGS="$ac_cv_POSTGRESQL_CPPFLAGS" 126 | 127 | 128 | AC_CACHE_CHECK([for the PostgreSQL libraries LDFLAGS],[ac_cv_POSTGRESQL_LDFLAGS], 129 | [ac_cv_POSTGRESQL_LDFLAGS="`$PKG_CONFIG libpq --libs-only-L --libs-only-other`" || _AX_LIB_POSTGRESQL_PKG_CONFIG_fail=yes]) 130 | AS_IF([test "X$_AX_LIB_POSTGRESQL_PKG_CONFIG_fail" = "Xyes"],[break]) 131 | POSTGRESQL_LDFLAGS="$ac_cv_POSTGRESQL_LDFLAGS" 132 | 133 | 134 | AC_CACHE_CHECK([for the PostgreSQL libraries LIBS],[ac_cv_POSTGRESQL_LIBS], 135 | [ac_cv_POSTGRESQL_LIBS="`$PKG_CONFIG libpq --libs-only-l`" || _AX_LIB_POSTGRESQL_PKG_CONFIG_fail=ye]) 136 | AS_IF([test "X$_AX_LIB_POSTGRESQL_PKG_CONFIG_fail" = "Xyes"],[break]) 137 | POSTGRESQL_LIBS="$ac_cv_POSTGRESQL_LIBS" 138 | 139 | dnl already checked by exist but need to be recovered 140 | AC_CACHE_CHECK([for the PostgreSQL version],[ac_cv_POSTGRESQL_VERSION], 141 | [ac_cv_POSTGRESQL_VERSION="`$PKG_CONFIG libpq --modversion`" || _AX_LIB_POSTGRESQL_PKG_CONFIG_fail=yes]) 142 | AS_IF([test "X$_AX_LIB_POSTGRESQL_PKG_CONFIG_fail" = "Xyes"],[break]) 143 | POSTGRESQL_VERSION="$ac_cv_POSTGRESQL_VERSION" 144 | 145 | found_postgresql=yes 146 | break; 147 | done 148 | 149 | ]) 150 | 151 | 152 | 153 | AC_DEFUN([AX_LIB_POSTGRESQL], 154 | [ 155 | AC_ARG_WITH([postgresql], 156 | AS_HELP_STRING([--with-postgresql=@<:@ARG@:>@], 157 | [use PostgreSQL library @<:@default=yes@:>@, optionally specify path to pg_config] 158 | ), 159 | [ 160 | AS_CASE([$withval], 161 | [[[nN]][[oO]]],[want_postgresql="no"], 162 | [[[yY]][[eE]][[sS]]],[want_postgresql="yes"], 163 | [ 164 | want_postgresql="yes" 165 | PG_CONFIG="$withval" 166 | ]) 167 | ], 168 | [want_postgresql="yes"] 169 | ) 170 | 171 | AC_ARG_VAR([POSTGRESQL_CPPFLAGS],[cpp flags for PostgreSQL overriding detected flags]) 172 | AC_ARG_VAR([POSTGRESQL_LIBFLAGS],[libs for PostgreSQL overriding detected flags]) 173 | AC_ARG_VAR([POSTGRESQL_LDFLAGS],[linker flags for PostgreSQL overriding detected flags]) 174 | 175 | # populate cache 176 | AS_IF([test "X$POSTGRESQL_CPPFLAGS" != X],[ac_cv_POSTGRESQL_CPPFLAGS="$POSTGRESQL_CPPFLAGS"]) 177 | AS_IF([test "X$POSTGRESQL_LDFLAGS" != X],[ac_cv_POSTGRESQL_LDFLAGS="$POSTGRESQL_LDFLAGS"]) 178 | AS_IF([test "X$POSTGRESQL_LIBS" != X],[ac_cv_POSTGRESQL_LIBS="$POSTGRESQL_LIBS"]) 179 | 180 | postgresql_version_req=ifelse([$1], [], [], [$1]) 181 | found_postgresql="no" 182 | 183 | POSTGRESQL_VERSION="" 184 | 185 | dnl 186 | dnl Check PostgreSQL libraries (libpq) 187 | dnl 188 | AS_IF([test X"$want_postgresql" = "Xyes"],[ 189 | _AX_LIB_POSTGRESQL_PKG_CONFIG 190 | 191 | 192 | AS_IF([test X"$found_postgresql" = "Xno"], 193 | [_AX_LIB_POSTGRESQL_OLD]) 194 | 195 | AS_IF([test X"$found_postgresql" = Xyes],[ 196 | _AX_LIB_POSTGRESQL_OLD_CPPFLAGS="$CPPFLAGS" 197 | CPPFLAGS="$CPPFLAGS $POSTGRESQL_CPPFLAGS" 198 | _AX_LIB_POSTGRESQL_OLD_LDFLAGS="$LDFLAGS" 199 | LDFLAGS="$LDFLAGS $POSTGRESQL_LDFLAGS" 200 | _AX_LIB_POSTGRESQL_OLD_LIBS="$LIBS" 201 | LIBS="$LIBS $POSTGRESQL_LIBS" 202 | while true; do 203 | dnl try to compile 204 | AC_CHECK_HEADER([libpq-fe.h],[],[found_postgresql=no]) 205 | AS_IF([test "X$found_postgresql" = "Xno"],[break]) 206 | dnl try now to link 207 | AC_CACHE_CHECK([for the PostgreSQL library linking is working],[ac_cv_postgresql_found], 208 | [ 209 | AC_LINK_IFELSE([ 210 | AC_LANG_PROGRAM( 211 | [ 212 | #include 213 | ], 214 | [[ 215 | char conninfo[]="dbname = postgres"; 216 | PGconn *conn; 217 | conn = PQconnectdb(conninfo); 218 | ]] 219 | ) 220 | ],[ac_cv_postgresql_found=yes], 221 | [ac_cv_postgresql_found=no]) 222 | ]) 223 | found_postgresql="$ac_cv_postgresql_found" 224 | AS_IF([test "X$found_postgresql" = "Xno"],[break]) 225 | break 226 | done 227 | CPPFLAGS="$_AX_LIB_POSTGRESQL_OLD_CPPFLAGS" 228 | LDFLAGS="$_AX_LIB_POSTGRESQL_OLD_LDFLAGS" 229 | LIBS="$_AX_LIB_POSTGRESQL_OLD_LIBS" 230 | ]) 231 | 232 | 233 | AS_IF([test "x$found_postgresql" = "xyes"],[ 234 | AC_DEFINE([HAVE_POSTGRESQL], [1], 235 | [Define to 1 if PostgreSQL libraries are available])]) 236 | ]) 237 | 238 | AC_SUBST([POSTGRESQL_VERSION]) 239 | AC_SUBST([POSTGRESQL_CPPFLAGS]) 240 | AC_SUBST([POSTGRESQL_LDFLAGS]) 241 | AC_SUBST([POSTGRESQL_LIBS]) 242 | 243 | AS_IF([test "x$found_postgresql" = "xyes"], 244 | [ifelse([$2], , :, [$2])], 245 | [ifelse([$3], , AS_IF([test X"$want_postgresql" = "Xyes"],[AC_MSG_ERROR([Library requirements (PostgreSQL) not met.])],[:]), [$3])]) 246 | 247 | ]) 248 | -------------------------------------------------------------------------------- /tools/m4_ax_with_curses_extra.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_with_curses_extra.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_WITH_CURSES_PANEL 8 | # AX_WITH_CURSES_MENU 9 | # AX_WITH_CURSES_FORM 10 | # 11 | # DESCRIPTION 12 | # 13 | # These macros try to find additional libraries that often come with 14 | # SysV-compatible Curses. In particular, the Panel, Menu and Form 15 | # libraries are searched, along with their header files. These macros 16 | # depend on AX_WITH_CURSES. 17 | # 18 | # The following preprocessor symbols may be defined by these macros: 19 | # 20 | # By AX_WITH_CURSES_PANEL: 21 | # 22 | # HAVE_PANEL - if the Panel library is present 23 | # HAVE_PANEL_H - if is present and should be used 24 | # HAVE_NCURSES_PANEL_H - if should be used 25 | # HAVE_NCURSESW_PANEL_H - if should be used 26 | # 27 | # By AX_WITH_CURSES_MENU: 28 | # 29 | # HAVE_MENU - if the Menu library is present 30 | # HAVE_MENU_H - if is present and should be used 31 | # HAVE_NCURSES_MENU_H - if should be used 32 | # HAVE_NCURSESW_MENU_H - if should be used 33 | # 34 | # By AX_WITH_CURSES_FORM: 35 | # 36 | # HAVE_FORM - if the Form library is present 37 | # HAVE_FORM_H - if is present and should be used 38 | # HAVE_NCURSES_FORM_H - if should be used 39 | # HAVE_NCURSESW_FORM_H - if should be used 40 | # 41 | # The following output variables may be defined by these macros; these are 42 | # precious and may be overridden on the ./configure command line: 43 | # 44 | # PANEL_LIBS - library to add to xxx_LDADD before CURSES_LIBS 45 | # MENU_LIBS - library to add to xxx_LDADD before CURSES_LIBS 46 | # FORM_LIBS - library to add to xxx_LDADD before CURSES_LIBS 47 | # 48 | # In previous versions of this macro, the flags PANEL_LIB, MENU_LIB and 49 | # FORM_LIB were defined. These have been renamed, in keeping with the 50 | # variable scheme of PKG_CHECK_MODULES, which should eventually supersede 51 | # the use of AX_WITH_CURSES and AX_WITH_CURSES_* macros. These libraries 52 | # are NOT added to LIBS by default. You need to add them to the 53 | # appropriate xxx_LDADD line in your Makefile.am in front of the 54 | # equivalent CURSES_LIBS incantation. For example: 55 | # 56 | # prog_LDADD = @PANEL_LIBS@ @CURSES_LIBS@ 57 | # 58 | # If one of the xxx_LIBS variables is set on the configure command line 59 | # (such as by running "./configure PANEL_LIBS=-lmypanel"), then the header 60 | # file searched must NOT contain a subpath. In this case, in other words, 61 | # only would be searched for. The user may use the CPPFLAGS 62 | # precious variable to override the standard #include search path. 63 | # 64 | # The following shell variables may be defined by these macros: 65 | # 66 | # ax_cv_panel - set to "yes" if Panels library is present 67 | # ax_cv_menu - set to "yes" if Menu library is present 68 | # ax_cv_form - set to "yes" if Form library is present 69 | # 70 | # These variables can be used in your configure.ac to determine whether a 71 | # library you require is actually present. For example: 72 | # 73 | # AX_WITH_CURSES 74 | # if test "x$ax_cv_curses" != xyes; then 75 | # AC_MSG_ERROR([requires a SysV or X/Open-compatible Curses library]) 76 | # fi 77 | # AX_WITH_CURSES_PANEL 78 | # if test "x$ax_cv_panel" != xyes; then 79 | # AC_MSG_ERROR([requires the Curses Panel library]) 80 | # fi 81 | # 82 | # To use the HAVE_xxx_H preprocessor symbols, insert the following into 83 | # your system.h (or equivalent) header file: 84 | # 85 | # For AX_WITH_CURSES_PANEL: 86 | # 87 | # #if defined HAVE_NCURSESW_PANEL_H 88 | # # include 89 | # #elif defined HAVE_NCURSES_PANEL_H 90 | # # include 91 | # #elif defined HAVE_PANEL_H 92 | # # include 93 | # #else 94 | # # error "SysV-compatible Curses Panel header file required" 95 | # #endif 96 | # 97 | # For AX_WITH_CURSES_MENU: 98 | # 99 | # #if defined HAVE_NCURSESW_MENU_H 100 | # # include 101 | # #elif defined HAVE_NCURSES_MENU_H 102 | # # include 103 | # #elif defined HAVE_MENU_H 104 | # # include 105 | # #else 106 | # # error "SysV-compatible Curses Menu header file required" 107 | # #endif 108 | # 109 | # For AX_WITH_CURSES_FORM: 110 | # 111 | # #if defined HAVE_NCURSESW_FORM_H 112 | # # include 113 | # #elif defined HAVE_NCURSES_FORM_H 114 | # # include 115 | # #elif defined HAVE_FORM_H 116 | # # include 117 | # #else 118 | # # error "SysV-compatible Curses Form header file required" 119 | # #endif 120 | # 121 | # LICENSE 122 | # 123 | # Copyright (c) 2011 John Zaitseff 124 | # 125 | # This program is free software: you can redistribute it and/or modify it 126 | # under the terms of the GNU General Public License as published by the 127 | # Free Software Foundation, either version 3 of the License, or (at your 128 | # option) any later version. 129 | # 130 | # This program is distributed in the hope that it will be useful, but 131 | # WITHOUT ANY WARRANTY; without even the implied warranty of 132 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 133 | # Public License for more details. 134 | # 135 | # You should have received a copy of the GNU General Public License along 136 | # with this program. If not, see . 137 | # 138 | # As a special exception, the respective Autoconf Macro's copyright owner 139 | # gives unlimited permission to copy, distribute and modify the configure 140 | # scripts that are the output of Autoconf when processing the Macro. You 141 | # need not follow the terms of the GNU General Public License when using 142 | # or distributing such scripts, even though portions of the text of the 143 | # Macro appear in them. The GNU General Public License (GPL) does govern 144 | # all other use of the material that constitutes the Autoconf Macro. 145 | # 146 | # This special exception to the GPL applies to versions of the Autoconf 147 | # Macro released by the Autoconf Archive. When you make and distribute a 148 | # modified version of the Autoconf Macro, you may extend this special 149 | # exception to the GPL to apply to your modified version as well. 150 | 151 | #serial 5 152 | 153 | AC_DEFUN([_AX_WITH_CURSES_CHECKEXTRA], [ 154 | dnl Parameter 1 is the variable name component, using uppercase letters only 155 | dnl Parameter 2 is the printable library name 156 | dnl Parameter 3 is the C code to try compiling and linking 157 | dnl Parameter 4 is the header filename 158 | dnl Parameter 5 is the library command line 159 | 160 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_have_var], [HAVE_$1])dnl 161 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_cv_var], [ax_cv_[]m4_tolower($1)])dnl 162 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_header_var], [ax_cv_header_$4])dnl 163 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_have_header_var], [HAVE_[]m4_toupper($4)])dnl 164 | 165 | ax_saved_LIBS=$LIBS 166 | ax_saved_CPPFLAGS=$CPPFLAGS 167 | 168 | AC_CACHE_CHECK([for Curses $2 library with $4], [_AX_WITH_CURSES_CHECKEXTRA_header_var], [ 169 | LIBS="$ax_saved_LIBS $5 $CURSES_LIBS" 170 | CPPFLAGS="$ax_saved_CPPFLAGS $CURSES_CFLAGS" 171 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 172 | @%:@include <$4> 173 | ]], [$3])], 174 | [_AX_WITH_CURSES_CHECKEXTRA_header_var=yes], 175 | [_AX_WITH_CURSES_CHECKEXTRA_header_var=no]) 176 | ]) 177 | AS_IF([test "x$[]_AX_WITH_CURSES_CHECKEXTRA_header_var" = xyes], [ 178 | _AX_WITH_CURSES_CHECKEXTRA_cv_var=yes 179 | AS_LITERAL_IF([$5], [$1_LIBS="$5"]) 180 | AC_DEFINE([_AX_WITH_CURSES_CHECKEXTRA_have_var], [1], [Define to 1 if the Curses $2 library is present]) 181 | AC_DEFINE([_AX_WITH_CURSES_CHECKEXTRA_have_header_var], [1], [Define to 1 if <$4> is present]) 182 | ], [ 183 | AS_IF([test "x$[]_AX_WITH_CURSES_CHECKEXTRA_cv_var" = xyes], [], 184 | [_AX_WITH_CURSES_CHECKEXTRA_cv_var=no]) 185 | ]) 186 | 187 | LIBS=$ax_saved_LIBS 188 | CPPFLAGS=$ax_saved_CPPFLAGS 189 | unset ax_saved_LIBS 190 | unset ax_saved_CPPFLAGS 191 | 192 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_have_header_var])dnl 193 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_header_var])dnl 194 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_cv_var])dnl 195 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_have_var])dnl 196 | ])dnl 197 | 198 | AC_DEFUN([_AX_WITH_CURSES_EXTRA], [ 199 | dnl Parameter 1 is the variable name component, using uppercase letters only 200 | dnl Parameter 2 is the printable library name 201 | dnl Parameter 3 is the C code to try compiling and linking 202 | dnl Parameter 4 is the header filename component 203 | dnl Parameter 5 is the NCursesW library command line 204 | dnl Parameter 6 is the NCurses library command line 205 | dnl Parameter 7 is the plain Curses library command line 206 | 207 | AC_REQUIRE([AX_WITH_CURSES]) 208 | AC_ARG_VAR([$1_LIBS], [linker library for Curses $2, e.g. $7]) 209 | 210 | AS_IF([test "x$[]$1_LIBS" != x], [ 211 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$[]$1_LIBS]) 212 | ], [ 213 | AS_IF([test "x$ax_cv_curses_which" = xncursesw], [ 214 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [ncursesw/$4], [$5]) 215 | AS_IF([test x$[]ax_cv_[]m4_tolower($1) != "xyes"], [ 216 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$6]) 217 | ]) 218 | ], [test "x$ax_cv_curses_which" = xncurses], [ 219 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$6]) 220 | AS_IF([test x$[]ax_cv_[]m4_tolower($1) != "xyes"], [ 221 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [ncurses/$4], [$6]) 222 | ]) 223 | ], [test "x$ax_cv_curses_which" = xplaincurses], [ 224 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$7]) 225 | ]) 226 | ]) 227 | ])dnl 228 | 229 | AC_DEFUN([AX_WITH_CURSES_PANEL], [ 230 | _AX_WITH_CURSES_EXTRA([PANEL], [Panel], [[ 231 | WINDOW *win = newwin(0, 0, 0, 0); 232 | PANEL *pan = new_panel(win); 233 | ]], [panel.h], [-lpanelw], [-lpanel], [-lpanel]) 234 | ])dnl 235 | 236 | AC_DEFUN([AX_WITH_CURSES_MENU], [ 237 | _AX_WITH_CURSES_EXTRA([MENU], [Menu], [[ 238 | ITEM **mi; 239 | MENU *m = new_menu(mi); 240 | ]], [menu.h], [-lmenuw], [-lmenu], [-lmenu]) 241 | ])dnl 242 | 243 | AC_DEFUN([AX_WITH_CURSES_FORM], [ 244 | _AX_WITH_CURSES_EXTRA([FORM], [Form], [[ 245 | FIELD **ff; 246 | FORM *f = new_form(ff); 247 | ]], [form.h], [-lformw], [-lform], [-lform]) 248 | ])dnl 249 | --------------------------------------------------------------------------------