source added
authorebelcrom <ebelcrom@gmail.com>
Sun, 20 May 2018 22:08:42 +0000 (00:08 +0200)
committerebelcrom <ebelcrom@gmail.com>
Sun, 20 May 2018 22:08:42 +0000 (00:08 +0200)
27 files changed:
deb/make_deb.sh [new file with mode: 0755]
deb/shgen-0.1/Makefile [new symlink]
deb/shgen-0.1/debian/changelog [new file with mode: 0644]
deb/shgen-0.1/debian/compat [new file with mode: 0644]
deb/shgen-0.1/debian/control [new file with mode: 0644]
deb/shgen-0.1/debian/copyright [new file with mode: 0644]
deb/shgen-0.1/debian/rules [new file with mode: 0755]
deb/shgen-0.1/debian/shgen-docs.docs [new file with mode: 0644]
deb/shgen-0.1/debian/source/format [new file with mode: 0644]
deb/shgen-0.1/shgen.c [new symlink]
deb/shgen-0.1/usr_share_shgen [new symlink]
src/Makefile [new file with mode: 0644]
src/debian/changelog [new file with mode: 0644]
src/debian/compat [new file with mode: 0644]
src/debian/control [new file with mode: 0644]
src/debian/copyright [new file with mode: 0644]
src/debian/rules [new file with mode: 0755]
src/debian/shgen-docs.docs [new file with mode: 0644]
src/debian/source/format [new file with mode: 0644]
src/shgen.c [new file with mode: 0644]
src/usr_share_shgen/GPLv2 [new file with mode: 0644]
src/usr_share_shgen/GPLv3 [new file with mode: 0644]
src/usr_share_shgen/custom [new file with mode: 0644]
src/usr_share_shgen/help [new file with mode: 0644]
src/usr_share_shgen/lib [new file with mode: 0644]
src/usr_share_shgen/shgen.sh [new file with mode: 0755]
src/usr_share_shgen/skeleton [new file with mode: 0644]

diff --git a/deb/make_deb.sh b/deb/make_deb.sh
new file mode 100755 (executable)
index 0000000..9283591
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+set -e
+set -x
+
+SRC_DIR=shgen-0.1
+
+# go to the dir of this script
+cd $(dirname $0)
+# install needed packages for build up a debian package
+sudo apt-get install build-essential debhelper dh-make quilt fakeroot lintian
+# tar source for dh_make
+tar -czf $SRC_DIR.tar.gz $SRC_DIR
+pushd $SRC_DIR
+# run dh_make
+set +e
+dh_make -s -y -f ../shgen-0.1.tar.gz
+set -e
+# package source
+dpkg-buildpackage -S -us -uc
+# install needed packages for build up a ncurses/cdk application
+sudo apt-get install libcdk5 libcdk5-dev
+# package binary of current architecture
+dpkg-buildpackage -us -uc
+# build for i386 on a amd64 machine
+if [ "$(uname -m)" == "x86_64" ]; then
+       # install needed packages for build up a ncurses/cdk application
+       sudo apt-get install libcdk5:i386 libcdk5-dev:i386
+       # package binary of current architecture
+       export CC="gcc -m32"
+       dpkg-buildpackage -us -uc
+       unset CC
+fi
+popd
+
diff --git a/deb/shgen-0.1/Makefile b/deb/shgen-0.1/Makefile
new file mode 120000 (symlink)
index 0000000..50be211
--- /dev/null
@@ -0,0 +1 @@
+../../src/Makefile
\ No newline at end of file
diff --git a/deb/shgen-0.1/debian/changelog b/deb/shgen-0.1/debian/changelog
new file mode 100644 (file)
index 0000000..6f7f324
--- /dev/null
@@ -0,0 +1,5 @@
+shgen (0.1-1) lucid; urgency=low
+
+  * Initial release
+
+ -- dragan <ebelcrom@gmail.com>  Thu, 17 May 2018 23:01:27 +0200
diff --git a/deb/shgen-0.1/debian/compat b/deb/shgen-0.1/debian/compat
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/deb/shgen-0.1/debian/control b/deb/shgen-0.1/debian/control
new file mode 100644 (file)
index 0000000..f784bbc
--- /dev/null
@@ -0,0 +1,13 @@
+Source: shgen
+Section: misc
+Priority: optional
+Maintainer: dragan <ebelcrom@gmail.com>
+Build-Depends: debhelper (>= 9)
+Standards-Version: 3.9.6
+Homepage: https://binomiant.duckdns.org/MpqU9XX8/shgen.git
+
+Package: shgen
+Architecture: any
+Depends: libc6 (>= 2.4), libncurses5 (>= 5.0), libcdk5 (>= 5.0)
+Description: Console shell script generator.
+ Ncurses based shell script generator for execution in a console.
diff --git a/deb/shgen-0.1/debian/copyright b/deb/shgen-0.1/debian/copyright
new file mode 100644 (file)
index 0000000..4c5d211
--- /dev/null
@@ -0,0 +1,26 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: shgen
+Source: https://binomiant.duckdns.org/MpqU9XX8/shgen.git
+
+Files: *
+Copyright: 2018 dragan <ebelcrom@gmail.com>
+License: GPL-2+
+
+Files: debian/*
+Copyright: 2018 dragan <ebelcrom@gmail.com>
+License: GPL-2+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
diff --git a/deb/shgen-0.1/debian/rules b/deb/shgen-0.1/debian/rules
new file mode 100755 (executable)
index 0000000..4ebc141
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+#export DH_VERBOSE = 1
+
+
+# see FEATURE AREAS in dpkg-buildflags(1)
+#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# see ENVIRONMENT in dpkg-buildflags(1)
+# package maintainers to append CFLAGS
+#export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
+# package maintainers to append LDFLAGS
+#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
+
+
+%:
+       dh $@ 
+
+
+# dh_make generated override targets
+# This is example for Cmake (See https://bugs.debian.org/641051 )
+#override_dh_auto_configure:
+#      dh_auto_configure -- #  -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
+
+override_dh_strip:
diff --git a/deb/shgen-0.1/debian/shgen-docs.docs b/deb/shgen-0.1/debian/shgen-docs.docs
new file mode 100644 (file)
index 0000000..7319041
--- /dev/null
@@ -0,0 +1,2 @@
+README.source
+README.Debian
diff --git a/deb/shgen-0.1/debian/source/format b/deb/shgen-0.1/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/deb/shgen-0.1/shgen.c b/deb/shgen-0.1/shgen.c
new file mode 120000 (symlink)
index 0000000..a303924
--- /dev/null
@@ -0,0 +1 @@
+../../src/shgen.c
\ No newline at end of file
diff --git a/deb/shgen-0.1/usr_share_shgen b/deb/shgen-0.1/usr_share_shgen
new file mode 120000 (symlink)
index 0000000..4bf4081
--- /dev/null
@@ -0,0 +1 @@
+../../src/usr_share_shgen
\ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..9df0f82
--- /dev/null
@@ -0,0 +1,34 @@
+CC ?= gcc
+STRIP ?= strip
+CFLAGS = -O2 -Wall -I/usr/include/cdk
+LDFLAGS = -lcdk -lncurses
+
+EXE = shgen
+MISC = usr_share_shgen
+
+default: $(EXE)
+
+%.o: %.c
+       @echo '  [CC] $^'
+       @$(CC) $(CFLAGS) -c -o $@ $<
+
+$(EXE): %: %.o
+       @echo '  [LD] $<'
+       @$(CC) -o $@ $< $(LDFLAGS)
+       @echo '  [STRIP] $<'
+       @$(STRIP) $@
+
+install: $(EXE)
+       @echo '  [INSTALL] $<'
+       @mkdir -p $(DESTDIR)/usr/bin
+       @install -m 755 $(EXE) $(DESTDIR)/usr/bin
+       @mkdir -p $(DESTDIR)/usr/share/$(EXE)
+       @install -m 644 -t $(DESTDIR)/usr/share/$(EXE) $(MISC)/GPLv2 $(MISC)/GPLv3\
+        $(MISC)/custom $(MISC)/help $(MISC)/lib $(MISC)/skeleton
+       @install -m 755 $(MISC)/shgen.sh $(DESTDIR)/usr/share/$(EXE)
+
+clean:
+       @echo '  [CLEAN]'
+       @rm -f $(EXE) *.o
+
+.PHONY: clean default install
diff --git a/src/debian/changelog b/src/debian/changelog
new file mode 100644 (file)
index 0000000..6f7f324
--- /dev/null
@@ -0,0 +1,5 @@
+shgen (0.1-1) lucid; urgency=low
+
+  * Initial release
+
+ -- dragan <ebelcrom@gmail.com>  Thu, 17 May 2018 23:01:27 +0200
diff --git a/src/debian/compat b/src/debian/compat
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/debian/control b/src/debian/control
new file mode 100644 (file)
index 0000000..f784bbc
--- /dev/null
@@ -0,0 +1,13 @@
+Source: shgen
+Section: misc
+Priority: optional
+Maintainer: dragan <ebelcrom@gmail.com>
+Build-Depends: debhelper (>= 9)
+Standards-Version: 3.9.6
+Homepage: https://binomiant.duckdns.org/MpqU9XX8/shgen.git
+
+Package: shgen
+Architecture: any
+Depends: libc6 (>= 2.4), libncurses5 (>= 5.0), libcdk5 (>= 5.0)
+Description: Console shell script generator.
+ Ncurses based shell script generator for execution in a console.
diff --git a/src/debian/copyright b/src/debian/copyright
new file mode 100644 (file)
index 0000000..4c5d211
--- /dev/null
@@ -0,0 +1,26 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: shgen
+Source: https://binomiant.duckdns.org/MpqU9XX8/shgen.git
+
+Files: *
+Copyright: 2018 dragan <ebelcrom@gmail.com>
+License: GPL-2+
+
+Files: debian/*
+Copyright: 2018 dragan <ebelcrom@gmail.com>
+License: GPL-2+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
diff --git a/src/debian/rules b/src/debian/rules
new file mode 100755 (executable)
index 0000000..4ebc141
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+#export DH_VERBOSE = 1
+
+
+# see FEATURE AREAS in dpkg-buildflags(1)
+#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# see ENVIRONMENT in dpkg-buildflags(1)
+# package maintainers to append CFLAGS
+#export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
+# package maintainers to append LDFLAGS
+#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
+
+
+%:
+       dh $@ 
+
+
+# dh_make generated override targets
+# This is example for Cmake (See https://bugs.debian.org/641051 )
+#override_dh_auto_configure:
+#      dh_auto_configure -- #  -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
+
+override_dh_strip:
diff --git a/src/debian/shgen-docs.docs b/src/debian/shgen-docs.docs
new file mode 100644 (file)
index 0000000..7319041
--- /dev/null
@@ -0,0 +1,2 @@
+README.source
+README.Debian
diff --git a/src/debian/source/format b/src/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/src/shgen.c b/src/shgen.c
new file mode 100644 (file)
index 0000000..050947e
--- /dev/null
@@ -0,0 +1,981 @@
+#include <cdk.h>
+#include <signal.h>
+
+/*
+ * TODO:
+ *   sha bang: /bin/sh|bash
+ *   header: comment, license
+ *   lib.sh: log, error, warning
+ *   BASH_XTRACEFD, debug file
+ * - check defined
+ *   name and directory
+ * - parameters...
+ */
+
+static int x_size = 0;
+static int y_size = 0;
+
+static WINDOW* window;
+static CDKSCREEN* screen;
+static CDKLABEL* title_label;
+static CDKLABEL* options_label;
+static CDKLABEL* commands_label;
+static char* shabang_opts[] = { " /bin/sh", " /bin/bash" };
+static CDKRADIO* shabang_radio;
+static CDKLABEL* shabang_label;
+static CDKSELECTION* header_selection;
+static CDKLABEL* header_label;
+static CDKLABEL* description_label;
+static CDKENTRY* description_entry;
+static char* license_opts[] = { " none", " GPLv2", " GPLv3", " custom" };
+static CDKRADIO* license_radio;
+static CDKLABEL* license_label;
+static CDKLABEL* script_label;
+static CDKBUTTON* script_button;
+static CDKENTRY* script_entry;
+static CDKSELECTION* debug_selection;
+static CDKLABEL* debug_label;
+static CDKLABEL* dfile_label;
+static CDKBUTTON* dfile_button;
+static CDKENTRY* dfile_entry;
+static char* common_opts[] = { " usage()", " log()", " error()", " warning()" };
+static CDKSELECTION* common_selection;
+static CDKLABEL* common_label;
+static CDKSELECTION* lib_selection;
+static CDKLABEL* lib_label;
+static CDKLABEL* lfile_label;
+static CDKBUTTON* lfile_button;
+static CDKENTRY* lfile_entry;
+static CDKBUTTON* generate_button;
+
+static char* default_opts = "<C></B><ESCAPE><!B> - Abort   </B><TAB|RETURN><!B> - Next";
+static char* enable_opts = "<C></B><ESCAPE><!B> - Abort   </B><TAB|RETURN><!B> - Next"
+       "   </B><SPACE><!B> - Choose";
+static char* select_opts = "<C></B><ESCAPE><!B> - Abort   </B><TAB|RETURN><!B> - Next"
+       "   </B><UP|DOWN><!B> - Select   </B><SPACE><!B> - Choose";
+static char* button_opts = "<C></B><ESCAPE><!B> - Abort   </B><RETURN><!B> - Enter";
+static char* gen_opts = "<C></B><ESCAPE><!B> - Abort   </B><RETURN><!B> - Generate";
+static char* help_opts = "<C></B><ESCAPE><!B> - Abort   </B><RETURN><!B> - Quit help"
+       "   </B><UP><!B> - Line up   </B><DOWN><!B> - Line down";
+static char* commands_msg;
+
+static const char* settings = ".shgen/settings";
+static const char* exec_script = "/usr/share/shgen/shgen.sh";
+static const char* help_file = "/usr/share/shgen/help";
+static const char* opt_create = " -c 2>&1";
+static const char* opt_generate = " -g 2>&1";
+static struct s_exec_res
+{
+       int status;
+       char message[1024];
+} exec_result;
+
+static struct s_data
+{
+       char* shabang;
+       boolean header;
+       char* description;
+       char* license;
+       char* script;
+       boolean debug;
+       char* dfile;
+       char* common[4];
+       boolean lib;
+       char* lfile;
+} data =
+{
+       NULL,
+       FALSE,
+       NULL,
+       NULL,
+       NULL,
+       FALSE,
+       NULL,
+       { NULL, NULL, NULL, NULL },
+       FALSE,
+       NULL
+};
+
+static void create_button(CDKSCREEN* screen);
+static void create_common(CDKSCREEN* screen);
+static void create_controls(void);
+static void create_debug(CDKSCREEN* screen);
+static void create_header(CDKSCREEN* screen);
+static void create_help(CDKSCREEN* screen);
+static void create_lib(CDKSCREEN* screen);
+static void create_script(CDKSCREEN* screen);
+static void create_shabang(CDKSCREEN* screen);
+static void create_titlebar(CDKSCREEN* screen);
+static void destroy_controls(void);
+static void dimension_check(void);
+static int process_common(void);
+static int process_debug(void);
+static int process_gen(void);
+static int process_header(void);
+static int process_lib(void);
+static int process_script(void);
+static int process_shabang(void);
+static void update_options(char* options);
+static void write_settings(int view);
+static int help(EObjectType cdktype, void* object, void* clientdata, chtype key);
+static int quit(EObjectType cdktype, void* object, void* clientdata, chtype key);
+
+/* generation button */
+static void create_button(CDKSCREEN* screen)
+{
+       char* generate_text[] = { " Generate " };
+       generate_button = newCDKButton(screen, x_size / 2 + 14,
+               getbegy(lfile_entry->win) + 2, generate_text[0], NULL, FALSE, FALSE);
+       setCDKButtonBackgroundAttrib(generate_button, A_REVERSE);
+       drawCDKButton(generate_button, FALSE);
+}
+
+/* common function */
+static void create_common(CDKSCREEN* screen)
+{
+       char* common_text[] = { "Functions: " };
+       char* common_choices[] = { "[ ]", "[X]" };
+       common_selection = newCDKSelection(screen, getbegx(debug_selection->win),
+               getbegy(dfile_entry->win) + 2, NONE, 4, 13, NULL, common_opts, 4,
+               common_choices, 2, NONE, FALSE, FALSE);
+       common_label = newCDKLabel(screen, getbegx(common_selection->win) -
+               strlen(common_text[0]), getbegy(common_selection->win), common_text, 1, FALSE,
+               FALSE);
+       drawCDKLabel(common_label, FALSE);
+       drawCDKSelection(common_selection, FALSE);
+}
+
+/* create controls */
+static void create_controls(void)
+{
+       create_titlebar(screen);
+       create_shabang(screen);
+       create_header(screen);
+       create_script(screen);
+       create_debug(screen);
+       create_common(screen);
+       create_lib(screen);
+       create_button(screen);
+       create_help(screen);
+}
+
+/* bash xtrace fd / debug option */
+static void create_debug(CDKSCREEN* screen)
+{
+       char* debug_text[] = { "Debug: " };
+       char* debug_choices[] = { "[ ]", "[X]" };
+       char* debug_opts[] = { " enable" };
+       debug_selection = newCDKSelection(screen, x_size / 2 + 14,
+               getmaxy(title_label->win) + 1, NONE, 1, 10, NULL, debug_opts, 1, debug_choices,
+               2, NONE, FALSE, FALSE);
+       debug_label = newCDKLabel(screen, getbegx(debug_selection->win) -
+               strlen(debug_text[0]), getbegy(debug_selection->win), debug_text, 1, FALSE,
+               FALSE);
+       drawCDKLabel(debug_label, FALSE);
+       drawCDKSelection(debug_selection, FALSE);
+
+       /* debug file */
+       char* dfile_text[] = { "Debug file name and path: " };
+       dfile_label = newCDKLabel(screen, x_size / 2 + 1,
+               getbegy(debug_selection->win) + 2, dfile_text, 1, FALSE, FALSE);
+       drawCDKLabel(dfile_label, FALSE);
+
+       dfile_text[0] = " Enter ";
+       dfile_button = newCDKButton(screen, x_size / 2 + 40 - strlen(dfile_text[0]) - 1,
+               getbegy(dfile_label->win), dfile_text[0], NULL, FALSE, FALSE);
+       setCDKButtonBackgroundAttrib(dfile_button, A_REVERSE);
+       drawCDKButton(dfile_button, FALSE);
+
+       dfile_entry = newCDKEntry(screen, getbegx(dfile_label->win),
+               getbegy(dfile_label->win) + 2, NULL, NULL, A_NORMAL, '.', vMIXED, 38, 0, 256,
+               FALSE, FALSE);
+       drawCDKEntry(dfile_entry, FALSE);
+}
+
+/* program description and license */
+static void create_header(CDKSCREEN* screen)
+{
+       /* header activation */
+       char* header_text[] = { "Header: " };
+       char* header_opts[] = { " enable" };
+       char* header_choices[] = { "[ ]", "[X]" };
+       header_selection = newCDKSelection(screen, getbegx(shabang_radio->win),
+               getbegy(shabang_radio->win) + 3, NONE, 1, 10, NULL, header_opts, 1,
+               header_choices, 2, NONE, FALSE, FALSE);
+       header_label = newCDKLabel(screen, getbegx(header_selection->win) -
+               strlen(header_text[0]), getbegy(header_selection->win), header_text, 1, FALSE,
+               FALSE);
+       drawCDKLabel(header_label, FALSE);
+       drawCDKSelection(header_selection, FALSE);
+
+       /* description */
+       char* description_text[] = { "Description: " };
+       description_label = newCDKLabel(screen, 1, getbegy(header_selection->win) +
+               2, description_text, 1, FALSE, FALSE);
+       drawCDKLabel(description_label, FALSE);
+       description_entry = newCDKEntry(screen, 1, getbegy(description_label->win) +
+               2, NULL, NULL, A_NORMAL, '.', vMIXED, 38, 0, 256, FALSE, FALSE);
+       drawCDKEntry(description_entry, FALSE);
+
+       /* license choice */
+       char* license_text[] = { "License: " };
+       license_radio = newCDKRadio(screen, getbegx(header_selection->win),
+               getbegy(description_entry->win) + 2, NONE, 4, 5, NULL, license_opts, 4, 'X', 1,
+               NONE, FALSE, FALSE);
+       setCDKRadioLeftBrace(license_radio, '(');
+       setCDKRadioRightBrace(license_radio, ')');
+       license_label = newCDKLabel(screen, getbegx(license_radio->win) -
+               strlen(license_text[0]), getbegy(license_radio->win), license_text, 1, FALSE,
+               FALSE);
+       drawCDKLabel(license_label, FALSE);
+       drawCDKRadio(license_radio, FALSE);
+}
+
+/* help viewer */
+static void create_help(CDKSCREEN* screen)
+{
+}
+
+/* lib activation */
+static void create_lib(CDKSCREEN* screen)
+{
+       /* lib activation */
+       char* lib_text[] = { "lib.sh: " };
+       char* lib_choices[] = { "[ ]", "[X]" };
+       char* lib_opts[] = { " enable" };
+       lib_selection = newCDKSelection(screen, getbegx(debug_selection->win),
+               getbegy(common_selection->win) + 5, NONE, 1, 10, NULL, lib_opts, 1, lib_choices,
+               2, NONE, FALSE, FALSE);
+       lib_label = newCDKLabel(screen, getbegx(lib_selection->win) -
+               strlen(lib_text[0]), getbegy(lib_selection->win), lib_text, 1, FALSE,
+               FALSE);
+       drawCDKLabel(lib_label, FALSE);
+       drawCDKSelection(lib_selection, FALSE);
+
+       /* lib file */
+       char* lfile_text[] = { "lib.sh path: " };
+       lfile_label = newCDKLabel(screen, x_size / 2 + 1,
+               getbegy(lib_selection->win) + 2, lfile_text, 1, FALSE, FALSE);
+       drawCDKLabel(lfile_label, FALSE);
+
+       lfile_text[0] = " Enter ";
+       lfile_button = newCDKButton(screen, x_size / 2 + 40 - strlen(lfile_text[0]) - 1,
+               getbegy(lfile_label->win), lfile_text[0], NULL, FALSE, FALSE);
+       setCDKButtonBackgroundAttrib(lfile_button, A_REVERSE);
+       drawCDKButton(lfile_button, FALSE);
+
+       lfile_entry = newCDKEntry(screen, getbegx(lfile_label->win),
+               getbegy(lfile_label->win) + 2, NULL, NULL, A_NORMAL, '.', vMIXED, 38, 0, 256,
+               FALSE, FALSE);
+       drawCDKEntry(lfile_entry, FALSE);
+}
+
+/* script name and dir */
+static void create_script(CDKSCREEN* screen)
+{
+       char* script_text[] = { "Script name and path: " };
+       script_label = newCDKLabel(screen, 1, getbegy(license_radio->win) + 5,
+               script_text, 1, FALSE, FALSE);
+       drawCDKLabel(script_label, FALSE);
+
+       script_text[0] = " Enter ";
+       script_button = newCDKButton(screen, 40 - strlen(script_text[0]) - 1,
+               getbegy(script_label->win), script_text[0], NULL, FALSE, FALSE);
+       setCDKButtonBackgroundAttrib(script_button, A_REVERSE);
+       drawCDKButton(script_button, FALSE);
+
+       script_entry = newCDKEntry(screen, 1, getbegy(script_label->win) + 2, NULL,
+               NULL, A_NORMAL, '.', vMIXED, 38, 0, 256, FALSE, FALSE);
+       drawCDKEntry(script_entry, FALSE);
+}
+
+/* shabang choice */
+static void create_shabang(CDKSCREEN* screen)
+{
+       char* shabang_text[] = { "Shabang: " };
+       shabang_radio = newCDKRadio(screen, 14, getmaxy(title_label->win) + 1,
+               NONE, 2, 8, NULL, shabang_opts, 2, 'X', 1, NONE, FALSE, FALSE);
+       setCDKRadioLeftBrace(shabang_radio, '(');
+       setCDKRadioRightBrace(shabang_radio, ')');
+       shabang_label = newCDKLabel(screen, getbegx(shabang_radio->win) -
+               strlen(shabang_text[0]), getbegy(shabang_radio->win), shabang_text, 1, FALSE, FALSE);
+       drawCDKLabel(shabang_label, FALSE);
+       drawCDKRadio(shabang_radio, FALSE);
+}
+
+/* program title and general options on top with hline below */
+static void create_titlebar(CDKSCREEN* screen)
+{
+       char hline_text[12];
+       snprintf(hline_text, 12, "<#HL(%i)>", x_size);
+       char* title_text[] = { "<L></B> Shell script generator v0.1<!B>", hline_text };
+       title_label = newCDKLabel(screen, LEFT, TOP, title_text, 2, FALSE, FALSE);
+       drawCDKLabel(title_label, FALSE);
+       char* options_text[] = { "<R></B><?><!B> - Help   </B><F10><!B> - Quit " };
+       options_label = newCDKLabel(screen, RIGHT, TOP, options_text, 1, FALSE,
+               FALSE);
+       drawCDKLabel(options_label, FALSE);
+}
+
+/* destroy controls */
+static void destroy_controls(void)
+{
+       destroyCDKLabel(title_label);
+       destroyCDKLabel(options_label);
+       destroyCDKLabel(commands_label);
+       destroyCDKLabel(shabang_label);
+       destroyCDKRadio(shabang_radio);
+       destroyCDKLabel(header_label);
+       destroyCDKSelection(header_selection);
+       destroyCDKLabel(description_label);
+       destroyCDKEntry(description_entry);
+       destroyCDKLabel(license_label);
+       destroyCDKRadio(license_radio);
+       destroyCDKLabel(script_label);
+       destroyCDKButton(script_button);
+       destroyCDKEntry(script_entry);
+       destroyCDKLabel(debug_label);
+       destroyCDKSelection(debug_selection);
+       destroyCDKLabel(dfile_label);
+       destroyCDKButton(dfile_button);
+       destroyCDKEntry(dfile_entry);
+       destroyCDKLabel(common_label);
+       destroyCDKSelection(common_selection);
+       destroyCDKLabel(lib_label);
+       destroyCDKSelection(lib_selection);
+       destroyCDKLabel(lfile_label);
+       destroyCDKButton(lfile_button);
+       destroyCDKEntry(lfile_entry);
+       destroyCDKButton(generate_button);
+}
+
+/* dimension check */
+static void dimension_check(void)
+{
+       initscr();
+       endwin();
+       getmaxyx(stdscr, y_size, x_size);
+
+       if (x_size < 80 || y_size < 24)
+       {
+               fprintf(stderr, "Minimal screen size must be at leaset 80x24. Aborting.\n");
+               exit(1);
+       }
+}
+
+static void execute(const char* option)
+{
+       char exec_str[strlen(exec_script) + strlen(option) + 1];
+       snprintf(exec_str, sizeof(exec_str), "%s%s", exec_script, option);
+
+       FILE* exec_pipe = popen(exec_str, "r");
+       if (exec_pipe != NULL)
+       {
+               char* pbuf;
+
+               while (TRUE)
+               {
+                       pbuf = fgets(exec_result.message, sizeof(exec_result.message), exec_pipe);
+                       if (pbuf == NULL)
+                       {
+                               break;
+                       }
+               }
+
+               int status = pclose(exec_pipe);
+               exec_result.status = WEXITSTATUS(status);
+       }
+       else
+       {
+               strerror_r(errno, exec_result.message, sizeof(exec_result.message));
+       }
+}
+
+/* process common selection */
+static int process_common(void)
+{
+       update_options(select_opts);
+       activateCDKSelection(common_selection, NULL);
+       if (common_selection->exitType == vNORMAL)
+       {
+               /* register choice */
+               int i;
+               for (i = 0; i < sizeof(data.common); i++)
+               {
+                       if (common_selection->selections[i])
+                       {
+                               data.common[i] = common_opts[i] + 1;
+                       }
+               }
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* process debug selection */
+static int process_debug(void)
+{
+       update_options(enable_opts);
+       activateCDKSelection(debug_selection, NULL);
+       if (debug_selection->exitType == vNORMAL)
+       {
+               /* register choice */
+               data.debug = debug_selection->selections[0];
+
+               if (debug_selection->selections[0] == TRUE)
+               {
+                       /* process debug button and entry */
+DFILE:
+                       update_options(button_opts);
+                       activateCDKButton(dfile_button, NULL);
+                       if (dfile_button->exitType == vNORMAL)
+                       {
+                               char* dfile_title =
+                                       "Navigate to a directory and enter a new file name below:  ";
+                               CDKFSELECT* dfile_fselect = newCDKFselect(screen, CENTER, CENTER, 18,
+                                       60, dfile_title, NULL, A_NORMAL, ' ', A_REVERSE, "</N>", "</N>",
+                                       "</N>", "</N>", TRUE, FALSE);
+
+                               char* filename = activateCDKFselect(dfile_fselect, NULL);
+                               if (filename != NULL && strlen(filename) > 0)
+                               {
+                                       /* register choice */
+                                       if (data.dfile != NULL)
+                                       {
+                                               free(data.dfile);
+                                       }
+                                       data.dfile = (char*) malloc(strlen(filename) + 1);
+                                       snprintf(data.dfile, strlen(filename) + 1, "%s", filename);
+
+                                       setCDKEntryValue(dfile_entry, data.dfile);
+                                       destroyCDKFselect(dfile_fselect);
+                                       refreshCDKScreen(screen);
+                               }
+                               else
+                               {
+                                       destroyCDKFselect(dfile_fselect);
+                                       refreshCDKScreen(screen);
+                                       goto DFILE;
+                               }
+                       }
+                       else
+                       {
+                               return 1;
+                       }
+               }
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* process generate button */
+static int process_gen(void)
+{
+       update_options(gen_opts);
+       activateCDKButton(generate_button, NULL);
+       if (generate_button->exitType == vNORMAL)
+       {
+               //write_settings(1);
+
+               char* gen_title = "<C></B>Generation progress<!B>";
+               char* gen_hl = "<#HL(34)>";
+               char* gen_1lp = "Create local directory [</B></00> pending <!00><!B>]";
+               char* gen_1lr = "Create local directory [</B></32> running <!32><!B>]";
+               char* gen_1ld = "Create local directory [</B></24>  ready  <!24><!B>]";
+               char* gen_1le = "Create local directory [</B></16>  error  <!16><!B>]";
+               char* gen_2lp = "Write settings         [</B></00> pending <!00><!B>]";
+               char* gen_2lr = "Write settings         [</B></32> running <!32><!B>]";
+               char* gen_2ld = "Write settings         [</B></24>  ready  <!24><!B>]";
+               char* gen_2le = "Write settings         [</B></16>  error  <!16><!B>]";
+               char* gen_3lp = "Generate script        [</B></00> pending <!00><!B>]";
+               char* gen_3lr = "Generate script        [</B></32> running <!32><!B>]";
+               char* gen_3ld = "Generate script        [</B></24>  ready  <!24><!B>]";
+               char* gen_3le = "Generate script        [</B></16>  error  <!16><!B>]";
+               char* gen_err = "</B></16>Error occurred:<!16><!B>";
+
+               char* init_text[] = { gen_title, gen_hl, gen_1lp, gen_2lp, gen_3lp };
+               CDKLABEL* progress_label = newCDKLabel(screen, CENTER, CENTER, init_text, 5,
+                       TRUE, FALSE);
+               drawCDKLabel(progress_label, TRUE);
+
+               /* create local directory */
+               char* create_text[] = { gen_title, gen_hl, gen_1lr, gen_2lp, gen_3lp };
+               setCDKLabel(progress_label, create_text, 5, TRUE);
+               sleep(1);
+               execute(opt_create);
+               if (exec_result.status > 0)
+               {
+                       char* failed_text[] = { gen_title, gen_hl, gen_1le, gen_2lp, gen_3lp };
+                       setCDKLabel(progress_label, failed_text, 5, TRUE);
+                       char* error_text[] = { gen_err, exec_result.message };
+                       popupLabel(screen, error_text, 2);
+                       destroyCDKLabel(progress_label);
+                       refreshCDKScreen(screen);
+                       return 1;
+               }
+
+               /* write settings to local directory */
+               char* settings_text[] = { gen_title, gen_hl, gen_1ld, gen_2lr, gen_3lp };
+               setCDKLabel(progress_label, settings_text, 5, TRUE);
+               sleep(1);
+               write_settings(0);
+               if (exec_result.status > 0)
+               {
+                       char* failed_text[] = { gen_title, gen_hl, gen_1ld, gen_2le, gen_3lp };
+                       setCDKLabel(progress_label, failed_text, 5, TRUE);
+                       char* error_text[] = { gen_err, exec_result.message };
+                       popupLabel(screen, error_text, 2);
+                       destroyCDKLabel(progress_label);
+                       refreshCDKScreen(screen);
+                       return 1;
+               }
+
+               /* generate shell script(s) */
+               char* generate_text[] = { gen_title, gen_hl, gen_1ld, gen_2ld, gen_3lr };
+               setCDKLabel(progress_label, generate_text, 5, TRUE);
+               sleep(1);
+               execute(opt_generate);
+               if (exec_result.status > 0)
+               {
+                       char* failed_text[] = { gen_title, gen_hl, gen_1ld, gen_2ld, gen_3le };
+                       setCDKLabel(progress_label, failed_text, 5, TRUE);
+                       char* error_text[] = { gen_err, exec_result.message };
+                       popupLabel(screen, error_text, 2);
+                       destroyCDKLabel(progress_label);
+                       refreshCDKScreen(screen);
+                       return 1;
+               }
+
+               char* exit_text[] = { gen_title, gen_hl, gen_1ld, gen_2ld, gen_3ld };
+               setCDKLabel(progress_label, exit_text, 5, TRUE);
+               sleep(1);
+               destroyCDKLabel(progress_label);
+               refreshCDKScreen(screen);
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* process header selection */
+static int process_header(void)
+{
+       int ch_num;
+       char* ch_str;
+
+       update_options(enable_opts);
+       ch_num = activateCDKSelection(header_selection, NULL);
+       if (header_selection->exitType == vNORMAL)
+       {
+               /* register choice */
+               data.header = header_selection->selections[0];
+
+               if (header_selection->selections[0] == TRUE)
+               {
+                       /* process decription entry */
+                       update_options(default_opts);
+                       ch_str = activateCDKEntry(description_entry, NULL);
+                       if (description_entry->exitType == vNORMAL)
+                       {
+                               /* register choice */
+                               data.description = ch_str;
+                       }
+                       else
+                       {
+                               return 1;
+                       }
+
+                       /* process license radio */
+                       update_options(select_opts);
+                       ch_num = activateCDKRadio(license_radio, NULL);
+                       if (license_radio->exitType == vNORMAL)
+                       {
+                               /* register choice */
+                               data.license = license_opts[ch_num] + 1;
+                       }
+                       else
+                       {
+                               return 1;
+                       }
+               }
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* process lib selection */
+static int process_lib(void)
+{
+       update_options(enable_opts);
+       activateCDKSelection(lib_selection, NULL);
+       if (lib_selection->exitType == vNORMAL)
+       {
+               /* register choice */
+               data.lib = lib_selection->selections[0];
+
+               if (lib_selection->selections[0] == TRUE)
+               {
+                       /* process lib button and entry */
+LFILE:
+                       update_options(default_opts);
+                       activateCDKButton(lfile_button, NULL);
+                       if (lfile_button->exitType == vNORMAL)
+                       {
+                               char* lfile_title =
+                                       "Navigate to a directory and enter a new file name below:  ";
+                               CDKFSELECT* lfile_fselect = newCDKFselect(screen, CENTER, CENTER, 18,
+                                       60, lfile_title, NULL, A_NORMAL, ' ', A_REVERSE, "</N>", "</N>",
+                                       "</N>", "</N>", TRUE, FALSE);
+
+                               char* filename = activateCDKFselect(lfile_fselect, NULL);
+                               if (filename != NULL && strlen(filename) > 0)
+                               {
+                                       /* register choice */
+                                       if (data.lfile != NULL)
+                                       {
+                                               free(data.lfile);
+                                       }
+                                       data.lfile = (char*) malloc(strlen(filename) + 1);
+                                       snprintf(data.lfile, strlen(filename) + 1, "%s", filename);
+
+                                       setCDKEntryValue(lfile_entry, data.lfile);
+                                       destroyCDKFselect(lfile_fselect);
+                                       refreshCDKScreen(screen);
+                               }
+                               else
+                               {
+                                       destroyCDKFselect(lfile_fselect);
+                                       refreshCDKScreen(screen);
+                                       goto LFILE;
+                               }
+                       }
+                       else
+                       {
+                               return 1;
+                       }
+               }
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* process script button and entry */
+static int process_script(void)
+{
+SCRIPT:
+       update_options(button_opts);
+       activateCDKButton(script_button, NULL);
+       if (script_button->exitType == vNORMAL)
+       {
+               char* script_title = "Navigate to a directory and enter a new file name below:  ";
+               CDKFSELECT* script_fselect = newCDKFselect(screen, CENTER, CENTER, 18, 60, script_title,
+                       NULL, A_NORMAL, ' ', A_REVERSE, "</N>", "</N>", "</N>", "</N>", TRUE, FALSE);
+
+               char* filename = activateCDKFselect(script_fselect, NULL);
+               if (filename != NULL && strlen(filename) > 0)
+               {
+                       /* register choice */
+                       if (data.script != NULL)
+                       {
+                               free(data.script);
+                       }
+                       data.script = (char*) malloc(strlen(filename) + 1);
+                       snprintf(data.script, strlen(filename) + 1, "%s", filename);
+
+                       setCDKEntryValue(script_entry, data.script);
+                       destroyCDKFselect(script_fselect);
+                       refreshCDKScreen(screen);
+               }
+               else
+               {
+                       destroyCDKFselect(script_fselect);
+                       refreshCDKScreen(screen);
+                       goto SCRIPT;
+               }
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* process shabang radio */
+static int process_shabang(void)
+{
+       int ch_num;
+
+       update_options(select_opts);
+       ch_num = activateCDKRadio(shabang_radio, NULL);
+       if (shabang_radio->exitType == vNORMAL)
+       {
+               /* register choice */
+               data.shabang = shabang_opts[ch_num] + 1;
+       }
+       else
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* update option line */
+static void update_options(char* options)
+{
+       char hline_cmd[12];
+       snprintf(hline_cmd, 12, "<#HL(%i)>", x_size);
+       commands_msg = options;
+       char* commands_text[] = { hline_cmd, options };
+       if (commands_label != NULL)
+       {
+               destroyCDKLabel(commands_label);
+       }
+       commands_label = newCDKLabel(screen, CENTER, BOTTOM, commands_text, 2,
+               FALSE, FALSE);
+       drawCDKLabel(commands_label, FALSE);
+}
+
+static void write_settings(int view)
+{
+       char* shabang = data.shabang;
+//     boolean header;
+       char header[2];
+       char* description = data.description;
+       char* license = data.license;
+       char* script = data.script;
+//     boolean debug;
+       char debug[2];
+       char* dfile = data.dfile;
+//     char* common[4];
+       char common[64];
+//     boolean lib;
+       char lib[2];
+       char* lfile = data.lfile;
+
+       if (data.shabang == NULL)
+               shabang = "NULL";
+       snprintf(header, sizeof(header), "%i", data.header);
+       if (data.description == NULL)
+               description = "NULL";
+       if (data.license == NULL)
+               license = "NULL";
+       if (data.script == NULL)
+               script = "NULL";
+       snprintf(debug, sizeof(debug), "%i", data.debug);
+       if (data.dfile == NULL)
+               dfile = "NULL";
+       int written = 0;
+       if (data.common[0] == NULL)
+               written += snprintf(common + written, sizeof(common) - written, "NULL, ");
+       else
+               written += snprintf(common + written, sizeof(common) - written, "%s, ", data.common[0]);
+       if (data.common[1] == NULL)
+               written += snprintf(common + written, sizeof(common) - written, "NULL, ");
+       else
+               written += snprintf(common + written, sizeof(common) - written, "%s, ", data.common[1]);
+       if (data.common[2] == NULL)
+               written += snprintf(common + written, sizeof(common) - written, "NULL, ");
+       else
+               written += snprintf(common + written, sizeof(common) - written, "%s, ", data.common[2]);
+       if (data.common[3] == NULL)
+               written += snprintf(common + written, sizeof(common) - written, "NULL");
+       else
+               written += snprintf(common + written, sizeof(common) - written, "%s", data.common[3]);
+       snprintf(lib, sizeof(lib), "%i", data.lib);
+       if (data.lfile == NULL)
+               lfile = "NULL";
+
+       if (view)
+       {
+               char* msg[] = { shabang, header, description, license, script,
+                       debug, dfile, common, lib, lfile };
+
+               popupLabel(screen, msg, 10);
+       }
+       else
+       {
+               char* home = getenv("HOME");
+               if (!home)
+               {
+                       exec_result.status = 1;
+                       snprintf(exec_result.message, sizeof(exec_result.message), "no home dir"
+                               "found");
+                       return;
+               }
+
+               char spath[strlen(home) + strlen(settings) + 2];
+               snprintf(spath, sizeof(spath), "%s/%s", home, settings);
+               FILE* fsettings = fopen(spath, "w");
+               if (!fsettings)
+               {
+                       exec_result.status = errno;
+                       strerror_r(errno, exec_result.message, sizeof(exec_result.message));
+                       return;
+               }
+
+               const char* fstring = "shabang=%s\nheader=%i\ndescription=\"%s\"\nlicense=%s\n"
+                       "script=%s\ndebug=%i\ndfile=%s\ncommon1=\"%s\"\ncommon2=\"%s\"\ncommon3=\"%s\"\n"
+                       "common4=\"%s\"\nlib=%i\nlfile=%s\n";
+               int res = fprintf(fsettings, fstring, data.shabang, data.header, data.description,
+                       data.license, data.script, data.debug, data.dfile, data.common[0], data.common[1],
+                       data.common[2], data.common[3], data.lib, data.lfile);
+               fclose(fsettings);
+               if (res < 0)
+               {
+                       exec_result.status = 1;
+                       snprintf(exec_result.message, sizeof(exec_result.message), "writing settings"
+                               "failed");
+                       return;
+               }
+       }
+}
+
+static int help(EObjectType cdktype, void* object, void* clientdata, chtype key)
+{
+       char* buttons[] = { " OK " };
+       char** info = (char**) calloc(2, sizeof(char*));
+       info[0] = (char*) malloc(5 + strlen(help_file));
+       snprintf(info[0], 5 + strlen(help_file), "<F=%s>", help_file);
+
+       char* text = commands_msg;
+       update_options(help_opts);
+       CDKSCREEN* screen = (CDKSCREEN*) clientdata;
+       CDKVIEWER* help_viewer = newCDKViewer(screen, CENTER, CENTER, y_size - 4, x_size - 2,
+               buttons, 1, A_REVERSE, TRUE, FALSE);
+       setCDKViewer(help_viewer, "</C></B>Help<!B><!C>", info, -1, A_REVERSE, TRUE, FALSE, FALSE);
+       activateCDKViewer(help_viewer, NULL);
+       destroyCDKViewer(help_viewer);
+       update_options(text);
+       refreshCDKScreen(screen);
+
+       return TRUE;
+}
+
+static int quit(EObjectType cdktype, void* object, void* clientdata, chtype key)
+{
+       char* buttons[] = { " OK ", " Cancel " };
+       char* msg[] = { "Realy quit?" };
+       char* text = commands_msg;
+       update_options(button_opts);
+       int res = popupDialog(screen, msg, 1, buttons, 2);
+       if (res == 0)
+       {
+               destroy_controls();
+               destroyCDKScreen(screen);
+               endCDK();
+               exit(EXIT_SUCCESS);
+       }
+       update_options(text);
+
+       return TRUE;
+}
+
+void sig_int(int signo)
+{
+       quit(0, NULL, NULL, 0);
+}
+
+int main(int argc, char* argv[])
+{
+       dimension_check();
+
+       window = initscr();
+       screen = initCDKScreen(window);
+       initCDKColor();
+
+       create_controls();
+
+       bindCDKObject(vRADIO, shabang_radio, '?', help, screen);
+       bindCDKObject(vSELECTION, header_selection, '?', help, screen);
+       bindCDKObject(vENTRY, description_entry, '?', help, screen);
+       bindCDKObject(vRADIO, license_radio, '?', help, screen);
+       bindCDKObject(vBUTTON, script_button, '?', help, screen);
+       bindCDKObject(vENTRY, script_entry, '?', help, screen);
+       bindCDKObject(vSELECTION, debug_selection, '?', help, screen);
+       bindCDKObject(vBUTTON, dfile_button, '?', help, screen);
+       bindCDKObject(vENTRY, dfile_entry, '?', help, screen);
+       bindCDKObject(vSELECTION, common_selection, '?', help, screen);
+       bindCDKObject(vSELECTION, lib_selection, '?', help, screen);
+       bindCDKObject(vBUTTON, lfile_button, '?', help, screen);
+       bindCDKObject(vENTRY, lfile_entry, '?', help, screen);
+       bindCDKObject(vBUTTON, generate_button, '?', help, screen);
+
+       bindCDKObject(vRADIO, shabang_radio, KEY_F10, quit, screen);
+       bindCDKObject(vSELECTION, header_selection, KEY_F10, quit, screen);
+       bindCDKObject(vENTRY, description_entry, KEY_F10, quit, screen);
+       bindCDKObject(vRADIO, license_radio, KEY_F10, quit, screen);
+       bindCDKObject(vBUTTON, script_button, KEY_F10, quit, screen);
+       bindCDKObject(vENTRY, script_entry, KEY_F10, quit, screen);
+       bindCDKObject(vSELECTION, debug_selection, KEY_F10, quit, screen);
+       bindCDKObject(vBUTTON, dfile_button, KEY_F10, quit, screen);
+       bindCDKObject(vENTRY, dfile_entry, KEY_F10, quit, screen);
+       bindCDKObject(vSELECTION, common_selection, KEY_F10, quit, screen);
+       bindCDKObject(vSELECTION, lib_selection, KEY_F10, quit, screen);
+       bindCDKObject(vBUTTON, lfile_button, KEY_F10, quit, screen);
+       bindCDKObject(vENTRY, lfile_entry, KEY_F10, quit, screen);
+       bindCDKObject(vBUTTON, generate_button, KEY_F10, quit, screen);
+
+       signal(SIGINT, sig_int);
+
+       int res;
+       while (TRUE)
+       {
+               res = process_shabang();
+               if (res)
+                       continue;
+
+               res = process_header();
+               if (res)
+                       continue;
+
+               res = process_script();
+               if (res)
+                       continue;
+
+               res = process_debug();
+               if (res)
+                       continue;
+
+               res = process_common();
+               if (res)
+                       continue;
+
+               res = process_lib();
+               if (res)
+                       continue;
+
+               res = process_gen();
+               if (res)
+                       continue;
+
+               break;
+       }
+
+       destroy_controls();
+
+       destroyCDKScreen(screen);
+       endCDK();
+
+       return 0;
+}
diff --git a/src/usr_share_shgen/GPLv2 b/src/usr_share_shgen/GPLv2
new file mode 100644 (file)
index 0000000..6cf5064
--- /dev/null
@@ -0,0 +1,14 @@
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
diff --git a/src/usr_share_shgen/GPLv3 b/src/usr_share_shgen/GPLv3
new file mode 100644 (file)
index 0000000..5c296cf
--- /dev/null
@@ -0,0 +1,12 @@
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
diff --git a/src/usr_share_shgen/custom b/src/usr_share_shgen/custom
new file mode 100644 (file)
index 0000000..3b9f63e
--- /dev/null
@@ -0,0 +1 @@
+# This is a custom license...
diff --git a/src/usr_share_shgen/help b/src/usr_share_shgen/help
new file mode 100644 (file)
index 0000000..bd86e49
--- /dev/null
@@ -0,0 +1,42 @@
+GENERAL COMMANDS
+
+<?> - Show this help.
+<F10> - Quit the application.
+
+Context commands are shown in the line at the bottom. They change when you
+change to an other generation option.
+
+GENERATION OPTIONS AND SETTINGS
+
+Shabang - Choose one for the type of shell script. Keep in mind different shell
+capabilities.
+
+Header - Activates header. The header contains sctipt author and year of
+creation as well as a description line and the licence text. If this option is
+not set the following two options have no effect.
+
+Description - A short desctiption of what the generated sctipt is intended to
+do.
+
+License - Choose a license option that comes up with the header. Since the
+application creates the ~/.shgen directory the custom license file goes there.
+Modify it to get your license text into the header.
+
+Script name and path - Choose where to generate the shell script. Navigate to
+the destination first and then enter a name.
+
+Debug - Activates debug output. Your shell script is then using set -x and the
+output is going to a file. This option activates the next one.
+
+Debug file name and path - Choose where debug output is going to. Navigate to
+the destination first and then enter a name.
+
+Functions - Choosing usage() gives your sctipt the -h option and prints info
+about script usage. log(), error() and warning() are functions you can use to
+print log output to stdout. error() terminates script execution after its call.
+
+lib.sh - Activates generation of a common script where log(), error() and
+warning() are going to. This options activates the next one.
+
+lib.sh path - Choose location of lib.sh. Navigate to the destination first and
+then enter a name.
diff --git a/src/usr_share_shgen/lib b/src/usr_share_shgen/lib
new file mode 100644 (file)
index 0000000..5df564c
--- /dev/null
@@ -0,0 +1,13 @@
+%shabang%
+#
+# Library functions and definitions.
+%copyright%
+#
+%license%
+
+LANG=C
+%debug%
+
+%common2%
+%common3%
+%common4%
diff --git a/src/usr_share_shgen/shgen.sh b/src/usr_share_shgen/shgen.sh
new file mode 100755 (executable)
index 0000000..5f78d00
--- /dev/null
@@ -0,0 +1,352 @@
+#!/bin/bash
+
+INSTALL_DIR=/usr/share/shgen
+LOCAL_DIR=~/.shgen
+SETTINGS=$LOCAL_DIR/settings
+
+ERR_FILE=/tmp/shgen.tmp
+
+E_NOARGS=1
+E_CREATE_DIR=2
+E_GENERATE=3
+
+LANG=C
+
+create_dir()
+{
+       if ! [ -e $LOCAL_DIR ]; then
+               # create local dir
+               mkdir $LOCAL_DIR 2>$ERR_FILE 1>/dev/null ||\
+                error "creating local dir failed" $E_CREATE_DIR $ERR_FILE
+               # copy files and set permisson
+               cp $INSTALL_DIR/skeleton $INSTALL_DIR/custom $INSTALL_DIR/GPLv*\
+                $INSTALL_DIR/lib $LOCAL_DIR/ 2>$ERR_FILE 1>/dev/null ||\
+                error "copying files failed" $E_CREATE_DIR $ERR_FILE
+       fi
+}
+
+error()
+{
+       echo -n "Error: $1" 1>&2
+       [ -z $3 ] && echo "" || echo -e ":\n$(cat $3)" 1>&2
+       exit $2
+}
+
+generate()
+{
+       # read/source settings file
+       . $SETTINGS
+
+       # generate main script according to the settings
+       cp $LOCAL_DIR/skeleton $script 2>$ERR_FILE 1>/dev/null ||\
+        error "creating script failed" $E_GENERATE $ERR_FILE
+       chmod +x $script 2>$ERR_FILE 1>/dev/null ||\
+        error "setting script permisson failed" $E_GENERATE $ERR_FILE
+
+       ###################################################
+       # lib
+       ###################################################
+       if [ $lib -eq 1 ]; then
+               # generate lib script according to the settings
+               cp $LOCAL_DIR/lib $lfile 2>$ERR_FILE 1>/dev/null ||\
+                error "creating lib failed" $E_GENERATE $ERR_FILE
+               chmod +x $lfile 2>$ERR_FILE 1>/dev/null ||\
+                error "setting lib permisson failed" $E_GENERATE $ERR_FILE
+               # write settings
+               sed "s:%lib%:. $lfile:" -i $script 2>$ERR_FILE\
+                1>/dev/null || error "writing lib failed" $E_GENERATE $ERR_FILE
+       else
+               # delete placeholder
+               sed "/%lib%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting lib placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       ###################################################
+       # shabang
+       ###################################################
+       sed "s:%shabang%:#!$shabang:" -i $script 2>$ERR_FILE 1>/dev/null ||\
+        error "writing shabang failed" $E_GENERATE $ERR_FILE
+       if [ $lib -eq 1 ]; then
+               sed "s:%shabang%:#!$shabang:" -i $lfile 2>$ERR_FILE\
+                1>/dev/null || error "writing shabang in lib failed" $E_GENERATE\
+                $ERR_FILE
+       fi
+
+       ###################################################
+       # header
+       ###################################################
+       if [ $header -eq 1 ]; then
+               # description, copyright
+               local copyright="# Copyright (C) $(date +%Y) $USER"
+               sed -e "s/%description%/# $description/" -e\
+                "s/%copyright%/$copyright/" -i $script 2>$ERR_FILE 1>/dev/null\
+                || error "writing header failed" $E_GENERATE $ERR_FILE
+               # same to lib
+               if [ $lib -eq 1 ]; then
+                       sed "s/%copyright%/$copyright/" -i $lfile 2>$ERR_FILE\
+                        1>/dev/null || error "writing header in lib failed"\
+                        $E_GENERATE $ERR_FILE
+               fi
+
+               # license
+               case $license in
+                       GPLv2|GPLv3|custom)
+                               sed "/%license%/r $LOCAL_DIR/$license" -i $script\
+                                2>$ERR_FILE 1>/dev/null || error "writing header failed"\
+                                $E_GENERATE $ERR_FILE
+                               # same to lib
+                               if [ $lib -eq 1 ]; then
+                                       sed "/%license%/r $LOCAL_DIR/$license" -i $lfile\
+                                        2>$ERR_FILE 1>/dev/null || error\
+                                        "writing header in lib failed" $E_GENERATE $ERR_FILE
+                               fi
+                               ;;
+               esac
+               sed "/%license%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting header placeholder failed" $E_GENERATE $ERR_FILE
+               # same to lib
+               if [ $lib -eq 1 ]; then
+                       sed "/%license%/d" -i $lfile 2>$ERR_FILE 1>/dev/null || error\
+                        "deleting header placeholder in lib failed" $E_GENERATE\
+                        $ERR_FILE
+               fi
+       else
+               # delete placeholder
+               sed -e "/%description%/d" -e "/%copyright%/d" -e "/%license%/d"\
+                -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting header placeholder failed" $E_GENERATE $ERR_FILE
+               # same to lib
+               if [ $lib -eq 1 ]; then
+                       sed -e "/%copyright%/d" -e "/%license%/d" -i $lfile 2>$ERR_FILE\
+                        1>/dev/null || error "deleting header placeholder in lib failed"\
+                        $E_GENERATE $ERR_FILE
+               fi
+       fi
+
+       # create temp file
+       local tmpf=$(mktemp 2>$ERR_FILE)
+       [ -e $tmpf ] || error "creating tmpfile failed" $E_GENERATE $ERR_FILE
+
+       ###################################################
+       # debug
+       ###################################################
+       if [ $debug -eq 1 ]; then
+               cat << EOF >/$tmpf
+exec 3>$dfile
+BASH_XTRACEFD=3
+set -x
+EOF
+               if [ $lib -eq 1 ]; then
+                       sed -e "/%debug%/r $tmpf" -e "/%debug%/d" -i $lfile\
+                        2>$ERR_FILE 1>/dev/null || error\
+                        "writing debug in lib failed" $E_GENERATE $ERR_FILE
+                       # delete placeholder in script
+                       sed "/%debug%/d" -i $script 2>$ERR_FILE 1>/dev/null ||\
+                        error "deleting debug placeholder failed" $E_GENERATE\
+                        $ERR_FILE
+               else
+                       sed -e "/%debug%/r $tmpf" -e "/%debug%/d" -i $script\
+                        2>$ERR_FILE 1>/dev/null || error "writing debug failed"\
+                        $E_GENERATE $ERR_FILE
+               fi
+       else
+               # delete placeholder
+               sed "/%debug%/d" -i $script 2>$ERR_FILE 1>/dev/null ||\
+                error "deleting debug placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       ###################################################
+       # usage()
+       ###################################################
+       if [ "$common1" == "usage()" ]; then
+               cat << _EOF >/$tmpf
+usage()
+{
+       cat << EOF
+Usage: \$0 [-h]
+
+Options:  -h  show help (resp. this message)
+EOF
+}
+
+_EOF
+               # place description if available
+               if [ $header -eq 1 ]; then
+                       sed -e "4i$description" -i $tmpf
+               fi
+               sed -e "/%common1%/r $tmpf" -e "/%common1%/d" -i $script 2>$ERR_FILE\
+                1>/dev/null || error "writing common1 in lib failed" $E_GENERATE\
+                $ERR_FILE
+       else
+               # delete placeholder
+               if [ $debug -eq 1 ]; then
+                       sed "/%common1%/d" -i $lfile 2>$ERR_FILE 1>/dev/null || error\
+                        "deleting common2 placeholder in lib failed" $E_GENERATE $ERR_FILE
+               fi
+               sed "/%common1%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting common1 placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       ###################################################
+       # log()
+       ###################################################
+       if [ "$common2" == "log()" ]; then
+               cat << _EOF >/$tmpf
+log()
+{
+       echo -n "\$(basename \$0): LOG: \$1"
+       [ -z \$2 ] || { echo; echo "\$2"; } && { echo; }
+}
+
+_EOF
+               if [ $lib -eq 1 ]; then
+                       sed -e "/%common2%/r $tmpf" -e "/%common2%/d" -i $lfile\
+                        2>$ERR_FILE 1>/dev/null || error "writing common2 failed"\
+                        $E_GENERATE $ERR_FILE
+                       # delete placeholder in script
+                       sed "/%common2%/d" -i $script 2>$ERR_FILE 1>/dev/null ||\
+                        error "deleting common2 placeholder failed" $E_GENERATE\
+                        $ERR_FILE
+               else
+                       sed -e "/%common2%/r $tmpf" -e "/%common2%/d" -i $script\
+                        2>$ERR_FILE 1>/dev/null || error "writing common2 in lib failed"\
+                        $E_GENERATE $ERR_FILE
+               fi
+       else
+               # delete placeholder
+               if [ $debug -eq 1 ]; then
+                       sed "/%common2%/d" -i $lfile 2>$ERR_FILE 1>/dev/null || error\
+                        "deleting common2 placeholder in lib failed" $E_GENERATE $ERR_FILE
+               fi
+               sed "/%common2%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting common2 placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       ###################################################
+       # error()
+       ###################################################
+       if [ "$common3" == "error()" ]; then
+               cat << _EOF >/$tmpf
+error()
+{
+       echo -n "\$(basename \$0): ERROR: \$1"
+       [ -z \$2 ] || { echo; echo "\$2"; } && { echo; }
+       exit 1
+}
+
+_EOF
+               if [ $lib -eq 1 ]; then
+                       sed -e "/%common3%/r $tmpf" -e "/%common3%/d" -i $lfile\
+                        2>$ERR_FILE 1>/dev/null || error "writing common3 failed"\
+                        $E_GENERATE $ERR_FILE
+                       # delete placeholder in script
+                       sed "/%common3%/d" -i $script 2>$ERR_FILE 1>/dev/null ||\
+                        error "deleting common3 placeholder failed" $E_GENERATE\
+                        $ERR_FILE
+               else
+                       sed -e "/%common3%/r $tmpf" -e "/%common3%/d" -i $script\
+                        2>$ERR_FILE 1>/dev/null || error "writing common3 in lib failed"\
+                        $E_GENERATE $ERR_FILE
+               fi
+       else
+               # delete placeholder
+               if [ $debug -eq 1 ]; then
+                       sed "/%common3%/d" -i $lfile 2>$ERR_FILE 1>/dev/null || error\
+                        "deleting common3 placeholder in lib failed" $E_GENERATE $ERR_FILE
+               fi
+               sed "/%common3%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting common3 placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       ###################################################
+       # warning()
+       ###################################################
+       if [ "$common4" == "warning()" ]; then
+               cat << _EOF >/$tmpf
+log()
+{
+       echo -n "\$(basename \$0): WARNING: \$1"
+       [ -z \$2 ] || { echo; echo "\$2"; } && { echo; }
+}
+
+_EOF
+               if [ $lib -eq 1 ]; then
+                       sed -e "/%common4%/r $tmpf" -e "/%common4%/d" -i $lfile\
+                        2>$ERR_FILE 1>/dev/null || error "writing common4 failed"\
+                        $E_GENERATE $ERR_FILE
+                       # delete placeholder in script
+                       sed "/%common4%/d" -i $script 2>$ERR_FILE 1>/dev/null ||\
+                        error "deleting common4 placeholder failed" $E_GENERATE\
+                        $ERR_FILE
+               else
+                       sed -e "/%common4%/r $tmpf" -e "/%common4%/d" -i $script\
+                        2>$ERR_FILE 1>/dev/null || error "writing common4 in lib failed"\
+                        $E_GENERATE $ERR_FILE
+               fi
+       else
+               # delete placeholder
+               if [ $debug -eq 1 ]; then
+                       sed "/%common4%/d" -i $lfile 2>$ERR_FILE 1>/dev/null || error\
+                        "deleting common4 placeholder in lib failed" $E_GENERATE $ERR_FILE
+               fi
+               sed "/%common4%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting common4 placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       # delete temp file
+       rm $tmpf &>/dev/null
+
+       ###################################################
+       # option processing
+       ###################################################
+       if [ "$common1" == "usage()" ]; then
+               cat << _EOF >/$tmpf
+while getopts ":h" opt; do
+       case \$opt in
+               h)
+                       usage
+                       ;;
+               *)
+                       usage
+                       ;;
+       esac
+done
+_EOF
+               sed -e "/%options%/r $tmpf" -e "/%options%/d" -i $script 2>$ERR_FILE\
+                1>/dev/null || error "writing options failed" $E_GENERATE $ERR_FILE
+       else
+               # delete placeholder
+               sed "/%options%/d" -i $script 2>$ERR_FILE 1>/dev/null || error\
+                "deleting options placeholder failed" $E_GENERATE $ERR_FILE
+       fi
+
+       # delete temp file
+       rm $tmpf &>/dev/null
+}
+
+usage()
+{
+       cat <<EOF
+Usage: $0 -<c|g>
+
+Options:  -c  create the local directory ~/.shgen
+          -g  generate shell scripts according to the settings
+EOF
+       exit $E_NOARGS
+}
+
+[ $# -eq 0 ] && usage
+
+while getopts ":cg" opt; do
+       case $opt in
+               c)
+                       create_dir
+                       ;;
+               g)
+                       generate
+                       ;;
+               *)
+                       usage
+                       ;;
+       esac
+done
diff --git a/src/usr_share_shgen/skeleton b/src/usr_share_shgen/skeleton
new file mode 100644 (file)
index 0000000..e4f4450
--- /dev/null
@@ -0,0 +1,28 @@
+%shabang%
+#
+%description%
+%copyright%
+#
+%license%
+
+LANG=C
+STDERR=$(mktemp)
+%debug%
+
+%lib%
+
+%common1%
+%common2%
+%common3%
+%common4%
+%options%
+
+#
+# Your code goes here.
+# Using the generated error function a sample instruction looks as follows:
+#
+# mkdir what_a_nice_dir 1>/dev/null 2>$STDERR ||\
+#  error "mkdir failed" "$(cat $STDERR)"
+#
+
+exit 0