112 | .SH "REPORT BUGS TO"
113 | the author.
114 |
--------------------------------------------------------------------------------
/contrib/shc-3.8.9/shc.README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaagr/shellscripts/dc2dd7addeb2e1bb794d9c459adffaafea757783/contrib/shc-3.8.9/shc.README
--------------------------------------------------------------------------------
/contrib/shc-3.8.9/shc.c:
--------------------------------------------------------------------------------
1 | shc-3.8.9.c
--------------------------------------------------------------------------------
/contrib/shc-3.8.9/shc.html:
--------------------------------------------------------------------------------
1 | Content-type: text/html
2 |
3 | Manpage of shc
4 |
5 | shc
6 | Section: User Commands (1)
Updated: Jun 18, 2003
Index
7 | Return to Main Contents
8 |
9 |
10 |
11 |
12 |
NAME
13 |
14 | shc - Generic shell script compiler
15 |
16 | SYNOPSIS
17 |
18 | shc
19 |
20 | [ -e date ]
21 | [ -m addr ]
22 | [ -i iopt ]
23 | [ -x cmnd ]
24 |
25 |
26 | [ -l lopt ]
27 | [ -ACDhTv ]
28 | -f script
29 |
30 | DESCRIPTION
31 |
32 | shc
33 |
34 | creates a stripped binary executable version of the script
35 | specified with -f on the command line.
36 |
37 | The binary version will get a .x extension appended
38 | and will usually be a bit larger in size than the original ascii code.
39 | Generated C source code is saved in a file with the extension .x.c
40 |
41 | If you supply an expiration date with the -e option the
42 | compiled binary will refuse to run after the date specified.
43 | The message "Please contact your provider" will be displayed instead.
44 | This message can be changed with the -m option.
45 |
46 | You can compile any kind of shell script, but you need to supply valid
47 | -i, -x and -l options.
48 |
49 | The compiled binary will still be dependent on the shell specified
50 | in the first line of the shell code (i.e. #!/bin/sh), thus shc does not create
51 | completely independent binaries.
52 |
53 | shc itself is not a compiler such as cc, it rather encodes and
54 | encrypts a shell script and generates C source code with the added expiration
55 | capability. It then uses the system compiler to compile a stripped binary
56 | which behaves exactly like the original script. Upon execution, the compiled binary
57 | will decrypt and execute the code with the shell -c option.
58 | Unfortunatelly, it will not give you any speed improvement as a real C program would.
59 |
60 | shc's main purpose is to protect your shell scripts from modification or
61 | inspection. You can use it if you wish to distribute your scripts but don't
62 | want them to be easily readable by other people.
63 |
64 |
OPTIONS
65 |
66 | The command line options are:
67 |
68 | - -e date
69 |
70 |
-
71 | Expiration date in dd/mm/yyyy format [none]
72 |
- -m message
73 |
74 |
-
75 | message to display upon expiration ["Please contact your provider"]
76 |
- -f script_name
77 |
78 |
-
79 | File name of the script to compile
80 |
- -i inline_option
81 |
82 |
-
83 | Inline option for the shell interpreter i.e: -e
84 |
- -x comand
85 |
86 |
-
87 | eXec command, as a printf format i.e: exec(\\'%s\\',@ARGV);
88 |
- -l last_option
89 |
90 |
-
91 | Last shell option i.e: --
92 |
- -r
93 |
94 |
-
95 | Relax security. Make a redistributable binary which executes on
96 | different systems running the same operating system.
97 |
- -v
98 |
99 |
-
100 | Verbose compilation
101 |
- -D
102 |
103 |
-
104 | Switch on debug exec calls
105 |
- -T
106 |
107 |
-
108 | Allow binary to be traceable (using strace, ptrace, truss, etc.)
109 |
- -C
110 |
111 |
-
112 | Display license and exit
113 |
- -A
114 |
115 |
-
116 | Display abstract and exit
117 |
- -h
118 |
119 |
-
120 | Display help and exit
121 |
122 |
123 | ENVIRONMENT VARIABLES
124 |
125 |
126 | - CC
127 |
128 |
-
129 | C compiler command [cc]
130 |
- CFLAGS
131 |
132 |
-
133 | C compiler flags [none]
134 |
135 |
136 | EXAMPLES
137 |
138 | Compile a script which can be run on other systems with the trace
139 | option enabled:
140 |
141 |
example% shc -v -r -T -f myscript
142 |
143 |
BUGS
144 |
145 | The maximum size of the script that could be executed once compiled is limited
146 | by the operating system configuration parameter
147 | _SC_ARG_MAX
148 |
149 | (see
150 | sysconf(2))
151 |
152 | AUTHOR
153 |
154 | Francisco Rosales
155 | <frosal@fi.upm.es>
156 |
157 | REPORT BUGS TO
158 |
159 | the author.
160 |
161 |
162 |
163 | Index
164 |
165 | - NAME
-
166 |
- SYNOPSIS
-
167 |
- DESCRIPTION
-
168 |
- OPTIONS
-
169 |
- ENVIRONMENT VARIABLES
-
170 |
- EXAMPLES
-
171 |
- BUGS
-
172 |
- AUTHOR
-
173 |
- REPORT BUGS TO
-
174 |
175 |
176 | This document was created by
177 | man2html,
178 | using the manual pages.
179 | Time: 15:46:31 GMT, July 08, 2004
180 |
181 |
182 |
--------------------------------------------------------------------------------
/contrib/shc-3.8.9/test.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | echo "\$@ is $@"
3 | echo "command line: $0 $*"
4 | echo "hello world"
5 | # Added
6 | echo "[$$] PAUSED... Hit return!"
7 | read DUMMY
8 | exit 0
9 |
--------------------------------------------------------------------------------
/contrib/shc-3.8.9/test.csh:
--------------------------------------------------------------------------------
1 | #!/bin/csh -x
2 | echo Hello world
3 |
4 | # A comment
5 |
6 | exit 0
7 |
--------------------------------------------------------------------------------
/contrib/shc-3.8.9/test.ksh:
--------------------------------------------------------------------------------
1 | #! /usr/bin/ksh -x
2 | echo "\$@ is $@"
3 | echo "command line: $0 $*"
4 | echo "hello world"
5 | # Added
6 | echo "[$$] PAUSED... Hit return!"
7 | read DUMMY
8 | exit 0
9 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/changelog.txt:
--------------------------------------------------------------------------------
1 | -----
2 | 0.1.1
3 | -----
4 |
5 | Added this changelog.
6 |
7 | Added an internal function for getting absolute paths in the generic
8 | script loader-extended.sh. Normal shells are now independent of the
9 | external commands getabspath and awk.
10 |
11 | Fixed detection of the optional external command getabspath. This time
12 | also, it will only be used if the newly added internal function doesn't
13 | work for the shell.
14 |
15 | No other changes were made in the other scripts.
16 |
17 | ---
18 | 0.1
19 | ---
20 |
21 | First Presentable Release
22 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/compiler:
--------------------------------------------------------------------------------
1 | compiler-20141212.gawk
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/loader.bash:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 |
4 | # ----------------------------------------------------------------------
5 |
6 | # loader.bash
7 | #
8 | # This script implements Shell Script Loader for all versions of bash
9 | # starting 2.04.
10 | #
11 | # The script works faster with associative arrays. To use associative
12 | # arrays, run the script with bash 4.2 or newer. You can also enable
13 | # usage of associative arrays with 4.0 or 4.1 by including it globally;
14 | # that is, not include the script with 'source' or '.' inside any
15 | # function.
16 | #
17 | # Please see loader.txt for more info on how to use this script.
18 | #
19 | # This script complies with the Requiring Specifications of
20 | # Shell Script Loader version 0 (RS0)
21 | #
22 | # Version: 0.1
23 | #
24 | # Author: konsolebox
25 | # Copyright Free / Public Domain
26 | # Aug. 29, 2009 (Last Updated 2011/04/08)
27 |
28 | # Limitations of Shell Script Loader with integers and associative
29 | # arrays:
30 | #
31 | # With versions of bash earlier than 4.2, a variable can't be declared
32 | # global with the use of 'typeset' and 'declare' builtins when inside a
33 | # function. With Shell Script Loader, shell scripts are always loaded
34 | # inside functions so variables that can only be declared using the said
35 | # builtin commands cannot be declared global. These kinds of variables
36 | # that cannot be declared global are the newer types like associative
37 | # arrays and integers. Unlike Zsh, we can add '-g' as an option to
38 | # 'typeset' or 'declare' to declare global variables but we can't do
39 | # that in bash.
40 | #
41 | # For example, if we do something like
42 | #
43 | # > include file.sh
44 | #
45 | # Where the contents of file.sh is
46 | #
47 | # > declare -A associative_array
48 | # > declare -i integer
49 | #
50 | # After include() ends, the variables automatically gets lost since
51 | # variables are only local and not global if declare or typeset is used
52 | # inside a function and we know that include() is a function.
53 | #
54 | # However it's safe to declare other types of variables like indexed
55 | # arrays in simpler way.
56 | #
57 | # For example:
58 | #
59 | # > SIMPLEVAR=''
60 | # > ARRAYVAR=()
61 | #
62 | # These declarations are even just optional.
63 | #
64 | # Note: These conditions do not apply if you only plan to run the code
65 | # in compiled form since you no longer have to use the functions. For
66 | # more info about compilation, please see the available compilers of
67 | # Shell Script Loader.
68 |
69 |
70 | # ----------------------------------------------------------------------
71 |
72 |
73 | if [ "$LOADER_ACTIVE" = true ]; then
74 | echo "loader: loader cannot be loaded twice."
75 | exit 1
76 | fi
77 | if [ -z "$BASH_VERSION" ]; then
78 | echo "loader: bash is needed to run this script."
79 | exit 1
80 | fi
81 | case "$BASH" in
82 | sh|*/sh)
83 | echo "loader: this script doesn't work if bash is running sh-emulation mode."
84 | exit 1
85 | ;;
86 | esac
87 | if ! [ "$BASH_VERSINFO" -ge 3 -o "$BASH_VERSION" '>' 2.03 ]; then
88 | echo "loader: this script is only compatible with versions of bash not earlier than 2.04."
89 | exit 1
90 | fi
91 | if ! declare -a LOADER_TEST0; then
92 | echo "loader: it seems that this build of bash does not include support for arrays."
93 | exit 1
94 | fi
95 |
96 |
97 | #### PUBLIC VARIABLES ####
98 |
99 | LOADER_ACTIVE=true
100 | LOADER_RS=0
101 | LOADER_VERSION=0.1
102 |
103 |
104 | #### PRIVATE VARIABLES ####
105 |
106 | LOADER_CS=()
107 | LOADER_CS_I=0
108 | LOADER_PATHS=()
109 |
110 | if [[ BASH_VERSINFO -ge 5 || (BASH_VERSINFO -eq 4 && BASH_VERSINFO[1] -ge 2) ]]; then
111 | declare -g -A LOADER_FLAGS=()
112 | declare -g -A LOADER_PATHS_FLAGS=()
113 | LOADER_USEAARRAYS=true
114 | elif [[ BASH_VERSINFO -eq 4 ]] && declare -A LOADER_TEST1 &>/dev/null && ! local LOADER_TEST2 &>/dev/null; then
115 | declare -A LOADER_FLAGS=()
116 | declare -A LOADER_PATHS_FLAGS=()
117 | LOADER_USEAARRAYS=true
118 | else
119 | LOADER_USEAARRAYS=false
120 | fi
121 |
122 |
123 | #### PUBLIC FUNCTIONS ####
124 |
125 | function load {
126 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." load
127 |
128 | case "$1" in
129 | '')
130 | loader_fail "file expression cannot be null." load "$@"
131 | ;;
132 | /*|./*|../*)
133 | if [[ -f $1 ]]; then
134 | loader_getabspath "$1"
135 |
136 | [[ -r $__ ]] || loader_fail "file not readable: $__" load "$@"
137 |
138 | shift
139 | loader_load "$@"
140 |
141 | return
142 | fi
143 | ;;
144 | *)
145 | for __ in "${LOADER_PATHS[@]}"; do
146 | [[ -f $__/$1 ]] || continue
147 |
148 | loader_getabspath "$__/$1"
149 |
150 | [[ -r $__ ]] || loader_fail "found file not readable: $__" load "$@"
151 |
152 | loader_flag_ "$1"
153 |
154 | shift
155 | loader_load "$@"
156 |
157 | return
158 | done
159 | ;;
160 | esac
161 |
162 | loader_fail "file not found: $1" load "$@"
163 | }
164 |
165 | function include {
166 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." include
167 |
168 | case "$1" in
169 | '')
170 | loader_fail "file expression cannot be null." include "$@"
171 | ;;
172 | /*|./*|../*)
173 | loader_getabspath "$1"
174 |
175 | loader_flagged "$__" && \
176 | return
177 |
178 | if [[ -f $__ ]]; then
179 | [[ -r $__ ]] || loader_fail "file not readable: $__" include "$@"
180 |
181 | shift
182 | loader_load "$@"
183 |
184 | return
185 | fi
186 | ;;
187 | *)
188 | loader_flagged "$1" && \
189 | return
190 |
191 | for __ in "${LOADER_PATHS[@]}"; do
192 | loader_getabspath "$__/$1"
193 |
194 | if loader_flagged "$__"; then
195 | loader_flag_ "$1"
196 |
197 | return
198 | elif [[ -f $__ ]]; then
199 | [[ -r $__ ]] || loader_fail "found file not readable: $__" include "$@"
200 |
201 | loader_flag_ "$1"
202 |
203 | shift
204 | loader_load "$@"
205 |
206 | return
207 | fi
208 | done
209 | ;;
210 | esac
211 |
212 | loader_fail "file not found: $1" include "$@"
213 | }
214 |
215 | function call {
216 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." call
217 |
218 | case "$1" in
219 | '')
220 | loader_fail "file expression cannot be null." call "$@"
221 | ;;
222 | /*|./*|../*)
223 | if [[ -f $1 ]]; then
224 | loader_getabspath "$1"
225 |
226 | [[ -r $__ ]] || loader_fail "file not readable: $__" call "$@"
227 |
228 | (
229 | shift
230 | loader_load "$@"
231 | )
232 |
233 | return
234 | fi
235 | ;;
236 | *)
237 | for __ in "${LOADER_PATHS[@]}"; do
238 | [[ -f $__/$1 ]] || continue
239 |
240 | loader_getabspath "$__/$1"
241 |
242 | [[ -r $__ ]] || loader_fail "found file not readable: $__" call "$@"
243 |
244 | (
245 | loader_flag_ "$1"
246 |
247 | shift
248 | loader_load "$@"
249 | )
250 |
251 | return
252 | done
253 | ;;
254 | esac
255 |
256 | loader_fail "file not found: $1" call "$@"
257 | }
258 |
259 | function loader_addpath {
260 | for __ in "$@"; do
261 | [[ -d $__ ]] || loader_fail "directory not found: $__" loader_addpath "$@"
262 | [[ -x $__ ]] || loader_fail "directory not accessible: $__" loader_addpath "$@"
263 | [[ -r $__ ]] || loader_fail "directory not searchable: $__" loader_addpath "$@"
264 | loader_getabspath_ "$__/."
265 | loader_addpath_ "$__"
266 | done
267 | }
268 |
269 | function loader_flag {
270 | [[ $# -eq 1 ]] || loader_fail "function requires a single argument." loader_flag "$@"
271 | loader_getabspath "$1"
272 | loader_flag_ "$__"
273 | }
274 |
275 | function loader_reset {
276 | if [[ $# -eq 0 ]]; then
277 | loader_resetflags
278 | loader_resetpaths
279 | elif [[ $1 = flags ]]; then
280 | loader_resetflags
281 | elif [[ $1 = paths ]]; then
282 | loader_resetpaths
283 | else
284 | loader_fail "invalid argument: $1" loader_reset "$@"
285 | fi
286 | }
287 |
288 | function loader_finish {
289 | LOADER_ACTIVE=false
290 |
291 | loader_unsetvars
292 |
293 | unset \
294 | load \
295 | include \
296 | call \
297 | loader_addpath \
298 | loader_addpath_ \
299 | loader_fail \
300 | loader_finish \
301 | loader_flag \
302 | loader_flag_ \
303 | loader_flagged \
304 | loader_getabspath \
305 | loader_getabspath_ \
306 | loader_load \
307 | loader_load_ \
308 | loader_reset \
309 | loader_resetflags \
310 | loader_resetpaths \
311 | loader_unsetvars \
312 | LOADER_CS \
313 | LOADER_CS_I \
314 | LOADER_PATHS
315 | }
316 |
317 |
318 | #### PRIVATE FUNCTIONS ####
319 |
320 | function loader_load {
321 | loader_flag_ "$__"
322 |
323 | LOADER_CS[LOADER_CS_I++]=$__
324 |
325 | loader_load_ "$@"
326 |
327 | __=$?
328 |
329 | unset LOADER_CS\[--LOADER_CS_I\]
330 |
331 | return "$__"
332 | }
333 |
334 | function loader_load_ {
335 | . "$__"
336 | }
337 |
338 | function loader_getabspath {
339 | case "$1" in
340 | .|'')
341 | case "$PWD" in
342 | /)
343 | __=/.
344 | ;;
345 | *)
346 | __=${PWD%/}
347 | ;;
348 | esac
349 | ;;
350 | ..|../*|*/..|*/../*|./*|*/.|*/./*|*//*)
351 | loader_getabspath_ "$1"
352 | ;;
353 | /*)
354 | __=$1
355 | ;;
356 | *)
357 | __=${PWD%/}/$1
358 | ;;
359 | esac
360 | }
361 |
362 | function loader_fail {
363 | local MESSAGE=$1 FUNC=$2 MAIN A I
364 | shift 2
365 |
366 | if [[ -n $0 && ! "${0##*/}" = "${BASH##*/}" ]]; then
367 | MAIN=$0
368 | else
369 | MAIN='(main)'
370 | fi
371 |
372 | {
373 | echo "loader: ${FUNC}(): ${MESSAGE}"
374 | echo
375 |
376 | echo " current scope:"
377 | if [[ LOADER_CS_I -gt 0 ]]; then
378 | echo " ${LOADER_CS[LOADER_CS_I - 1]}"
379 | else
380 | echo " $MAIN"
381 | fi
382 | echo
383 |
384 | if [[ $# -gt 0 ]]; then
385 | echo " command:"
386 | echo -n " $FUNC"
387 | for A; do
388 | echo -n " \"$A\""
389 | done
390 | echo
391 | echo
392 | fi
393 |
394 | if [[ LOADER_CS_I -gt 0 ]]; then
395 | echo " call stack:"
396 | echo " $MAIN"
397 | for A in "${LOADER_CS[@]}"; do
398 | echo " -> $A"
399 | done
400 | echo
401 | fi
402 |
403 | echo " search paths:"
404 | if [[ ${#LOADER_PATHS[@]} -gt 0 ]]; then
405 | for A in "${LOADER_PATHS[@]}"; do
406 | echo " $A"
407 | done
408 | else
409 | echo " (empty)"
410 | fi
411 | echo
412 |
413 | echo " working directory:"
414 | echo " $PWD"
415 | echo
416 | } >&2
417 |
418 | exit 1
419 | }
420 |
421 |
422 | #### VERSION DEPENDENT FUNCTIONS AND VARIABLES ####
423 |
424 | if [[ $LOADER_USEAARRAYS = true ]]; then
425 | function loader_addpath_ {
426 | if [[ -z ${LOADER_PATHS_FLAGS[$1]} ]]; then
427 | LOADER_PATHS[${#LOADER_PATHS[@]}]=$1
428 | LOADER_PATHS_FLAGS[$1]=.
429 | fi
430 | }
431 |
432 | function loader_flag_ {
433 | LOADER_FLAGS[$1]=.
434 | }
435 |
436 | function loader_flagged {
437 | [[ -n ${LOADER_FLAGS[$1]} ]]
438 | }
439 |
440 | function loader_resetflags {
441 | LOADER_FLAGS=()
442 | }
443 |
444 | function loader_resetpaths {
445 | LOADER_PATHS=()
446 | LOADER_PATHS_FLAGS=()
447 | }
448 |
449 | function loader_unsetvars {
450 | unset LOADER_FLAGS LOADER_PATHS_FLAGS
451 | }
452 | else
453 | function loader_addpath_ {
454 | for __ in "${LOADER_PATHS[@]}"; do
455 | [[ $1 = "$__" ]] && \
456 | return
457 | done
458 |
459 | LOADER_PATHS[${#LOADER_PATHS[@]}]=$1
460 | }
461 |
462 | function loader_flag_ {
463 | local V
464 | V=${1//./_dt_}
465 | V=${V// /_sp_}
466 | V=${V//\//_sl_}
467 | V=LOADER_FLAGS_${V//[^[:alnum:]_]/_ot_}
468 | eval "$V=."
469 | }
470 |
471 | function loader_flagged {
472 | local V
473 | V=${1//./_dt_}
474 | V=${V// /_sp_}
475 | V=${V//\//_sl_}
476 | V=LOADER_FLAGS_${V//[^[:alnum:]_]/_ot_}
477 | [[ -n ${!V} ]]
478 | }
479 |
480 | function loader_resetflags {
481 | local IFS=' '
482 | unset ${!LOADER_FLAGS_*}
483 | }
484 |
485 | function loader_resetpaths {
486 | LOADER_PATHS=()
487 | }
488 |
489 | function loader_unsetvars {
490 | loader_resetflags
491 | }
492 | fi
493 |
494 | if [[ BASH_VERSINFO -ge 3 ]]; then
495 | eval "
496 | function loader_getabspath_ {
497 | local -a T1 T2
498 | local -i I=0
499 | local IFS=/ A
500 |
501 | case \"\$1\" in
502 | /*)
503 | read -r -a T1 <<< \"\$1\"
504 | ;;
505 | *)
506 | read -r -a T1 <<< \"/\$PWD/\$1\"
507 | ;;
508 | esac
509 |
510 | T2=()
511 |
512 | for A in \"\${T1[@]}\"; do
513 | case \"\$A\" in
514 | ..)
515 | [[ I -ne 0 ]] && unset T2\\[--I\\]
516 | continue
517 | ;;
518 | .|'')
519 | continue
520 | ;;
521 | esac
522 |
523 | T2[I++]=\$A
524 | done
525 |
526 | case \"\$1\" in
527 | */)
528 | [[ I -ne 0 ]] && __=\"/\${T2[*]}/\" || __=/
529 | ;;
530 | *)
531 | [[ I -ne 0 ]] && __=\"/\${T2[*]}\" || __=/.
532 | ;;
533 | esac
534 | }
535 | "
536 | elif [[ $BASH_VERSION = 2.05b ]]; then
537 | eval "
538 | function loader_getabspath_ {
539 | local -a T=()
540 | local -i I=0
541 | local IFS=/ A
542 |
543 | case \"\$1\" in
544 | /*)
545 | __=\$1
546 | ;;
547 | *)
548 | __=/\$PWD/\$1
549 | ;;
550 | esac
551 |
552 | while read -r -d / A; do
553 | case \"\$A\" in
554 | ..)
555 | [[ I -ne 0 ]] && unset T\\[--I\\]
556 | continue
557 | ;;
558 | .|'')
559 | continue
560 | ;;
561 | esac
562 |
563 | T[I++]=\$A
564 | done <<< \"\$__/\"
565 |
566 | case \"\$1\" in
567 | */)
568 | [[ I -ne 0 ]] && __=\"/\${T[*]}/\" || __=/
569 | ;;
570 | *)
571 | [[ I -ne 0 ]] && __=\"/\${T[*]}\" || __=/.
572 | ;;
573 | esac
574 | }
575 | "
576 | else
577 | eval "
578 | function loader_getabspath_ {
579 | local -a T=()
580 | local -i I=0
581 | local IFS=/ A
582 |
583 | case \"\$1\" in
584 | /*)
585 | __=\$1
586 | ;;
587 | *)
588 | __=/\$PWD/\$1
589 | ;;
590 | esac
591 |
592 | while read -r -d / A; do
593 | case \"\$A\" in
594 | ..)
595 | [[ I -ne 0 ]] && unset T\\[--I\\]
596 | continue
597 | ;;
598 | .|'')
599 | continue
600 | ;;
601 | esac
602 |
603 | T[I++]=\$A
604 | done << .
605 | \$__/
606 | .
607 |
608 | case \"\$1\" in
609 | */)
610 | [[ I -ne 0 ]] && __=\"/\${T[*]}/\" || __=/
611 | ;;
612 | *)
613 | [[ I -ne 0 ]] && __=\"/\${T[*]}\" || __=/.
614 | ;;
615 | esac
616 | }
617 | "
618 | fi
619 |
620 | unset LOADER_TEST0 LOADER_TEST1 LOADER_TEST2 LOADER_USEAARRAYS
621 |
622 |
623 | # ----------------------------------------------------------------------
624 |
625 | # * Using 'set -- $VAR' to split strings inside variables will sometimes
626 | # yield different strings if one of the strings contain globs
627 | # characters like *, ? and the brackets [ and ] that are also valid
628 | # characters in filenames.
629 |
630 | # * Using 'read -a' to split strings to arrays yields elements
631 | # that contain invalid characters when a null token is found.
632 | # (bash versions < 3.0)
633 |
634 | # ----------------------------------------------------------------------
635 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/loader.ksh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ksh
2 |
3 |
4 | # ----------------------------------------------------------------------
5 |
6 | # loader.ksh
7 | #
8 | # This script implements Shell Script Loader for ksh; both the original
9 | # (KornShell 93+) and the public domain (PD KSH) Korn shell.
10 | #
11 | # Please see loader.txt for more info on how to use this script.
12 | #
13 | # This script complies with the Requiring Specifications of
14 | # Shell Script Loader version 0 (RS0)
15 | #
16 | # Version: 0.1
17 | #
18 | # Author: konsolebox
19 | # Copyright Free / Public Domain
20 | # Aug. 29, 2009 (Last Updated 2011/04/08)
21 |
22 | # Limitations of Shell Script Loader in PD KSH:
23 | #
24 | # In PD KSH (not the Ksh 93+), typeset declarations inside functions
25 | # always make variables only available within the encapsulating function
26 | # therefore scripts that have typeset declarations that are meant to
27 | # create global variables when called within a loader function like
28 | # include() will only have visibility inside include().
29 | #
30 | # Array indices in PD KSH are currently limited to the range of 0
31 | # through 1023 but this value is big enough for the list of search paths
32 | # and for the call stack.
33 |
34 | # ----------------------------------------------------------------------
35 |
36 |
37 | if [ "$LOADER_ACTIVE" = true ]; then
38 | echo "loader: loader cannot be loaded twice."
39 | exit 1
40 | fi
41 | if [ -n "$KSH_VERSION" ]; then
42 | LOADER_KSH_VERSION=1
43 | elif
44 | ( eval 'test -n "${.sh.version}" && exit 10'; ) >/dev/null 2>&1
45 | [ "$?" -eq 10 ]
46 | then
47 | LOADER_KSH_VERSION=0
48 | elif [ "$ZSH_NAME" = ksh ]; then
49 | echo "loader: emulated ksh from zsh does not work with this script."
50 | exit 1
51 | else
52 | echo "loader: ksh is needed to run this script."
53 | exit 1
54 | fi
55 |
56 |
57 | #### PUBLIC VARIABLES ####
58 |
59 | LOADER_ACTIVE=true
60 | LOADER_RS=0
61 | LOADER_VERSION=0.1
62 |
63 |
64 | #### PRIVATE VARIABLES ####
65 |
66 | set -A LOADER_CS
67 | set -A LOADER_PATHS
68 | LOADER_CS_I=0
69 |
70 |
71 | #### PUBLIC FUNCTIONS ####
72 |
73 | load() {
74 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." load
75 |
76 | case "$1" in
77 | '')
78 | loader_fail "file expression cannot be null." load "$@"
79 | ;;
80 | /*|./*|../*)
81 | if [[ -f $1 ]]; then
82 | loader_getabspath "$1"
83 |
84 | [[ -r $__ ]] || loader_fail "file not readable: $__" load "$@"
85 |
86 | shift
87 | loader_load "$@"
88 |
89 | return
90 | fi
91 | ;;
92 | *)
93 | for __ in "${LOADER_PATHS[@]}"; do
94 | [[ -f $__/$1 ]] || continue
95 |
96 | loader_getabspath "$__/$1"
97 |
98 | [[ -r $__ ]] || loader_fail "found file not readable: $__" load "$@"
99 |
100 | loader_flag_ "$1"
101 |
102 | shift
103 | loader_load "$@"
104 |
105 | return
106 | done
107 | ;;
108 | esac
109 |
110 | loader_fail "file not found: $1" load "$@"
111 | }
112 |
113 | include() {
114 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." include
115 |
116 | case "$1" in
117 | '')
118 | loader_fail "file expression cannot be null." include "$@"
119 | ;;
120 | /*|./*|../*)
121 | loader_getabspath "$1"
122 |
123 | loader_flagged "$__" && \
124 | return
125 |
126 | if [[ -f $__ ]]; then
127 | [[ -r $__ ]] || loader_fail "file not readable: $__" include "$@"
128 |
129 | shift
130 | loader_load "$@"
131 |
132 | return
133 | fi
134 | ;;
135 | *)
136 | loader_flagged "$1" && \
137 | return
138 |
139 | for __ in "${LOADER_PATHS[@]}"; do
140 | loader_getabspath "$__/$1"
141 |
142 | if loader_flagged "$__"; then
143 | loader_flag_ "$1"
144 |
145 | return
146 | elif [[ -f $__ ]]; then
147 | [[ -r $__ ]] || loader_fail "found file not readable: $__" include "$@"
148 |
149 | loader_flag_ "$1"
150 |
151 | shift
152 | loader_load "$@"
153 |
154 | return
155 | fi
156 | done
157 | ;;
158 | esac
159 |
160 | loader_fail "file not found: $1" include "$@"
161 | }
162 |
163 | call() {
164 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." call
165 |
166 | case "$1" in
167 | '')
168 | loader_fail "file expression cannot be null." call "$@"
169 | ;;
170 | /*|./*|../*)
171 | if [[ -f $1 ]]; then
172 | loader_getabspath "$1"
173 |
174 | [[ -r $__ ]] || loader_fail "file not readable: $__" call "$@"
175 |
176 | (
177 | shift
178 | loader_load "$@"
179 | )
180 |
181 | return
182 | fi
183 | ;;
184 | *)
185 | for __ in "${LOADER_PATHS[@]}"; do
186 | [[ -f $__/$1 ]] || continue
187 |
188 | loader_getabspath "$__/$1"
189 |
190 | [[ -r $__ ]] || loader_fail "found file not readable: $__" call "$@"
191 |
192 | (
193 | loader_flag_ "$1"
194 |
195 | shift
196 | loader_load "$@"
197 | )
198 |
199 | return
200 | done
201 | ;;
202 | esac
203 |
204 | loader_fail "file not found: $1" call "$@"
205 | }
206 |
207 | loader_addpath() {
208 | for __ in "$@"; do
209 | [[ -d $__ ]] || loader_fail "directory not found: $__" loader_addpath "$@"
210 | [[ -x $__ ]] || loader_fail "directory not accessible: $__" loader_addpath "$@"
211 | [[ -r $__ ]] || loader_fail "directory not searchable: $__" loader_addpath "$@"
212 | loader_getabspath_ "$__/."
213 | loader_addpath_ "$__"
214 | done
215 | }
216 |
217 | loader_flag() {
218 | [[ $# -eq 1 ]] || loader_fail "function requires a single argument." loader_flag "$@"
219 | loader_getabspath "$1"
220 | loader_flag_ "$__"
221 | }
222 |
223 | loader_reset() {
224 | if [[ $# -eq 0 ]]; then
225 | loader_resetflags
226 | loader_resetpaths
227 | elif [[ $1 = flags ]]; then
228 | loader_resetflags
229 | elif [[ $1 = paths ]]; then
230 | loader_resetpaths
231 | else
232 | loader_fail "invalid argument: $1" loader_reset "$@"
233 | fi
234 | }
235 |
236 | loader_finish() {
237 | LOADER_ACTIVE=false
238 |
239 | loader_unsetvars
240 |
241 | unset \
242 | load \
243 | include \
244 | call \
245 | loader_addpath \
246 | loader_addpath_ \
247 | loader_fail \
248 | loader_finish \
249 | loader_flag \
250 | loader_flag_ \
251 | loader_flagged \
252 | loader_getabspath \
253 | loader_getabspath_ \
254 | loader_load \
255 | loader_load_ \
256 | loader_reset \
257 | loader_unsetvars \
258 | LOADER_CS \
259 | LOADER_CS_I \
260 | LOADER_KSH_VERSION \
261 | LOADER_PATHS
262 | }
263 |
264 |
265 | #### PRIVATE FUNCTIONS ####
266 |
267 | loader_addpath_() {
268 | for __ in "${LOADER_PATHS[@]}"; do
269 | [[ $1 = $__ ]] && \
270 | return
271 | done
272 |
273 | LOADER_PATHS[${#LOADER_PATHS[@]}]=$1
274 | }
275 |
276 | loader_load() {
277 | loader_flag_ "$__"
278 |
279 | LOADER_CS[++LOADER_CS_I]=$__
280 |
281 | loader_load_ "$@"
282 |
283 | __=$?
284 |
285 | LOADER_CS[LOADER_CS_I--]=
286 |
287 | return "$__"
288 | }
289 |
290 | loader_load_() {
291 | . "$__"
292 | }
293 |
294 | loader_getabspath() {
295 | case "$1" in
296 | .|'')
297 | case "$PWD" in
298 | /)
299 | __=/.
300 | ;;
301 | *)
302 | __=${PWD%/}
303 | ;;
304 | esac
305 | ;;
306 | ..|../*|*/..|*/../*|./*|*/.|*/./*|*//*)
307 | loader_getabspath_ "$1"
308 | ;;
309 | /*)
310 | __=$1
311 | ;;
312 | *)
313 | __=${PWD%/}/$1
314 | ;;
315 | esac
316 | }
317 |
318 | loader_fail() {
319 | typeset MESSAGE FUNC A I
320 |
321 | MESSAGE=$1 FUNC=$2
322 | shift 2
323 |
324 | {
325 | echo "loader: ${FUNC}(): ${MESSAGE}"
326 | echo
327 |
328 | echo " current scope:"
329 | if [[ LOADER_CS_I -gt 0 ]]; then
330 | echo " ${LOADER_CS[LOADER_CS_I]}"
331 | else
332 | echo " (main)"
333 | fi
334 | echo
335 |
336 | if [[ $# -gt 0 ]]; then
337 | echo " command:"
338 | echo -n " $FUNC"
339 | for A; do
340 | echo -n " \"$A\""
341 | done
342 | echo
343 | echo
344 | fi
345 |
346 | if [[ LOADER_CS_I -gt 0 ]]; then
347 | echo " call stack:"
348 | echo " (main)"
349 | I=1
350 | while [[ I -le LOADER_CS_I ]]; do
351 | echo " -> ${LOADER_CS[I]}"
352 | (( ++I ))
353 | done
354 | echo
355 | fi
356 |
357 | echo " search paths:"
358 | if [[ ${#LOADER_PATHS[@]} -gt 0 ]]; then
359 | for A in "${LOADER_PATHS[@]}"; do
360 | echo " $A"
361 | done
362 | else
363 | echo " (empty)"
364 | fi
365 | echo
366 |
367 | echo " working directory:"
368 | echo " $PWD"
369 | echo
370 | } >&2
371 |
372 | exit 1
373 | }
374 |
375 |
376 | #### VERSION DEPENDENT FUNCTIONS AND VARIABLES ####
377 |
378 | if [[ $LOADER_KSH_VERSION = 0 ]]; then
379 | eval "
380 | LOADER_FLAGS=([.]=.)
381 | LOADER_PATHS_FLAGS=([.]=.)
382 |
383 | loader_addpath_() {
384 | if [[ -z \${LOADER_PATHS_FLAGS[\$1]} ]]; then
385 | LOADER_PATHS[\${#LOADER_PATHS[@]}]=\$1
386 | LOADER_PATHS_FLAGS[\$1]=.
387 | fi
388 | }
389 |
390 | loader_flag_() {
391 | LOADER_FLAGS[\$1]=.
392 | }
393 |
394 | loader_flagged() {
395 | [[ -n \${LOADER_FLAGS[\$1]} ]]
396 | }
397 |
398 | loader_resetflags() {
399 | LOADER_FLAGS=()
400 | }
401 |
402 | loader_resetpaths() {
403 | set -A LOADER_PATHS
404 | LOADER_PATHS_FLAGS=()
405 | }
406 |
407 | loader_unsetvars() {
408 | unset LOADER_FLAGS LOADER_PATHS_FLAGS
409 | }
410 | "
411 |
412 | if
413 | eval "
414 | __=.
415 | read __ <<< \"\$__\"
416 | [[ \$__ = '\".\"' ]]
417 | "
418 | then
419 | eval "
420 | function loader_getabspath_ {
421 | typeset T1 T2
422 | typeset -i I=0
423 | typeset IFS=/ A
424 |
425 | case \"\$1\" in
426 | /*)
427 | read -r -A T1 <<< \$1
428 | ;;
429 | *)
430 | read -r -A T1 <<< \$PWD/\$1
431 | ;;
432 | esac
433 |
434 | set -A T2
435 |
436 | for A in \"\${T1[@]}\"; do
437 | case \"\$A\" in
438 | ..)
439 | [[ I -ne 0 ]] && unset T2\\[--I\\]
440 | continue
441 | ;;
442 | .|'')
443 | continue
444 | ;;
445 | esac
446 |
447 | T2[I++]=\$A
448 | done
449 |
450 | case \"\$1\" in
451 | */)
452 | [[ I -ne 0 ]] && __=\"/\${T2[*]}/\" || __=/
453 | ;;
454 | *)
455 | [[ I -ne 0 ]] && __=\"/\${T2[*]}\" || __=/.
456 | ;;
457 | esac
458 | }
459 | "
460 | else
461 | eval "
462 | function loader_getabspath_ {
463 | typeset T1 T2
464 | typeset -i I=0
465 | typeset IFS=/ A
466 |
467 | case \"\$1\" in
468 | /*)
469 | read -r -A T1 <<< \"\$1\"
470 | ;;
471 | *)
472 | read -r -A T1 <<< \"\$PWD/\$1\"
473 | ;;
474 | esac
475 |
476 | set -A T2
477 |
478 | for A in \"\${T1[@]}\"; do
479 | case \"\$A\" in
480 | ..)
481 | [[ I -ne 0 ]] && unset T2\\[--I\\]
482 | continue
483 | ;;
484 | .|'')
485 | continue
486 | ;;
487 | esac
488 |
489 | T2[I++]=\$A
490 | done
491 |
492 | case \"\$1\" in
493 | */)
494 | [[ I -ne 0 ]] && __=\"/\${T2[*]}/\" || __=/
495 | ;;
496 | *)
497 | [[ I -ne 0 ]] && __=\"/\${T2[*]}\" || __=/.
498 | ;;
499 | esac
500 | }
501 | "
502 | fi
503 | else
504 | loader_addpath_() {
505 | for __ in "${LOADER_PATHS[@]}"; do
506 | [[ $1 = "$__" ]] && \
507 | return
508 | done
509 |
510 | LOADER_PATHS[${#LOADER_PATHS[@]}]=$1
511 | }
512 |
513 | loader_flag_() {
514 | eval "LOADER_FLAGS_$(echo "$1" | sed 's/\./_dt_/g; s/\//_sl_/g; s/ /_sp_/g; s/[^[:alnum:]_]/_ot_/g')=."
515 | }
516 |
517 | loader_flagged() {
518 | eval "[[ -n \$LOADER_FLAGS_$(echo "$1" | sed 's/\./_dt_/g; s/\//_sl_/g; s/ /_sp_/g; s/[^[:alnum:]_]/_ot_/g') ]]"
519 | }
520 |
521 | loader_getabspath_() {
522 | typeset A T IFS=/ TOKENS I=0 J=0
523 |
524 | A=${1%/}
525 |
526 | if [[ -n $A ]]; then
527 | while :; do
528 | T=${A%%/*}
529 |
530 | case "$T" in
531 | ..)
532 | if [[ I -gt 0 ]]; then
533 | unset TOKENS\[--I\]
534 | else
535 | (( ++J ))
536 | fi
537 | ;;
538 | .|'')
539 | ;;
540 | *)
541 | TOKENS[I++]=$T
542 | ;;
543 | esac
544 |
545 | case "$A" in
546 | */*)
547 | A=${A#*/}
548 | ;;
549 | *)
550 | break
551 | ;;
552 | esac
553 | done
554 | fi
555 |
556 | __="/${TOKENS[*]}"
557 |
558 | if [[ $1 != /* ]]; then
559 | A=${PWD%/}
560 |
561 | while [[ J -gt 0 && -n $A ]]; do
562 | A=${A%/*}
563 | (( --J ))
564 | done
565 |
566 | [[ -n $A ]] && __=$A${__%/}
567 | fi
568 |
569 | if [[ $__ = / ]]; then
570 | [[ $1 != */ ]] && __=/.
571 | elif [[ $1 == */ ]]; then
572 | __=$__/
573 | fi
574 | }
575 |
576 | loader_resetflags() {
577 | unset $(set | grep -a ^LOADER_FLAGS_ | cut -f 1 -d =)
578 | }
579 |
580 | loader_resetpaths() {
581 | set -A LOADER_PATHS
582 | }
583 |
584 | loader_unsetvars() {
585 | loader_resetflags
586 | }
587 | fi
588 |
589 |
590 | # ----------------------------------------------------------------------
591 |
592 | # * In some if not all versions of ksh, "${@:X[:Y]}" always presents a
593 | # single null string if no positional parameter is matched.
594 | #
595 | # * In some versions of ksh, 'read <<< "$VAR"' includes '"' in the
596 | # string.
597 | #
598 | # * Using 'set -- $VAR' to split strings inside variables will sometimes
599 | # yield different strings if one of the strings contain globs
600 | # characters like *, ? and the brackets [ and ] that are also valid
601 | # characters in filenames.
602 | #
603 | # * Changing the IFS causes buggy behaviors in PD KSH.
604 |
605 | # ----------------------------------------------------------------------
606 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/loader.txt:
--------------------------------------------------------------------------------
1 | Shell Script Loader
2 | -------------------
3 |
4 | Preamble
5 |
6 | This document describes Shell Script Loader and its usage. It also
7 | serves as a co-describer for the Requiring Specifications of
8 | Shell Script Loader version 0 (RS0).
9 |
10 |
11 | Document Version
12 |
13 | 0.1
14 |
15 |
16 | Definitions
17 |
18 | shell script - a script that is acknowledged by the shell.
19 |
20 | co-shell-script - a shell script that is called by and works with
21 | another another shell script.
22 |
23 | complete path - refers to a path that clearly points to a file. A
24 | path that begins with /, ./ or ../ is considered as
25 | complete.
26 |
27 | partial path - refers to a path that implies a need for a prefix to
28 | make itself complete. A path that doesn't begin with
29 | /, ./, and ../ is considered as partial.
30 |
31 | absolute path - refers to a path that begins with /.
32 |
33 | clean absolute - refers to an absolute path that does not contain /./
34 | or /../ in between.
35 |
36 | relative path - refers to a path that does not begin with /.
37 |
38 | flagged - a path to a file that is flagged is considered as
39 | already included. If a second attempt to load the
40 | file is made using the function include(), the file
41 | will just be ignored.
42 |
43 |
44 | What is Shell Script Loader?
45 |
46 | Shell Script Loader is a framework (in a helper script) that can be used
47 | by shell script based applications for easy loading of co-shell-scripts
48 | or subscripts. Using this utility a scripter can now be able to apply
49 | multi-file or module-oriented scripting or programming in shells just
50 | like the way they are always done in known languages like Perl, PHP and
51 | Ruby. There are many benefits with using module-oriented programming
52 | just like code sharing, portability, modularity, easy revisioning, easy
53 | restructuring, and reusability.
54 |
55 | The helper functions that the framework provides include load(),
56 | include(), call(), loader_addpath(), loader_flag(), loader_reset(), and
57 | loader_finish(). Among the said functions, load(), include() and call()
58 | are the ones that can be used to manipulate co-shell-scripts.
59 |
60 |
61 | Design
62 |
63 | Shell Script Loader has been carefully designed for stability, speed and
64 | efficiency with minimum sacrifice in readability of code's logic.
65 | Uniform coding style and structure also is very strict.
66 |
67 |
68 | Shell-Dependent Limitations
69 |
70 | Since co-shell-scripts are loaded through functions, variables inside
71 | co-shell-scripts are treated as if they were declared inside funtions.
72 | If a shell script requires a variable to be global, the scripter should
73 | consider how the shell creates variables inside functions without
74 | giving it a visibility or scope that is only local to the function.
75 |
76 | Some shells like Zsh (using "typeset -g"), Bash (using "declare -g" in
77 | versions 4.2 and newer) and Ksh (functions not declared with the
78 | "function" keyword) have full support for creating global variables
79 | inside functions. As of this writing, global variables in bash are
80 | declared global by default only when using the simple declaration syntax
81 | but some variables like associative (not indexed) array variables that
82 | can only be created using the 'declare' builtin are always local if
83 | declared inside a function.
84 |
85 | Note: These limitations should not be applicable if you only intend to
86 | run the application in compiled form and not from the source scripts.
87 |
88 |
89 | Choosing a Shell Script Loader script
90 |
91 | Before it was recommended to always use the right implementation script
92 | for the shell for the sake of speed but it's now optional since the
93 | current implementation scripts are now capable of selecting optimized
94 | and/or proper functions for the running shell.
95 |
96 | For example, with loader.bash, associative arrays are automatically used
97 | if they can be used. Even with the generic script loader.sh, speed with
98 | the specialized versions does not really differ anymore.
99 |
100 | Please see the header notes of the implementation scripts to know what
101 | shells they support. You can also just use loader.sh to have
102 | compatibility with all shells that are compatible with the original sh
103 | with very little overhead.
104 |
105 |
106 | Loading the Script
107 |
108 | Implementation scripts of Shell Script Loader can be loaded just like
109 | any other shell script. In most shells, this can be done using '.' or
110 | 'source' targetting the implementation file.
111 |
112 | Also, arguments passed to an implementation script are not used and
113 | safely ignored but take note that these argument may replace the
114 | positional parameters.
115 |
116 |
117 | Functions
118 |
119 | (a) load() - Unconditionally loads a file even though it has already
120 | been flagged.
121 |
122 | usage: load
123 | load
124 |
125 | (b) include() - Also loads and flags a file like load() but only if the
126 | file has not yet been loaded with any of the three
127 | loading functions or flagged.
128 |
129 | usage: include
130 | include
131 |
132 | (c) call() - This function acts the same as load() but it loads the
133 | file in a separated environment or subshell. This is
134 | useful if a user wants to make a co-shell-script do its
135 | job without affecting the environment of the caller.
136 | The function also returns the exit code of the subshell
137 | after the subshell finishes executing.
138 |
139 | usage: call
140 | call
141 |
142 | (d) loader_addpath() - Accepts one or more arguments of directory paths
143 | and adds them to the list of searchable
144 | directories that will be used by load(),
145 | include() and call() when searching for files
146 | that are specified through partial paths.
147 |
148 | (e) loader_flag() - Marks the specified path to a file as if it's
149 | already been loaded with load(), include() or
150 | call(). Note that the file referred by path does
151 | not need to exist.
152 |
153 | This function is mostly useful like when you want
154 | to mark a loaded script that has not been loaded
155 | by any of the loading functions like the startup
156 | or main script that loads the implementation
157 | script.
158 |
159 | This function can accept any form of path (may it
160 | be absolute or relative) but note that the
161 | function always convert a path to its clean
162 | absolute form.
163 |
164 | usage: loader_flag
165 |
166 | (f) loader_reset() - This function behaves depending on the argument
167 | that is passed to it.
168 |
169 | usage: loader_reset []
170 |
171 | flags - function will clear the flags
172 | paths - function will the list of search paths
173 |
174 | If no argument is passed, function will act on
175 | both items. If an unknown argument was passed,
176 | the function will generate a failure with an
177 | optional error message.
178 |
179 | (g) loader_finish() - Use this function to unload Shell Script Loader
180 | from shellspace. Everything except the variables
181 | LOADER_VERSION, LOADER_RS and LOADER_ACTIVE will
182 | be removed.
183 |
184 | Note: In the functions load() and include(), the co-shell-script is
185 | loaded inside the the same environment of the script along with the
186 | calling script's environment therefore if arguments are passed to the
187 | script upon load, replacement of the positional parameters with the
188 | arguments is expected.
189 |
190 |
191 | Reference Variables
192 |
193 | User scripts can also refer to some of the variables that an
194 | implementation script shall provide during load. This information can
195 | be used to check for compatibilies and to check if Shell Script Loader
196 | is still running or not. These variables will remain in shellspace even
197 | if loader_finish() was already called.
198 |
199 | (a) LOADER_VERSION - Refers to the version of the implementation script.
200 |
201 | (b) LOADER_RS - Refers to the version of Requiring Specification (RS)
202 | that is being implemented by the script.
203 |
204 | (c) LOADER_ACTIVE - This is set to 'true' if Shell Script Loader is
205 | already loaded and is still active (not yet removed
206 | with loader_finish()). The variable should be unset
207 | if Shell Script Loader was not yet loaded and set to
208 | 'false' if it is no longer active.
209 |
210 |
211 | Compilers
212 |
213 | Shell Script Loader was also designed so that the scripts that were
214 | created based from it can also be compiled to form a single script.
215 |
216 | As of this writing, a working compiler is already available. You can
217 | check the site where this program originally came for available
218 | compilers.
219 |
220 |
221 | Examples
222 |
223 | > . loader.sh
224 | > source ./loader.bash
225 | > source /usr/share/shellscript-loader/loader.zsh
226 |
227 | > loader_flag start.sh
228 | > loader_flag "${BASH_SOURCE[0]}"
229 |
230 | > loader_addpath source
231 | > loader_addpath /usr/share/scripts/sh
232 |
233 | > load main.sh
234 | > load some/reloadable.sh
235 | > include commands.sh
236 | > include utils/parawrap.sh
237 | > call checkconnection.sh && connected=true
238 | > call tools/strip.sh a.txt b.txt
239 |
240 | > loader_finish
241 |
242 |
243 | Prepared by konsolebox
244 | Copyright Free / Public Domain
245 | Aug. 29, 2009 (Last Updated 2011/04/07)
246 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/loader.zsh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env zsh
2 |
3 |
4 | # ----------------------------------------------------------------------
5 |
6 | # loader.zsh
7 | #
8 | # This script implements Shell Script Loader for all versions of Zsh
9 | # starting 4.2.
10 | #
11 | # Please see loader.txt for more info on how to use this script.
12 | #
13 | # This script complies with the Requiring Specifications of
14 | # Shell Script Loader version 0 (RS0)
15 | #
16 | # Version: 0.1
17 | #
18 | # Author: konsolebox
19 | # Copyright Free / Public Domain
20 | # Aug. 29, 2009 (Last Updated 2011/04/07)
21 |
22 | # Notes:
23 | #
24 | # When using "typeset" or "declare" to declare global variables in
25 | # scripts, always add '-g' as an option. Not adding this option will
26 | # make the variables only have a local scope inside any of the functions
27 | # here that will be used to load the script. Among the major known
28 | # shells, only Zsh and Bash (ver. 4.2+) are the only shells that are
29 | # capable of having this explicit feature (as of this writing). There
30 | # are also other ways to declare global variables in other shells but
31 | # not through the use of "typeset" or "declare". Variables that can
32 | # only be declared using the two builtin commands sometimes can never be
33 | # declared global unless declared outside any function or the main
34 | # scope.
35 | #
36 | # This implementation script for Zsh actually is also tested to be
37 | # functionally compatible with versions 4.0.* and 4.1.* but these
38 | # earlier versions of Zsh have limited execution stack (job tables) that
39 | # are sometimes configured by default at small sizes and are also not
40 | # expandable unlike in 4.2.* and newer so I thought that it's better to
41 | # exclude these versions just to keep integrity.
42 | #
43 | # If you know what you're doing you may change the conditional
44 | # expression below to something like '[ ! "${ZSH_VERSION%%.*}" -ge 4 ]'.
45 | # You may want to do this for example, if you want your scripts to be
46 | # more compatible with most versions of Zsh and if you're sure that your
47 | # scripts doesn't make too much recursions in which even the earlier
48 | # versions will be able to handle. You may verify this by testing your
49 | # scripts with the earlier versions of Zsh that is configured to have
50 | # its limit set to minimum (see MAXJOB in zshconfig.ac). If you don't
51 | # find an error message like "job table full or recursion limit
52 | # exceeded", then as with respect to this issue, your scripts should
53 | # probably run just fine.
54 |
55 | # ----------------------------------------------------------------------
56 |
57 |
58 | if [ "$LOADER_ACTIVE" = true ]; then
59 | echo "loader: loader cannot be loaded twice."
60 | exit 1
61 | fi
62 | if [ -z "$ZSH_VERSION" ]; then
63 | echo "loader: zsh is needed to run this script."
64 | exit 1
65 | fi
66 | if ! ( eval "set -- ${ZSH_VERSION//./ }"; [ "$1" -gt 4 ] || [ "$1" -eq 4 -a "$2" -ge 2 ]; exit "$?"; ); then
67 | echo "loader: only versions of zsh not earlier than 4.2.0 can work properly with this script."
68 | exit 1
69 | fi
70 | if [ "$ZSH_NAME" = sh -o "$ZSH_NAME" = ksh ]; then
71 | echo "loader: this script doesn't work if zsh is running in sh or ksh emulation mode."
72 | exit 1
73 | fi
74 |
75 |
76 | #### PUBLIC VARIABLES ####
77 |
78 | typeset -g LOADER_ACTIVE=true
79 | typeset -g LOADER_VERSION=0.1
80 | typeset -g LOADER_RS=0
81 |
82 |
83 | #### PRIVATE VARIABLES ####
84 |
85 | typeset -g -a LOADER_CS
86 | typeset -g -i LOADER_CS_I=0
87 | typeset -g -A LOADER_FLAGS
88 | typeset -g -a LOADER_PATHS
89 | typeset -g -A LOADER_PATHS_FLAGS
90 |
91 |
92 | #### PUBLIC FUNCTIONS ####
93 |
94 | function load {
95 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." load
96 |
97 | case "$1" in
98 | '')
99 | loader_fail "file expression cannot be null." load "$@"
100 | ;;
101 | /*|./*|../*)
102 | if [[ -f $1 ]]; then
103 | loader_getabspath "$1"
104 |
105 | [[ -r $__ ]] || loader_fail "file not readable: $__" load "$@"
106 |
107 | shift
108 | loader_load "$@"
109 |
110 | return
111 | fi
112 | ;;
113 | *)
114 | for __ in "${LOADER_PATHS[@]}"; do
115 | [[ -f $__/$1 ]] || continue
116 |
117 | loader_getabspath "$__/$1"
118 |
119 | [[ -r $__ ]] || loader_fail "found file not readable: $__" load "$@"
120 |
121 | LOADER_FLAGS[$1]=.
122 |
123 | shift
124 | loader_load "$@"
125 |
126 | return
127 | done
128 | ;;
129 | esac
130 |
131 | loader_fail "file not found: $1" load "$@"
132 | }
133 |
134 | function include {
135 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." include
136 |
137 | case "$1" in
138 | '')
139 | loader_fail "file expression cannot be null." include "$@"
140 | ;;
141 | /*|./*|../*)
142 | loader_getabspath "$1"
143 |
144 | [[ -n ${LOADER_FLAGS[$__]} ]] && \
145 | return
146 |
147 | if [[ -f $__ ]]; then
148 | [[ -r $__ ]] || loader_fail "file not readable: $__" include "$@"
149 |
150 | shift
151 | loader_load "$@"
152 |
153 | return
154 | fi
155 | ;;
156 | *)
157 | [[ -n ${LOADER_FLAGS[$1]} ]] && \
158 | return
159 |
160 | for __ in "${LOADER_PATHS[@]}"; do
161 | loader_getabspath "$__/$1"
162 |
163 | if [[ -n ${LOADER_FLAGS[$__]} ]]; then
164 | LOADER_FLAGS[$1]=.
165 |
166 | return
167 | elif [[ -f $__ ]]; then
168 | [[ -r $__ ]] || loader_fail "found file not readable: $__" include "$@"
169 |
170 | LOADER_FLAGS[$1]=.
171 |
172 | shift
173 | loader_load "$@"
174 |
175 | return
176 | fi
177 | done
178 | ;;
179 | esac
180 |
181 | loader_fail "file not found: $1" include "$@"
182 | }
183 |
184 | function call {
185 | [[ $# -eq 0 ]] && loader_fail "function called with no argument." call
186 |
187 | case "$1" in
188 | '')
189 | loader_fail "file expression cannot be null." call "$@"
190 | ;;
191 | /*|./*|../*)
192 | if [[ -f $1 ]]; then
193 | loader_getabspath "$1"
194 |
195 | [[ -r $__ ]] || loader_fail "file not readable: $__" call "$@"
196 |
197 | (
198 | shift
199 | loader_load "$@"
200 | )
201 |
202 | return
203 | fi
204 | ;;
205 | *)
206 | for __ in "${LOADER_PATHS[@]}"; do
207 | [[ -f $__/$1 ]] || continue
208 |
209 | loader_getabspath "$__/$1"
210 |
211 | [[ -r $__ ]] || loader_fail "found file not readable: $__" call "$@"
212 |
213 | (
214 | LOADER_FLAGS[$1]=.
215 |
216 | shift
217 | loader_load "$@"
218 | )
219 |
220 | return
221 | done
222 | ;;
223 | esac
224 |
225 | loader_fail "file not found: $1" call "$@"
226 | }
227 |
228 | function loader_addpath {
229 | for __ in "$@"; do
230 | [[ -d $__ ]] || loader_fail "directory not found: $__" loader_addpath "$@"
231 | [[ -x $__ ]] || loader_fail "directory not accessible: $__" loader_addpath "$@"
232 | [[ -r $__ ]] || loader_fail "directory not searchable: $__" loader_addpath "$@"
233 |
234 | loader_getabspath_ "$__/."
235 |
236 | if [[ -z ${LOADER_PATHS_FLAGS[$__]} ]]; then
237 | LOADER_PATHS[${#LOADER_PATHS[@]}+1]=$__
238 | LOADER_PATHS_FLAGS[$__]=.
239 | fi
240 | done
241 | }
242 |
243 | function loader_flag {
244 | [[ $# -eq 1 ]] || loader_fail "function requires a single argument." loader_flag "$@"
245 | loader_getabspath "$1"
246 | LOADER_FLAGS[$__]=.
247 | }
248 |
249 | function loader_reset {
250 | if [[ $# -eq 0 ]]; then
251 | set -A LOADER_FLAGS
252 | set -A LOADER_PATHS
253 | set -A LOADER_PATHS_FLAGS
254 | elif [[ $1 = flags ]]; then
255 | set -A LOADER_FLAGS
256 | elif [[ $1 = paths ]]; then
257 | set -A LOADER_PATHS
258 | set -A LOADER_PATHS_FLAGS
259 | else
260 | loader_fail "invalid argument: $1" loader_reset "$@"
261 | fi
262 | }
263 |
264 | function loader_finish {
265 | LOADER_ACTIVE=false
266 |
267 | unset \
268 | load \
269 | include \
270 | call \
271 | loader_addpath \
272 | loader_fail \
273 | loader_finish \
274 | loader_flag \
275 | loader_getabspath \
276 | loader_getabspath_ \
277 | loader_load \
278 | loader_load_ \
279 | loader_reset \
280 | LOADER_CS \
281 | LOADER_CS_I \
282 | LOADER_FLAGS \
283 | LOADER_PATHS \
284 | LOADER_PATHS_FLAGS
285 | }
286 |
287 |
288 | #### PRIVATE FUNCTIONS ####
289 |
290 | function loader_load {
291 | LOADER_FLAGS[$__]=.
292 |
293 | LOADER_CS[++LOADER_CS_I]=$__
294 |
295 | loader_load_ "$@"
296 |
297 | __=$?
298 | LOADER_CS[LOADER_CS_I--]=()
299 | return "$__"
300 | }
301 |
302 | function loader_load_ {
303 | . "$__"
304 | }
305 |
306 | function loader_getabspath {
307 | case "$1" in
308 | .|'')
309 | case "$PWD" in
310 | /)
311 | __=/.
312 | ;;
313 | *)
314 | __=${PWD%/}
315 | ;;
316 | esac
317 | ;;
318 | ..|../*|*/..|*/../*|./*|*/.|*/./*|*//*)
319 | loader_getabspath_ "$1"
320 | ;;
321 | /*)
322 | __=$1
323 | ;;
324 | *)
325 | __=${PWD%/}/$1
326 | ;;
327 | esac
328 | }
329 |
330 | function loader_getabspath_ {
331 | local -a TOKENS; set -A TOKENS
332 | local -i I=0
333 | local IFS=/ T
334 |
335 | __=$1
336 |
337 | case "$1" in
338 | /*)
339 | set -- ${=1}
340 | ;;
341 | *)
342 | set -- ${=PWD} ${=1}
343 | ;;
344 | esac
345 |
346 | for T; do
347 | case "$T" in
348 | ..)
349 | [[ I -ne 0 ]] && TOKENS[I--]=()
350 | continue
351 | ;;
352 | .|'')
353 | continue
354 | ;;
355 | esac
356 |
357 | TOKENS[++I]=$T
358 | done
359 |
360 | case "$__" in
361 | */)
362 | [[ I -ne 0 ]] && __="/${TOKENS[*]}/" || __=/
363 | ;;
364 | *)
365 | [[ I -ne 0 ]] && __="/${TOKENS[*]}" || __=/.
366 | ;;
367 | esac
368 | }
369 |
370 | function loader_fail {
371 | local MESSAGE=$1 FUNC=$2 A I
372 | shift 2
373 |
374 | {
375 | echo "loader: ${FUNC}(): ${MESSAGE}"
376 | echo
377 |
378 | echo " current scope:"
379 | if [[ LOADER_CS_I -gt 0 ]]; then
380 | echo " ${LOADER_CS[LOADER_CS_I]}"
381 | else
382 | echo " (main)"
383 | fi
384 | echo
385 |
386 | if [[ $# -gt 0 ]]; then
387 | echo " command:"
388 | echo -n " $FUNC"
389 | for A; do
390 | echo -n " $A"
391 | done
392 | echo
393 | echo
394 | fi
395 |
396 | if [[ LOADER_CS_I -gt 0 ]]; then
397 | echo " call stack:"
398 | echo " (main)"
399 | for A in "${LOADER_CS[@]}"; do
400 | echo " -> $A"
401 | done
402 | echo
403 | fi
404 |
405 | echo " search paths:"
406 | if [[ ${#LOADER_PATHS[@]} -gt 0 ]]; then
407 | for A in "${LOADER_PATHS[@]}"; do
408 | echo " $A"
409 | done
410 | else
411 | echo " (empty)"
412 | fi
413 | echo
414 |
415 | echo " working directory:"
416 | echo " $PWD"
417 | echo
418 | } >&2
419 |
420 | exit 1
421 | }
422 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/module.txt:
--------------------------------------------------------------------------------
1 | Some Benefits of Module Oriented Scripting
2 | ------------------------------------------
3 |
4 | Early ancestors of Loader were originally only meant to
5 | make modularization possible in shell scripts through a
6 | custom function named use(); that which is now named
7 | include(). The purpose was to make shellscripts easier
8 | to handle and more arranged.
9 |
10 | When modularization was made possible, coding truly
11 | became a lot easier. Co-shellscripts became a lot easier
12 | to add and remove, dependencies are no longer difficult
13 | to handle, and more importantly, common codes became
14 | shared and no longer have to be repeated in many parts of
15 | the whole code and in future applications that might try
16 | to reuse it.
17 |
18 | In a shared code, bugs related to that code can be easily
19 | fixed in one shot unlike when its not shared where all of
20 | its instances should be located, analyzed and fixed at
21 | the same time.
22 |
23 | As for multi-scripts, they no longer appear confusing as
24 | to deciding which subscript has to be loaded first. The
25 | subscripts can also be dynamically (re)located anywhere
26 | in the filesystem. The main script no longer has to be
27 | updated everytime a new subscript is added. It can call
28 | for its dependencies just like other scripts and may only
29 | specify its direct dependencies and no longer the
30 | indirect ones. If all of the subscripts properly specify
31 | their dependencies, the requiring script no longer has to
32 | call them in proper order.
33 |
34 | On a properly crafted set of modularized scripts, the
35 | developer should easily recognize how the whole code
36 | works by just looking at its main code. Also, as related
37 | to bugs and features of a module script, a developer can
38 | easily fix or improve those without needing to touch the
39 | other scripts that depends on the script.
40 |
41 | konsolebox, 2009-08-29
42 |
--------------------------------------------------------------------------------
/contrib/shellscriptloader-0.1.1/version.txt:
--------------------------------------------------------------------------------
1 | 0.1.1
--------------------------------------------------------------------------------
/packages/nvidia/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/packages/nvidia/Makefile:
--------------------------------------------------------------------------------
1 | PREFIX ?= /usr/local
2 | BINPREFIX ?= $(PREFIX)/bin
3 | BUILDDIR ?= build
4 |
5 | CSCRIPT := ../../compile.sh
6 | CFLAGS += -O -a /home/jaagr/.local/lib/sh -s "'/usr/bin/env bash'"
7 |
8 | all: build
9 |
10 | build:
11 | mkdir -p -v $(BUILDDIR)
12 | for f in gpu-*; do \
13 | $(CSCRIPT) $$f $(BUILDDIR)/$$f $(CFLAGS) ; \
14 | done
15 |
16 | install:
17 | for f in gpu-*; do \
18 | install -Dvm755 $(BUILDDIR)/$$f $(DESTDIR)$(BINPREFIX)/$$f ; \
19 | done
20 |
21 | uninstall:
22 | for f in gpu-*; do \
23 | rm -vf $(DESTDIR)$(BINPREFIX)/$$f ; \
24 | done
25 |
26 | clean:
27 | rm -rf build
28 |
29 | .PHONY: build install uninstall clean
30 |
31 | # vim:ts=2 sw=2 noet nolist
32 |
--------------------------------------------------------------------------------
/packages/nvidia/gpu-change:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/log.sh
6 | include utils/log/defer.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | local to_state
13 |
14 | if [[ "$1" == "on" ]]; then
15 | to_state=1
16 | elif [[ "$1" == "off" ]]; then
17 | to_state=0
18 | else
19 | log::err "Usage: ${0##*/} on|off"; exit 125
20 | fi
21 |
22 | if gpu-state; then
23 | if [[ $to_state -eq 1 ]]; then
24 | log::info "GPU state already ON..." ; exit 0
25 | fi
26 | elif [[ $to_state -eq 0 ]]; then
27 | log::info "GPU state already OFF..." ; exit 0
28 | fi
29 |
30 | if [[ $to_state -eq 1 ]]; then
31 | log::defer "Loading kernel modules..."
32 | err=$(sudo modprobe -a nvidia 2>&1 >/dev/null)
33 | lsmod | grep -q nvidia || {
34 | log::defer::failure "" "$err" ; exit 1
35 | }
36 | elif [[ $to_state -eq 0 ]]; then
37 | log::defer "Unloading kernel modules..."
38 | err=$(sudo modprobe -r nvidia 2>&1 >/dev/null)
39 | lsmod | grep -q nvidia && {
40 | log::defer::failure "" "$err" ; exit 1
41 | }
42 |
43 | log::defer "Sending new state to bbswitch..."
44 | sudo tee /proc/acpi/bbswitch <<< "OFF" >/dev/null
45 | fi
46 |
47 | log::defer "Verifying new GPU state..."
48 |
49 | if gpu-state; then
50 | if [[ $to_state -eq 1 ]]; then
51 | log::defer::success
52 | else
53 | log::defer::failure
54 | fi
55 | elif [[ $to_state -eq 0 ]]; then
56 | log::defer::success
57 | else
58 | log::defer::failure
59 | fi
60 | }
61 |
62 | main "$@"
63 |
--------------------------------------------------------------------------------
/packages/nvidia/gpu-run:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/log.sh
6 | include utils/log/defer.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | if [[ $# -lt 1 ]]; then
13 | log::err "Usage: ${0##*/} command"; exit 125
14 | fi
15 |
16 | log::info "Activating the GPU..."
17 | gpu-change on || exit 1
18 |
19 | trap 'gpu-state && { log::info "Deactivating the GPU..."; gpu-change off; }' 0 INT TERM
20 |
21 | log::info "Executing 'optirun $*'"
22 | optirun "$@" 2>&1 | while read -r line; do
23 | [[ "$line" ]] && log " $line"
24 | done
25 | }
26 |
27 | main "$@"
28 |
--------------------------------------------------------------------------------
/packages/nvidia/gpu-state:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/log.sh
6 | include utils/log/defer.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | local gpu_loaded='true'
13 |
14 | lsmod | grep -q nvidia || exit 1
15 |
16 | bbswitch_status=$(&1 | grep -q 'direct rendering: Yes'; then
21 | log::defer::failure ; exit
22 | fi
23 | }
24 |
25 | main "$@"
26 |
--------------------------------------------------------------------------------
/packages/sonybravia/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/packages/sonybravia/Makefile:
--------------------------------------------------------------------------------
1 | PREFIX ?= /usr/local
2 | BINPREFIX ?= $(PREFIX)/bin
3 | SHRPREFIX ?= $(PREFIX)/share/sonybravia
4 | BUILDDIR ?= build
5 |
6 | CSCRIPT := ../../compile.sh
7 | CFLAGS += -O -a /home/jaagr/.local/lib/sh -s "'/usr/bin/env bash'"
8 |
9 | all: build
10 |
11 | build:
12 | mkdir -p -v $(BUILDDIR)
13 | for f in sonybravia-*; do \
14 | cat $$f | sed '/#/!q' | tail -n+2 > $(BUILDDIR)/$$f.header ; \
15 | $(CSCRIPT) $$f $(BUILDDIR)/$$f -H $(BUILDDIR)/$$f.header $(CFLAGS) ; \
16 | done
17 | sed -i "s|commands.json|$(DESTDIR)$(SHRPREFIX)/commands.json|g" $(BUILDDIR)/sonybravia-ctl
18 |
19 | install:
20 | for f in sonybravia-*; do \
21 | install -Dvm755 $(BUILDDIR)/$$f $(DESTDIR)$(BINPREFIX)/$$f ; \
22 | done
23 | install -Dm755 commands.json $(DESTDIR)$(SHRPREFIX)/commands.json
24 |
25 | uninstall:
26 | for f in sonybravia-*; do \
27 | rm -vf $(DESTDIR)$(BINPREFIX)/$$f ; \
28 | done
29 | rm -vf $(DESTDIR)$(SHRPREFIX)/commands.json
30 |
31 | clean:
32 | rm -rf build
33 |
34 | .PHONY: build install uninstall clean
35 |
36 | # vim:ts=2 sw=2 noet nolist
37 |
--------------------------------------------------------------------------------
/packages/sonybravia/commands.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 10,
3 | "result": [
4 | {
5 | "bundled": true,
6 | "type": "RM-J1100"
7 | },
8 | [
9 | {
10 | "name": "PowerOff",
11 | "value": "AAAAAQAAAAEAAAAvAw=="
12 | },
13 | {
14 | "name": "Input",
15 | "value": "AAAAAQAAAAEAAAAlAw=="
16 | },
17 | {
18 | "name": "GGuide",
19 | "value": "AAAAAQAAAAEAAAAOAw=="
20 | },
21 | {
22 | "name": "EPG",
23 | "value": "AAAAAgAAAKQAAABbAw=="
24 | },
25 | {
26 | "name": "Favorites",
27 | "value": "AAAAAgAAAHcAAAB2Aw=="
28 | },
29 | {
30 | "name": "Display",
31 | "value": "AAAAAQAAAAEAAAA6Aw=="
32 | },
33 | {
34 | "name": "Home",
35 | "value": "AAAAAQAAAAEAAABgAw=="
36 | },
37 | {
38 | "name": "Options",
39 | "value": "AAAAAgAAAJcAAAA2Aw=="
40 | },
41 | {
42 | "name": "Return",
43 | "value": "AAAAAgAAAJcAAAAjAw=="
44 | },
45 | {
46 | "name": "Up",
47 | "value": "AAAAAQAAAAEAAAB0Aw=="
48 | },
49 | {
50 | "name": "Down",
51 | "value": "AAAAAQAAAAEAAAB1Aw=="
52 | },
53 | {
54 | "name": "Right",
55 | "value": "AAAAAQAAAAEAAAAzAw=="
56 | },
57 | {
58 | "name": "Left",
59 | "value": "AAAAAQAAAAEAAAA0Aw=="
60 | },
61 | {
62 | "name": "Confirm",
63 | "value": "AAAAAQAAAAEAAABlAw=="
64 | },
65 | {
66 | "name": "Red",
67 | "value": "AAAAAgAAAJcAAAAlAw=="
68 | },
69 | {
70 | "name": "Green",
71 | "value": "AAAAAgAAAJcAAAAmAw=="
72 | },
73 | {
74 | "name": "Yellow",
75 | "value": "AAAAAgAAAJcAAAAnAw=="
76 | },
77 | {
78 | "name": "Blue",
79 | "value": "AAAAAgAAAJcAAAAkAw=="
80 | },
81 | {
82 | "name": "Num1",
83 | "value": "AAAAAQAAAAEAAAAAAw=="
84 | },
85 | {
86 | "name": "Num2",
87 | "value": "AAAAAQAAAAEAAAABAw=="
88 | },
89 | {
90 | "name": "Num3",
91 | "value": "AAAAAQAAAAEAAAACAw=="
92 | },
93 | {
94 | "name": "Num4",
95 | "value": "AAAAAQAAAAEAAAADAw=="
96 | },
97 | {
98 | "name": "Num5",
99 | "value": "AAAAAQAAAAEAAAAEAw=="
100 | },
101 | {
102 | "name": "Num6",
103 | "value": "AAAAAQAAAAEAAAAFAw=="
104 | },
105 | {
106 | "name": "Num7",
107 | "value": "AAAAAQAAAAEAAAAGAw=="
108 | },
109 | {
110 | "name": "Num8",
111 | "value": "AAAAAQAAAAEAAAAHAw=="
112 | },
113 | {
114 | "name": "Num9",
115 | "value": "AAAAAQAAAAEAAAAIAw=="
116 | },
117 | {
118 | "name": "Num0",
119 | "value": "AAAAAQAAAAEAAAAJAw=="
120 | },
121 | {
122 | "name": "Num11",
123 | "value": "AAAAAQAAAAEAAAAKAw=="
124 | },
125 | {
126 | "name": "Num12",
127 | "value": "AAAAAQAAAAEAAAALAw=="
128 | },
129 | {
130 | "name": "VolumeUp",
131 | "value": "AAAAAQAAAAEAAAASAw=="
132 | },
133 | {
134 | "name": "VolumeDown",
135 | "value": "AAAAAQAAAAEAAAATAw=="
136 | },
137 | {
138 | "name": "Mute",
139 | "value": "AAAAAQAAAAEAAAAUAw=="
140 | },
141 | {
142 | "name": "ChannelUp",
143 | "value": "AAAAAQAAAAEAAAAQAw=="
144 | },
145 | {
146 | "name": "ChannelDown",
147 | "value": "AAAAAQAAAAEAAAARAw=="
148 | },
149 | {
150 | "name": "SubTitle",
151 | "value": "AAAAAgAAAJcAAAAoAw=="
152 | },
153 | {
154 | "name": "ClosedCaption",
155 | "value": "AAAAAgAAAKQAAAAQAw=="
156 | },
157 | {
158 | "name": "Enter",
159 | "value": "AAAAAQAAAAEAAAALAw=="
160 | },
161 | {
162 | "name": "DOT",
163 | "value": "AAAAAgAAAJcAAAAdAw=="
164 | },
165 | {
166 | "name": "Analog",
167 | "value": "AAAAAgAAAHcAAAANAw=="
168 | },
169 | {
170 | "name": "Teletext",
171 | "value": "AAAAAQAAAAEAAAA/Aw=="
172 | },
173 | {
174 | "name": "Exit",
175 | "value": "AAAAAQAAAAEAAABjAw=="
176 | },
177 | {
178 | "name": "Analog2",
179 | "value": "AAAAAQAAAAEAAAA4Aw=="
180 | },
181 | {
182 | "name": "*AD",
183 | "value": "AAAAAgAAABoAAAA7Aw=="
184 | },
185 | {
186 | "name": "Digital",
187 | "value": "AAAAAgAAAJcAAAAyAw=="
188 | },
189 | {
190 | "name": "Analog?",
191 | "value": "AAAAAgAAAJcAAAAuAw=="
192 | },
193 | {
194 | "name": "BS",
195 | "value": "AAAAAgAAAJcAAAAsAw=="
196 | },
197 | {
198 | "name": "CS",
199 | "value": "AAAAAgAAAJcAAAArAw=="
200 | },
201 | {
202 | "name": "BSCS",
203 | "value": "AAAAAgAAAJcAAAAQAw=="
204 | },
205 | {
206 | "name": "Ddata",
207 | "value": "AAAAAgAAAJcAAAAVAw=="
208 | },
209 | {
210 | "name": "PicOff",
211 | "value": "AAAAAQAAAAEAAAA+Aw=="
212 | },
213 | {
214 | "name": "Tv_Radio",
215 | "value": "AAAAAgAAABoAAABXAw=="
216 | },
217 | {
218 | "name": "Theater",
219 | "value": "AAAAAgAAAHcAAABgAw=="
220 | },
221 | {
222 | "name": "SEN",
223 | "value": "AAAAAgAAABoAAAB9Aw=="
224 | },
225 | {
226 | "name": "InternetWidgets",
227 | "value": "AAAAAgAAABoAAAB6Aw=="
228 | },
229 | {
230 | "name": "InternetVideo",
231 | "value": "AAAAAgAAABoAAAB5Aw=="
232 | },
233 | {
234 | "name": "Netflix",
235 | "value": "AAAAAgAAABoAAAB8Aw=="
236 | },
237 | {
238 | "name": "SceneSelect",
239 | "value": "AAAAAgAAABoAAAB4Aw=="
240 | },
241 | {
242 | "name": "Mode3D",
243 | "value": "AAAAAgAAAHcAAABNAw=="
244 | },
245 | {
246 | "name": "iManual",
247 | "value": "AAAAAgAAABoAAAB7Aw=="
248 | },
249 | {
250 | "name": "Audio",
251 | "value": "AAAAAQAAAAEAAAAXAw=="
252 | },
253 | {
254 | "name": "Wide",
255 | "value": "AAAAAgAAAKQAAAA9Aw=="
256 | },
257 | {
258 | "name": "Jump",
259 | "value": "AAAAAQAAAAEAAAA7Aw=="
260 | },
261 | {
262 | "name": "PAP",
263 | "value": "AAAAAgAAAKQAAAB3Aw=="
264 | },
265 | {
266 | "name": "MyEPG",
267 | "value": "AAAAAgAAAHcAAABrAw=="
268 | },
269 | {
270 | "name": "ProgramDescription",
271 | "value": "AAAAAgAAAJcAAAAWAw=="
272 | },
273 | {
274 | "name": "WriteChapter",
275 | "value": "AAAAAgAAAHcAAABsAw=="
276 | },
277 | {
278 | "name": "TrackID",
279 | "value": "AAAAAgAAABoAAAB+Aw=="
280 | },
281 | {
282 | "name": "TenKey",
283 | "value": "AAAAAgAAAJcAAAAMAw=="
284 | },
285 | {
286 | "name": "AppliCast",
287 | "value": "AAAAAgAAABoAAABvAw=="
288 | },
289 | {
290 | "name": "acTVila",
291 | "value": "AAAAAgAAABoAAAByAw=="
292 | },
293 | {
294 | "name": "DeleteVideo",
295 | "value": "AAAAAgAAAHcAAAAfAw=="
296 | },
297 | {
298 | "name": "PhotoFrame",
299 | "value": "AAAAAgAAABoAAABVAw=="
300 | },
301 | {
302 | "name": "TvPause",
303 | "value": "AAAAAgAAABoAAABnAw=="
304 | },
305 | {
306 | "name": "KeyPad",
307 | "value": "AAAAAgAAABoAAAB1Aw=="
308 | },
309 | {
310 | "name": "Media",
311 | "value": "AAAAAgAAAJcAAAA4Aw=="
312 | },
313 | {
314 | "name": "SyncMenu",
315 | "value": "AAAAAgAAABoAAABYAw=="
316 | },
317 | {
318 | "name": "Forward",
319 | "value": "AAAAAgAAAJcAAAAcAw=="
320 | },
321 | {
322 | "name": "Play",
323 | "value": "AAAAAgAAAJcAAAAaAw=="
324 | },
325 | {
326 | "name": "Rewind",
327 | "value": "AAAAAgAAAJcAAAAbAw=="
328 | },
329 | {
330 | "name": "Prev",
331 | "value": "AAAAAgAAAJcAAAA8Aw=="
332 | },
333 | {
334 | "name": "Stop",
335 | "value": "AAAAAgAAAJcAAAAYAw=="
336 | },
337 | {
338 | "name": "Next",
339 | "value": "AAAAAgAAAJcAAAA9Aw=="
340 | },
341 | {
342 | "name": "Rec",
343 | "value": "AAAAAgAAAJcAAAAgAw=="
344 | },
345 | {
346 | "name": "Pause",
347 | "value": "AAAAAgAAAJcAAAAZAw=="
348 | },
349 | {
350 | "name": "Eject",
351 | "value": "AAAAAgAAAJcAAABIAw=="
352 | },
353 | {
354 | "name": "FlashPlus",
355 | "value": "AAAAAgAAAJcAAAB4Aw=="
356 | },
357 | {
358 | "name": "FlashMinus",
359 | "value": "AAAAAgAAAJcAAAB5Aw=="
360 | },
361 | {
362 | "name": "TopMenu",
363 | "value": "AAAAAgAAABoAAABgAw=="
364 | },
365 | {
366 | "name": "PopUpMenu",
367 | "value": "AAAAAgAAABoAAABhAw=="
368 | },
369 | {
370 | "name": "RakurakuStart",
371 | "value": "AAAAAgAAAHcAAABqAw=="
372 | },
373 | {
374 | "name": "OneTouchTimeRec",
375 | "value": "AAAAAgAAABoAAABkAw=="
376 | },
377 | {
378 | "name": "OneTouchView",
379 | "value": "AAAAAgAAABoAAABlAw=="
380 | },
381 | {
382 | "name": "OneTouchRec",
383 | "value": "AAAAAgAAABoAAABiAw=="
384 | },
385 | {
386 | "name": "OneTouchStop",
387 | "value": "AAAAAgAAABoAAABjAw=="
388 | },
389 | {
390 | "name": "DUX",
391 | "value": "AAAAAgAAABoAAABzAw=="
392 | },
393 | {
394 | "name": "FootballMode",
395 | "value": "AAAAAgAAABoAAAB2Aw=="
396 | },
397 | {
398 | "name": "Social",
399 | "value": "AAAAAgAAABoAAAB0Aw=="
400 | }
401 | ]
402 | ]
403 | }
404 |
--------------------------------------------------------------------------------
/packages/sonybravia/sonybravia-ctl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Options:
4 | # -h, --help display this help and exit
5 | # -i, --ip=ADDRESSS sets the target ip address
6 | # -a, --auth authenticate with the device
7 | # -l, --list-commands show a list of available commands
8 | #
9 | # Interface for sending keycodes to my Sony Bravia TV
10 | # jaagr
11 | #
12 |
13 | source bootstrap.sh
14 |
15 | include utils/ansi.sh
16 | include utils/cli.sh
17 | include utils/log.sh
18 | include utils/log/defer.sh
19 |
20 | bootstrap::finish
21 |
22 | declare -r AUTH_COOKIE="${XDG_DATA_HOME}/sonybravia.cookie"
23 |
24 | function ensure_auth_cookie
25 | {
26 | log::defer "Looking for existing auth cookie"
27 |
28 | [[ -e "$AUTH_COOKIE" ]] || {
29 | log::defer::failure "" "No cookie found at $(ansi::bold "$AUTH_COOKIE")"; exit 1
30 | }
31 |
32 | log::defer::success
33 | }
34 |
35 | function translate_command
36 | {
37 | local command="$1"
38 |
39 | log::defer "Validating command $(ansi::bold "$command")"
40 |
41 | __COMMAND_KEYCODE=$(grep -i "\"$command\"" -A 1 "commands.json" | sed -nr '2s/.*:\s"(.*)"$/\1/p')
42 |
43 | [[ "$__COMMAND_KEYCODE" ]] || {
44 | log::defer::failure "" "Command not listed in commands.json"; exit 1
45 | }
46 |
47 | log::defer::success
48 | }
49 |
50 | function list_commands
51 | {
52 | log::info "List of available commands"
53 | sed -n -r 's/.*"(.+)",$/\1/p' "commands.json" | while read -r command; do
54 | log "- $command"
55 | done
56 | }
57 |
58 | function send_auth_request
59 | {
60 | local ip="$1"
61 | local payload response_code
62 | local nick device uuid
63 | local auth_header auth_code
64 |
65 | log::defer "Making sure we're not already authenticated"
66 |
67 | [[ -e "$AUTH_COOKIE" ]] && {
68 | log::defer::failure "" "An auth cookie is already present at $(ansi::bold "$AUTH_COOKIE"). Remove it to re-authenticate."; exit 1
69 | }
70 |
71 | log::defer::success
72 |
73 | nick=$(whoami)
74 | uuid=$(uuidgen)
75 | device=$(hostname)
76 |
77 | payload=$(printf '{"method":"actRegister","params":[{"clientid":"%s:%s","nickname":"%s","level":"private"},[{"value":"yes","function":"WOL"}]],"id":8,"version":"1.0"}"' "$nick" "$uuid" "$nick ($device)")
78 |
79 | log::defer "Sending authentication request"
80 |
81 | curl -s -XPOST "http://${ip}/sony/accessControl" -d "$payload"
82 |
83 | [[ $? -eq 0 ]] || {
84 | log::defer::failure "" "Failed with status code $?"; exit 1
85 | }
86 |
87 | log::defer::success
88 |
89 | log "Enter the 4-digit code shown on the TV: $(ansi::save_position)"
90 | ansi::restore_position
91 | read -r auth_code
92 |
93 | auth_header="Authorization: Basic $(printf ":%s" "$auth_code" | base64)"
94 |
95 | log::defer "Trying to authenticate using $(ansi::bold "$auth_code")"
96 |
97 | curl -s -i -XPOST "http://${ip}/sony/accessControl" -H "$auth_header" -d "$payload" | egrep -o 'auth=([a-z0-9]+)' > "$AUTH_COOKIE"
98 |
99 | [[ $? -eq 0 ]] || {
100 | log::defer::failure "" "Failed with status code $?"; exit 1
101 | }
102 |
103 | log::defer::success "Authentication successful" "Cookie stored at $(ansi::bold "$AUTH_COOKIE")"
104 | }
105 |
106 | function send_keycode
107 | {
108 | local addr="http://$1/sony/IRCC"
109 | local keycode="$2"
110 | local payload response_code
111 |
112 | keycode="${keycode//\"/}"
113 | keycode="${keycode//\'/}"
114 |
115 | read -r cookie < "$AUTH_COOKIE"
116 |
117 | log::defer "Sending keycode $(ansi::bold "$keycode") to $(ansi::bold "$addr")"
118 |
119 | payload="$keycode"
120 | response_code=$(curl -w '%{http_code}' -s -XPOST "$addr" -d "$payload" -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPACTION: "urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"' -H "Cookie: $cookie" -o /dev/null)
121 |
122 | [[ "$response_code" == "200" ]] || {
123 | log::defer::failure "" "Command failed with response_code ${response_code}"; exit 1
124 | }
125 |
126 | log::defer::success
127 | }
128 |
129 | function main
130 | {
131 | local ip='tv.local'
132 | local auth='false'
133 |
134 | while [[ "${1:0:1}" = "-" ]]; do
135 | case "$1" in
136 | "-h" | "--help") cli::usage_from_commentblock; exit;;
137 | "-i"* | "--ip"*) ip=$(cli::get_argument_value "$@") && shift ;;
138 | "-a" | "--auth") auth='true' ;;
139 | "-l" | "--list-commands") list_commands; exit ;;
140 | *) cli::unrecognized_option "$1" ;;
141 | esac
142 | shift
143 | done
144 |
145 | if $auth; then
146 | send_auth_request "$ip"; exit
147 | fi
148 |
149 | [[ $# -eq 0 ]] && {
150 | cli::usage_from_commentblock; exit
151 | }
152 |
153 | local command="$1" ; shift
154 | local n_events=1
155 | local keycode
156 |
157 | [[ $# -gt 0 ]] && {
158 | n_events=$(( command ))
159 | command="$1"
160 | }
161 |
162 | ensure_auth_cookie
163 | translate_command "$command"
164 |
165 | while (( n_events-- > 0 )); do
166 | send_keycode "$ip" "$__COMMAND_KEYCODE"
167 | done
168 | }
169 |
170 | main "$@"
171 |
--------------------------------------------------------------------------------
/packages/sonybravia/sonybravia-remote:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/ansi.sh
6 | include utils/log.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | # forward if called with arguments
13 | if [[ $# -gt 0 ]]; then
14 | exec sonybravia-ctl "$@"
15 | fi
16 |
17 | declare -A commands
18 |
19 | commands[k]="up"
20 | commands[j]="down"
21 | commands[h]="left"
22 | commands[l]="right"
23 | commands[m]="mute"
24 | commands[return]="confirm"
25 | commands[backspace]="return"
26 | commands[+]="volumeup"
27 | commands[-]="volumedown"
28 |
29 | K_ESC=$(echo -e "\033")
30 | K_RETURN=$(echo -e "\n")
31 | K_BACKSPACE=$(tput kbs)
32 |
33 | ansi::save_position
34 |
35 | while read -r -N1 key; do
36 | ansi::clear_line
37 | ansi::restore_position
38 |
39 | if [[ "$key" == "$K_RETURN" ]]; then
40 | key="return"
41 | elif [[ "$key" == "$K_BACKSPACE" ]]; then
42 | key="backspace"
43 | fi
44 |
45 | if [[ "$key" == "$K_ESC" ]] || [[ "$key" == "q" ]]; then
46 | log "Exitting..."
47 | exit
48 | elif [[ "$key" ]] && [[ "${commands[$key]}" ]]; then
49 | log "${commands[$key]}"
50 | sonybravia-ctl "${commands[$key]}" >/dev/null
51 | else
52 | log::err "Key not mapped to a command"
53 | fi
54 |
55 | ansi::save_position
56 | done
57 | }
58 |
59 | main "$@"
60 |
--------------------------------------------------------------------------------
/packages/themer/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/packages/themer/Makefile:
--------------------------------------------------------------------------------
1 | PREFIX ?= /usr/local
2 | BINPREFIX ?= $(PREFIX)/bin
3 | ZSHCOMP ?= $(PREFIX)/share/zsh/site-functions
4 | BUILDDIR ?= build
5 |
6 | CSCRIPT := ../../compile.sh
7 | CFLAGS += -O -a /home/jaagr/.local/lib/sh -s "'/usr/bin/env bash'"
8 |
9 | all: build
10 |
11 | build:
12 | mkdir -p -v $(BUILDDIR)
13 | for f in theme-*; do \
14 | $(CSCRIPT) $$f $(BUILDDIR)/$$f $(CFLAGS) ; \
15 | done
16 |
17 | install:
18 | for f in theme-*; do \
19 | install -Dvm755 $(BUILDDIR)/$$f $(DESTDIR)$(BINPREFIX)/$$f ; \
20 | done
21 | install -Dm755 _themer $(DESTDIR)$(ZSHCOMP)/_themer
22 |
23 | uninstall:
24 | for f in theme-*; do \
25 | rm -vf $(DESTDIR)$(BINPREFIX)/$$f ; \
26 | done
27 | rm -vf $(DESTDIR)$(ZSHCOMP)/_themer
28 |
29 | clean:
30 | rm -rf build
31 |
32 | .PHONY: build install uninstall clean
33 |
34 | # vim:ts=2 sw=2 noet nolist
35 |
--------------------------------------------------------------------------------
/packages/themer/_themer:
--------------------------------------------------------------------------------
1 | #compdef theme-activate theme-edit
2 |
3 | function _list_themes {
4 | compadd "$@" -- "$CURRENT_THEME"/../themes/*(:t)
5 | }
6 |
7 | function _list_current_configs {
8 | local -a files=("$CURRENT_THEME"/^README.md*(:t))
9 | compadd "$@" -- ${files%%*.png}
10 | }
11 |
12 | case "$service" in
13 | theme-activate)
14 | _arguments : \
15 | "(-h --help)"{-h,--help}"[display help]" \
16 | "(-l --list)"{-l,--list}"[list themes]" \
17 | "1:available themes:_list_themes" \
18 | "*::"
19 | ;;
20 | theme-edit)
21 | _arguments : \
22 | "(-h --help)"{-h,--help}"[display help]" \
23 | "(-c --create)"{-c,--create}"[create configuration if it doesn't exist]" \
24 | "1:current theme configurations:_list_current_configs" \
25 | "*::"
26 | ;;
27 | esac
28 |
--------------------------------------------------------------------------------
/packages/themer/theme-activate:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Activates specified theme configuration
4 | # jaagr
5 | #
6 |
7 | source bootstrap.sh
8 |
9 | include utils/cli2.sh
10 | include utils/ansi.sh
11 | include utils/log.sh
12 | include utils/log/defer.sh
13 |
14 | bootstrap::finish
15 |
16 | cli::define_flag -h --help "Print this help text"
17 | cli::define_flag -l --list "List available themes"
18 |
19 | declare -r BASE_DIR="$LOCAL_ETC"/themer
20 | declare -r CURRENT_DIR="$BASE_DIR"/current
21 |
22 | function main
23 | {
24 | cli::parse "$@"
25 |
26 | if cli::flag --help; then
27 | cli::usage "[opts...] theme_name" ; exit
28 | elif cli::flag --list || [[ $# -eq 0 ]]; then
29 | local current_theme theme
30 | current_theme=$(dirname "$(readlink "$CURRENT_DIR"/*)" 2>/dev/null | tail -1 | xargs basename 2>/dev/null)
31 |
32 | log::info "Available themes:"
33 |
34 | for theme in "$BASE_DIR"/themes/*; do
35 | [[ -d "$theme" ]] || continue
36 |
37 | theme="${theme##*/}"
38 |
39 | if [[ "$theme" == "$current_theme" ]]; then
40 | log "$theme $(ansi::bold "(in use)")"
41 | else
42 | log "$theme"
43 | fi
44 | done
45 |
46 | exit
47 | fi
48 |
49 | local theme_name="$1"
50 | local theme_dir="${BASE_DIR}/themes/${theme_name}"
51 | local termite_config="${XDG_CONFIG_HOME}/termite/config"
52 |
53 | [[ "${theme_name}" ]] || {
54 | log::err "No theme given. Use '--list' to show available themes." ; exit
55 | }
56 |
57 | [[ -d "${theme_dir}" ]] || {
58 | log::err "Could not find theme '${theme_name}'. Show available themes with '--list'" ; exit
59 | }
60 |
61 | log::info "Applying theme $(ansi::bold "${theme_name}")"
62 |
63 | rm -f "${CURRENT_DIR}"/* &>/dev/null
64 |
65 | for file in "${theme_dir}"/*; do
66 | log::defer "Creating symlink to $(basename "${file}")"
67 |
68 | if ln -sf "${file}" "${CURRENT_DIR}/$(basename "${file}")"; then
69 | log::defer::success
70 | else
71 | log::defer::failure
72 | fi
73 | done
74 |
75 | [[ -e "${CURRENT_DIR}/termite" ]] && {
76 | if [[ -e "${termite_config}" ]]; then
77 | local termite_tag="themer::placeholder"
78 |
79 | if grep -q "${termite_tag}" "${termite_config}"; then
80 | log::defer "Creating backup of termite config"
81 |
82 | if ! cp "${termite_config}" "${termite_config}.bak"; then
83 | log::defer::failure "Failed with status $?" ; exit 1
84 | fi
85 |
86 | log::defer::success
87 | log::defer "Removing termite config"
88 |
89 | if ! rm "${termite_config}"; then
90 | log::defer::failure "Failed with status $?" ; exit 1
91 | fi
92 |
93 | log::defer::success
94 |
95 | line=$(sed -nr "/\[colors\]/q ; /font/=" "${termite_config}.bak" | tail -1)
96 | if grep -q "font" "${CURRENT_DIR}/termite" && [[ "${line}" ]] && [[ "$(grep "font" "${CURRENT_DIR}/termite")" != "$(sed -n "${line}p" "${termite_config}.bak")" ]]; then
97 | tmp=$(mktemp)
98 | log::info "Adding font to termite configuration"
99 | {
100 | sed "${line}q" "${termite_config}.bak"
101 | grep "font" "${CURRENT_DIR}/termite"
102 | sed "$((line+1))~1!d" "${termite_config}.bak"
103 | } > "${tmp}"
104 | mv "${tmp}" "${termite_config}.bak"
105 | fi
106 |
107 | log::info "Adding new colors to termite configuration"
108 | {
109 | sed "/${termite_tag}/q" "${termite_config}.bak"
110 | echo "# -- start of script output --"
111 | egrep -v "\[colors\]|font|^#" "${CURRENT_DIR}/termite"
112 | echo "# -- end of script output --"
113 | } >> "${termite_config}"
114 | else
115 | log::debug "Could not find placeholder in termite config"
116 | fi
117 | else
118 | log::debug "Could not find termite config file"
119 | fi
120 | }
121 |
122 | [[ -e ${CURRENT_DIR}/polybar ]] && [[ -e ${XDG_CONFIG_HOME}/polybar/.runargs ]] && {
123 | log::info "Removing cached runargs for polybar"
124 | rm -rf "${XDG_CONFIG_HOME}/polybar/.runargs" &>/dev/null
125 | }
126 | [[ -e ${CURRENT_DIR}/compton ]] && {
127 | log::info "Reloading compton"
128 | bash "${LOCAL_ETC}/compton/reload" &>/dev/null &
129 | }
130 | [[ -e ${CURRENT_DIR}/bspwm ]] && {
131 | log::info "Reloading bspwm"
132 | bash "${LOCAL_ETC}/bspwm/reload" &>/dev/null &
133 | }
134 | [[ -e ${CURRENT_DIR}/termite ]] && {
135 | log::info "Reloading termite"
136 | bash "${LOCAL_ETC}/termite/reload" &>/dev/null &
137 | }
138 | [[ -e ${CURRENT_DIR}/dunst ]] && {
139 | log::info "Reloading dunst"
140 | bash "${LOCAL_ETC}/dunst/reload" &>/dev/null &
141 | }
142 | [[ -e ${CURRENT_DIR}/wallpaper ]] && {
143 | log::info "Setting wallpaper"
144 | bash "${CURRENT_DIR}/wallpaper" &>/dev/null &
145 | }
146 | [[ -e ${CURRENT_DIR}/xresources ]] && {
147 | log::info "Applying xrdb overrides"
148 | xrdb -override "${CURRENT_DIR}/xresources" &>/dev/null &
149 | }
150 |
151 | log::ok "All done! Enjoy..."
152 | }
153 |
154 | main "$@"
155 |
--------------------------------------------------------------------------------
/packages/themer/theme-edit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Opens up the specified theme config for edit
4 | # jaagr
5 | #
6 |
7 | source bootstrap.sh
8 |
9 | include utils/tests.sh
10 | include utils/cli2.sh
11 | include utils/ansi.sh
12 | include utils/log.sh
13 | include utils/log/defer.sh
14 |
15 | bootstrap::finish
16 |
17 | cli::define_flag -h --help "Print this help text"
18 | cli::define_flag -c --create "Create configuration if it doesn't exist"
19 |
20 | declare -r BASE_DIR="$LOCAL_ETC/themer"
21 |
22 | function main
23 | {
24 | cli::parse "$@"
25 |
26 | if cli::flag --help || [[ $# -eq 0 ]]; then
27 | cli::usage "[(current|theme_name).]" ; exit
28 | fi
29 |
30 | local theme_name
31 | local app_name
32 | local app_file
33 |
34 | if [[ "${1//[^.]/}" ]]; then
35 | theme_name="${1%%.*}"
36 | app_name="${1##*.}"
37 | else
38 | theme_name="current"
39 | app_name="$1"
40 | fi
41 |
42 | if ! [[ "$theme_name" ]] || ! [[ "$app_name" ]]; then
43 | cli::usage_from_commentblock; exit
44 | fi
45 |
46 | if [[ "$theme_name" == "current" ]]; then
47 | app_file="${BASE_DIR}/current/${app_name}"
48 | else
49 | app_file="${BASE_DIR}/themes/${theme_name}/${app_name}"
50 | fi
51 |
52 | if ! [[ -e "$app_file" ]]; then
53 | if ! cli::flag --create; then
54 | log::err "Could not find ${app_file}. Use --create to add the app file"; exit
55 | elif [[ "$theme_name" == "current" ]]; then
56 | log::err "Use a named theme when creating a new file"; exit
57 | fi
58 | fi
59 |
60 | log::info "Opening $app_file"
61 | vim "$app_file"
62 | log::ok "Done!"
63 | }
64 |
65 | main "$@"
66 |
--------------------------------------------------------------------------------
/packages/x11/xmatch:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Synopsis:
4 | # ${SCRIPT_NAME} [OPTION...] query
5 | #
6 | # Options:
7 | # -h, --help display this help and exit
8 | # -a, --atom=ATOM atom to match against
9 | # -w, --window=ID id of window to target
10 | # -p, --process match against pstree line instead (pstree -p | head -1)
11 | # -P, --process-root only match against process root
12 | # -x, --process-exact only match against process root
13 | # -i, --invert invert match
14 | # -v, --verbose output descriptive info
15 | #
16 | # Utility for matching X windows by atom value or pstree cmd string
17 | # jaagr
18 | #
19 |
20 | source bootstrap.sh
21 |
22 | include utils/ansi.sh
23 | include utils/cli.sh
24 | include utils/log.sh
25 |
26 | bootstrap::finish
27 |
28 | function main
29 | {
30 | local match='false'
31 | local verbose='false'
32 | local process='false'
33 | local process_root='false'
34 | local process_exact='false'
35 | local invert='false'
36 | local atom="WM_CLASS"
37 | local wid pid value query
38 |
39 | while [[ "${1:0:1}" = "-" ]]; do
40 | case "$1" in
41 | "-h" | "--help") cli::usage_from_commentblock; exit ;;
42 | "-v" | "--verbose") verbose='true' ;;
43 | "-a"*| "--atom"*) atom=$(cli::get_argument_value "$@") && shift ;;
44 | "-w"*| "--window"*) wid=$(cli::get_argument_value "$@") && shift ;;
45 | "-p" | "--process") process='true' ;;
46 | "-P" | "--process-root") process='true'; process_root='true' ;;
47 | "-x" | "--process-exact") process='true'; process_exact='true' ;;
48 | "-i" | "--invert") invert='true' ;;
49 | *) cli::unrecognized_option "$1" ;;
50 | esac
51 | shift
52 | done
53 |
54 | [[ $# -eq 0 ]] && {
55 | cli::usage_from_commentblock; exit
56 | }
57 |
58 | wid="$(xwid)"
59 | query="$*"
60 |
61 | if $process; then
62 | pid=$(( $(xprop -id "$wid" _NET_WM_PID | cut -d'=' -f2) ))
63 | value="$(pstree -p $pid | head -1)"
64 | else
65 | value="$(xprop -id "$wid" "$atom")"
66 | fi
67 |
68 | if $verbose; then
69 | if $invert; then
70 | log::info "Testing if window DOES NOT match user query"
71 | else
72 | log::info "Testing if window matches user query"
73 | fi
74 |
75 | log::info "Querying window $(ansi::bold "$wid")"
76 | log::debug "Using $(ansi::bold "$query") as query string"
77 |
78 | if $process; then
79 | log::debug "Matching against process id $(ansi::bold "$pid")"
80 | log::debug "Process command string $(ansi::bold "$value")"
81 |
82 | if $process_root; then
83 | log::debug "Only matches process root"
84 | fi
85 |
86 | if $process_exact; then
87 | log::debug "Requires exact match"
88 | fi
89 | else
90 | log::debug "Matching against atom $(ansi::bold "$atom")"
91 | log::debug "Atom value $(ansi::bold "$value")"
92 | fi
93 | fi
94 |
95 | if $process_exact; then
96 | sed -nr "/^$query$/q0 ; q1" <<< "$value" && match='true'
97 | elif $process_root; then
98 | sed -nr "/^$query\([0-9]+\)/q0 ; q1" <<< "$value" && match='true'
99 | elif $process; then
100 | sed -nr "/-$query\([0-9]+\)/q0 ; q1" <<< "$value" && match='true'
101 | elif [[ $value =~ $query ]]; then
102 | match='true'
103 | fi
104 |
105 | if $match && $invert; then
106 | match='false'
107 | fi
108 |
109 | if $verbose; then
110 | if $match; then
111 | log::ok "window matches"
112 | else
113 | log::err "window doesn't match"
114 | fi
115 | fi;
116 |
117 | $match || exit 1
118 | }
119 |
120 | main "$@"
121 |
--------------------------------------------------------------------------------
/packages/x11/xwid:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function main
4 | {
5 | [[ $# -eq 0 ]] && \
6 | set -- "echo"
7 | eval "$* $(xdo id)"
8 | }
9 |
10 | main "$@"
11 |
--------------------------------------------------------------------------------
/packages/x11/xwincenter:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | [[ $# -eq 0 ]] && {
4 | echo "Usage: $(basename "$0") window_id"; exit
5 | }
6 |
7 | function main
8 | {
9 | local wid=$1 viewport display width height
10 |
11 | xdo id "$wid" &>/dev/null || {
12 | echo "Window does not exist" ; exit 1
13 | }
14 |
15 | viewport=$(lsw -r)
16 | display=$(xdo id -n root | head -1)
17 | width=$(wattr w "$display")
18 | width=$((width/2-$(wattr w "$wid")/2))
19 | height=$(wattr h "$viewport"||echo 0)
20 | height=$((height - $(wattr h "$display") + $(wattr h "$display")/2))
21 |
22 | wmv -a $width $height "$wid"
23 | }
24 |
25 | main "$@"
26 |
--------------------------------------------------------------------------------
/packages/x11/xwindowname:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function print_title
4 | {
5 | [[ "$(bspc query -N -d)" ]] || {
6 | echo; return
7 | }
8 |
9 | xtitle -i
10 | }
11 |
12 | function main
13 | {
14 | if [[ "$1" = "tail" ]]; then
15 | bspc subscribe | while read -r evt; do
16 | print_title
17 | done
18 | else
19 | print_title
20 | fi
21 | }
22 |
23 | main "$@"
24 |
--------------------------------------------------------------------------------
/packages/x11/xwinprocess:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | [[ $# -eq 0 ]] && {
4 | echo "Usage: $(basename "$0") window_id"; exit
5 | }
6 |
7 | function main
8 | {
9 | local wid="$1"
10 | local pid
11 |
12 | pid=$(xprop -id "$1" _NET_WM_PID)
13 | pid=${pid##* }
14 |
15 | echo "$pid"
16 | ps -p "$pid" -h -o comm
17 | }
18 |
19 | main "$@"
20 |
--------------------------------------------------------------------------------
/packages/x11/xwmstrut:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function main
4 | {
5 | if [[ $# -ne 5 ]]; then
6 | log::err "Usage: ${0##*/} bottom|top w h x y"; exit 125
7 | fi
8 |
9 | local pos="$1"; shift
10 | local h="$1"; shift
11 | local w="$1"; shift
12 | local x="$1"; shift
13 | local y="$1"; shift
14 |
15 | local top=0
16 | local top_start_x=0
17 | local top_end_x=0
18 | local bottom=0
19 | local bottom_start_x=0
20 | local bottom_end_x=0
21 |
22 | if [[ "$pos" == "bottom" ]]; then
23 | bottom=$((h+y))
24 | bottom_start_x=$x
25 | bottom_end_x=$((x+w))
26 | else
27 | top=$((h+y))
28 | top_start_x=$x
29 | top_end_x=$((x+w))
30 | fi
31 |
32 | xprop -f _NET_WM_STRUT_PARTIAL 32c -set _NET_WM_STRUT_PARTIAL \
33 | "0, 0, ${top}, ${bottom}, 0, 0, 0, 0, ${top_start_x}, ${top_end_x}, ${bottom_start_x}, ${bottom_end_x}"
34 | }
35 |
36 | main "$@"
37 |
--------------------------------------------------------------------------------
/standalone/encryptandsign:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Encrypt and sign given file
4 | #
5 | # Synopsis:
6 | # ${SCRIPT_NAME} [OPTION...] file
7 | #
8 | # Options:
9 | # -h, --help display this help and exit
10 | # -s, --sender=ID sender id
11 | # -r, --recipient=ID recipient id
12 | #
13 |
14 | source bootstrap.sh
15 |
16 | include utils/cli.sh
17 | include utils/log.sh
18 |
19 | bootstrap::finish
20 |
21 | function main
22 | {
23 | local file sender recipient abort=0
24 |
25 | [[ $# -eq 0 ]] && set -- "-h"
26 |
27 | while [[ "${1:0:1}" = "-" ]]; do
28 | case "$1" in
29 | "-h" | "--help") cli::usage_from_commentblock; exit;;
30 | "-s"*| "--sender"*) sender=$(cli::get_argument_value "$@") && shift ;;
31 | "-r"*| "--recipient"*) recipient=$(cli::get_argument_value "$@") && shift ;;
32 | *) cli::unrecognized_option "$1" ;;
33 | esac
34 | shift
35 | done
36 |
37 | file="$1" ; shift
38 |
39 | [[ "$sender" ]] || read -r -p "Sender: " sender
40 | [[ "$recipient" ]] || read -r -p "Recipient: " recipient
41 | [[ "$file" ]] || read -r -p "File: " file
42 |
43 | gpg --list-secret-keys "${sender}" &>/dev/null || {
44 | log::err "Unknown sender '${sender}'" ; abort=1
45 | }
46 |
47 | gpg --list-keys "${recipient}" &>/dev/null || {
48 | log::err "Unknown recipient '${recipient}'" ; abort=1
49 | }
50 |
51 | if ! [ -e "${file}" ]; then
52 | log::err "File '${file}' does not exist" ; abort=1
53 | elif ! [ -r "${file}" ]; then
54 | log::err "File '${file}' is not readable" ; abort=1
55 | fi
56 |
57 | [[ $abort -gt 0 ]] && {
58 | log::err "Prerequisites failed" ; exit 1
59 | }
60 |
61 | gpg --default-key "${sender}" --recipient "${recipient}" -e -s -a "${file}" "$@"
62 | }
63 |
64 | main "$@"
65 |
--------------------------------------------------------------------------------
/standalone/lpassfind:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function main
4 | {
5 | if ! lpass status -q; then
6 | lpass login --trust "$(sudo cat /root/lpass_username)" >/dev/null || {
7 | echo "error: login failed"; exit 1
8 | }
9 | fi
10 |
11 | lpass show --clip --password "$(lpass ls | fzf | awk '{print $(NF)}' | sed 's/\]//g')"
12 | }
13 |
14 | main "$@"
15 |
--------------------------------------------------------------------------------
/standalone/time_exec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/log.sh
6 |
7 | bootstrap::finish
8 |
9 | function main {
10 | local -i start seconds minutes
11 |
12 | log::info "Executing: $*"
13 | start=$(date +%s)
14 | eval "$@"
15 |
16 | let minutes=$(date +%s)-start seconds=minutes%60 minutes/=60
17 | log::info "Duration: ${minutes}m${seconds}s"
18 | }
19 |
20 | main "$@"
21 |
--------------------------------------------------------------------------------
/standalone/timeout_prompt.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # TODO: Replace the prompting with:
4 | # > select choice in OPT1 OPT2 OPT3
5 |
6 | require::set_timer(){
7 | timeout="$1" ; shift
8 |
9 | [[ -n "$timeout_pid" ]] && kill "$timeout_pid"
10 |
11 | { sleep "$timeout"
12 | kill -SIGUSR1 0
13 | } & timeout_pid=$!
14 | }
15 |
16 | require::prompt(){
17 | local text="$1" ; shift
18 | local choices=("$@") choice
19 |
20 | echo "Enter a valid choice (${choices[*]}):"
21 | read -r input
22 |
23 | [[ -n $timeout_pid ]] && kill "$timeout_pid"
24 |
25 | for choice in "${choices[@]}"; do
26 | if [[ "$input" == "$choice" ]]; then
27 | result="$choice"; return
28 | fi
29 | done
30 |
31 | [[ $input ]] && echo -e "\"$input\" is not a valid choice.\n"
32 |
33 | [[ -n "$timeout" ]] && require::set_timer "$timeout"
34 |
35 | require::prompt "$text" "${choices[@]}"
36 | }
37 |
38 | main() {
39 | trap 'return' SIGUSR1
40 |
41 | require::set_timer 3
42 | require::prompt "title" "A" "B" "C"
43 |
44 | if [[ -z "$result" ]]; then
45 | echo -e "Timeout"; exit
46 | fi
47 |
48 | echo "Result: $result"
49 | }
50 |
51 | main "$@" 2>/dev/null
52 |
--------------------------------------------------------------------------------
/tpl.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Lorem ipsum dolor sit amet...
4 | # jaagr
5 | #
6 |
7 | source bootstrap.sh
8 |
9 | include utils/log.sh
10 | include utils/cli2.sh
11 |
12 | bootstrap::finish
13 |
14 | cli::define_flag -h --help "Print this help text"
15 | cli::define_flag -f --force "..."
16 |
17 | function main {
18 | cli::parse "$@"
19 |
20 | if cli::flag --help; then
21 | cli::usage "[opts...] arg"; exit
22 | fi
23 | }
24 |
25 | main "$@"
26 |
--------------------------------------------------------------------------------
/utils/_.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Set of functions used internally by the utils
4 |
5 | function _::stdout {
6 | echo "${FUNCNAME[1]} -> $*"
7 | }
8 |
9 | function _::stderr {
10 | echo "${FUNCNAME[1]} -> $*" >&2
11 | }
12 |
13 | function _::geom {
14 | echo "${1//[^0-9]/}x${2//[^0-9]/}+${3//[^0-9]/}+${4//[^0-9]/}"
15 | }
16 |
--------------------------------------------------------------------------------
/utils/algo.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function algo::luhn {
4 | local seq="$1" ; shift
5 | local val ret map i j
6 |
7 | for (( i=1 ; i<=${#seq} ; i+=1 )); do
8 | j="${seq:$i-1:1}"
9 | val=$(( j * ( i % 2 + 1 ) ));
10 | map="${map}${val}"
11 | done
12 |
13 | ret=$(echo "${map}" | sed -nr 's/(.)/\1+/gp' | sed -nr 's/^(.*)\+$/\1/gp' )
14 |
15 | if [[ "${#seq}" -eq 9 ]]; then
16 | echo "$(( 10 - ( ret % 10 )))"
17 | else
18 | echo "$(( ret % 10 ))"
19 | fi
20 | }
21 |
--------------------------------------------------------------------------------
/utils/alsa.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Alsa utility functions
4 | # jaagr
5 | #
6 |
7 | function alsa::get_card_index {
8 | amixer controls | sed -nr "s/^numid=([0-9]+).*CARD.*${1}.*/\1/p"
9 | }
10 |
11 | function alsa::is_connected {
12 | amixer cget "numid=$1" | sed -rn '$!d;/=on$/!q1' \
13 | && return 0 \
14 | || return 1
15 | }
16 |
17 | function alsa::get_volume {
18 | amixer sget "${1},0" | sed -nr 's/.*\[([0-9]+)%\].*/\1/p'
19 | }
20 |
21 | function alsa::set_volume {
22 | amixer -q set "${1},0" "${2}%"
23 | }
24 |
25 | function alsa::is_muted {
26 | amixer sget "${1},0" | sed -rn '$!d;/\[off\]$/!q1' \
27 | && return 0 \
28 | || return 1
29 | }
30 |
31 | function alsa::mute {
32 | local mixer="$1" ; shift
33 | local mode
34 |
35 | [[ $# -gt 0 ]] && mode=$1 || mode='true'
36 |
37 | if $mode; then
38 | amixer -q set "$mixer" off
39 | else
40 | amixer -q set "$mixer" on
41 | fi
42 | }
43 |
44 | function alsa::unmute {
45 | alsa::mute "$1" 'false'
46 | }
47 |
--------------------------------------------------------------------------------
/utils/ansi.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility functions for handling terminal output/formatting
4 | # jaagr
5 | #
6 |
7 | test '[post-pass:require-fn=ansi::check_support]'
8 | declare -gx __ANSI_SUPPORT='true'
9 |
10 | if ! [[ -t 1 ]]; then
11 | __ANSI_SUPPORT='false'
12 | fi
13 | test '[/post-pass:require-fn]'
14 |
15 | function ansi::check_support {
16 | $__ANSI_SUPPORT || [[ -t 1 ]] \
17 | && return 0 \
18 | || return 1
19 | }
20 |
21 | function ansi {
22 | if ansi::check_support; then
23 | printf "\033[%s" "$*"
24 | fi
25 | }
26 |
27 | function ansi::reset {
28 | ansi "0m"
29 | }
30 |
31 | function ansi::colorize {
32 | local colors=$1 ; shift
33 | ansi "${colors}m"
34 | printf "%s" "$*"
35 | ansi::reset
36 | }
37 |
38 | function ansi::bold {
39 | ansi "1m"
40 | printf "%s" "$*"
41 | ansi::reset
42 | }
43 |
44 | function ansi::italic {
45 | ansi "3m"
46 | printf "%s" "$*"
47 | ansi::reset
48 | }
49 |
50 | function ansi::conceal {
51 | ansi "8m"
52 | printf "%s" "$*"
53 | ansi::reset
54 | }
55 |
56 | function ansi::strikethrough {
57 | ansi "9m"
58 | printf "%s" "$*"
59 | ansi::reset
60 | }
61 |
62 | function ansi::beginning {
63 | printf "\r"
64 | }
65 |
66 | function ansi::up {
67 | ansi "${1}A"
68 | }
69 |
70 | function ansi::down {
71 | ansi "${1}B"
72 | }
73 |
74 | function ansi::left {
75 | ansi "${1}D"
76 | }
77 |
78 | function ansi::right {
79 | ansi "${1}C"
80 | }
81 |
82 | function ansi::line_up {
83 | ansi "${1}F"
84 | }
85 |
86 | function ansi::line_down {
87 | ansi "${1}E"
88 | }
89 |
90 | function ansi::move {
91 | local rows=$1 ; shift
92 | local cols=$1 ; shift
93 |
94 | if [[ $rows -lt 0 ]]; then
95 | ansi::up "${rows:1}"
96 | elif [[ $rows -gt 0 ]]; then
97 | ansi::down "$rows"
98 | fi
99 |
100 | if [[ $cols -lt 0 ]]; then
101 | ansi::left "${cols:1}"
102 | elif [[ $cols -gt 0 ]]; then
103 | ansi::right "$cols"
104 | fi
105 | }
106 |
107 | function ansi::move_absolute {
108 | local row=$1 ; shift
109 | local col=$1 ; shift
110 | ansi "${row};${col}f"
111 | }
112 |
113 | function ansi::save_position {
114 | ansi "s"
115 | }
116 |
117 | function ansi::restore_position {
118 | ansi "u"
119 | }
120 |
121 | function ansi::clear_screen {
122 | ansi::beginning
123 | ansi "2J"
124 | }
125 |
126 | function ansi::clear_lines_before {
127 | ansi::beginning
128 | ansi "1J"
129 | }
130 |
131 | function ansi::clear_lines_after {
132 | ansi::beginning
133 | ansi "0J"
134 | }
135 |
136 | function ansi::clear_line {
137 | ansi::beginning
138 | ansi "K"
139 | }
140 |
141 | function ansi::extend_buffer {
142 | if ansi::check_support; then
143 | printf "\n\n"
144 | ansi::line_up 2
145 | fi
146 | }
147 |
148 | #function ansi::is_last_line {
149 | # local report
150 | # report=$(ansi "6n")
151 | #}
152 |
153 | function ansi::draw_line {
154 | if ansi::check_support; then
155 | printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | sed -n -r "s/ /${1:-─}/gp"
156 | fi
157 | }
158 |
--------------------------------------------------------------------------------
/utils/atexit.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function sigaction {
4 | trap - INT TERM QUIT 0
5 | declare -f atexit >/dev/null && atexit
6 | }
7 |
8 | trap sigaction INT TERM QUIT 0
9 |
--------------------------------------------------------------------------------
/utils/cli.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility funtions for the cli
4 | # jaagr
5 | #
6 |
7 | include utils/log.sh
8 |
9 | function cli::usage_from_commentblock
10 | {
11 | [[ -n "$1" ]] && script="$1" || script="$0"
12 |
13 | local script_name
14 | script_name=$(basename "$script")
15 |
16 | local synopsis='false'
17 | local options='false'
18 |
19 | while read -r line
20 | do
21 | # Break at first non-comment line
22 | [[ "${line:0:1}" = '#' ]] || break
23 |
24 | [[ "${line##* }" == "Synopsis:" ]] && {
25 | synopsis='true'
26 | continue
27 | }
28 | [[ "${line##* }" == "Options:" ]] && {
29 | printf "\n"
30 | options='true'
31 | continue
32 | }
33 |
34 | if $synopsis; then
35 | line=${line:4}
36 | line=${line//\$\{SCRIPT_NAME\} /}
37 | line=${line//\$0 /}
38 | echo "Usage: $script_name $line"
39 | synopsis='false'
40 | continue
41 | fi
42 |
43 | if $options; then
44 | [[ "${line:0:4}" != "# " ]] && {
45 | printf "\n"
46 | options='false'
47 | continue
48 | }
49 |
50 | echo "${line:1}"
51 | fi
52 | done < "$script"
53 | }
54 |
55 | function cli::unrecognized_option
56 | {
57 | log::err "Unrecognized option '$1'"
58 | log "Try $(basename "$0") --help for more information."
59 | exit 125
60 | }
61 |
62 | function cli::get_argument_value
63 | {
64 | if [[ ${1:0:2} == "--" ]]; then
65 | echo "$1" | sed -rn 's/^--[^=\ ]*=([^\ ]*)$/\1/p' ; exit 1
66 | elif [[ ${#1} -eq 2 ]]; then
67 | echo "$2" ; exit 0
68 | else
69 | exit 1
70 | fi
71 | }
72 |
--------------------------------------------------------------------------------
/utils/cli2.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility funtions for the cli
4 | # jaagr
5 | #
6 |
7 | include utils/log.sh
8 |
9 | test '[post-pass:require-fn=cli::parse]'
10 | declare -gA __map=()
11 | declare -gA __revmap=()
12 | declare -gA __values=()
13 | declare -gA __flags=()
14 | declare -ga __positional=()
15 |
16 | declare -gi CLI_FLAG_NONE=1
17 | declare -gi CLI_FLAG_OPTVAL=2
18 | declare -gi CLI_FLAG_REQVAL=4
19 | test '[/post-pass:require-fn]'
20 |
21 | function cli::define_flag # (short,long,helptext) ->
22 | {
23 | local shortname="$1" ; shift
24 | local longname="$1" ; shift
25 | local helptext="$1" ; shift
26 | local -i flags=${1:-$CLI_FLAG_NONE} ; shift
27 | IFS="+"
28 | __map[$longname]="$flags+$shortname+$longname+${helptext//+/\\+}"
29 | __revmap[$shortname]=$longname
30 | }
31 |
32 | function cli::define_optflag
33 | {
34 | echo TODO
35 | }
36 |
37 | function cli::define_arg
38 | {
39 | echo TODO
40 | }
41 |
42 | function cli::define_optarg
43 | {
44 | echo TODO
45 | }
46 |
47 | function cli::flag
48 | {
49 | [[ "${__flags[$1]}" == "1" ]]
50 | }
51 |
52 | function cli::value
53 | {
54 | echo "${__values[$1]}"
55 | }
56 |
57 | function cli::get_positional
58 | {
59 | if [[ $# -eq 0 ]]; then
60 | echo "${__positional[@]}"
61 | elif [[ ${#__positional[@]} -ge $1 ]]; then
62 | echo "${__positional[$1]}"
63 | fi
64 | }
65 |
66 | function cli::parse
67 | {
68 | local -a map_entry
69 | local -i flags
70 | local value
71 |
72 | while [[ $# -gt 0 ]]
73 | do
74 | unset value
75 |
76 | if [[ ${1:0:1} != "-" ]]; then
77 | __positional+=("$1")
78 | shift
79 | continue
80 | elif [[ ${#__map[${1%%=*}]} -gt 0 ]]; then
81 | map_entry=(${__map[${1%%=*}][@]})
82 | value="${1#*=}"
83 | if [[ ${#value} -eq ${#1} ]]; then
84 | unset value
85 | fi
86 | shiftcount=1
87 |
88 | elif [[ ${#__revmap[$1]} -gt 0 ]]; then
89 | map_entry=(${__map[${__revmap[$1]}][@]})
90 |
91 | if [[ $# -gt 1 ]] && [[ ${2:0:1} != "-" ]]; then
92 | value="$2"
93 | shiftcount=2
94 | elif [[ $# -gt 1 ]] && [[ ${2:0:1} == "-" ]]; then
95 | shiftcount=1
96 | unset value
97 | fi
98 |
99 | else
100 | log::err "Unrecognized argument '$1'" ; exit 125
101 | fi
102 |
103 | local -n shortname="map_entry[1]"
104 | local -n longname="map_entry[2]"
105 | local -n flags_ref="map_entry[0]"
106 |
107 | let flags=$flags_ref
108 |
109 | if (( (flags & CLI_FLAG_NONE) == CLI_FLAG_NONE )); then
110 | if [[ "$value" ]] && [[ $shiftcount -gt 1 ]]; then
111 | let shiftcount--;
112 | unset value
113 | fi
114 | __flags[$longname]=1
115 | else
116 |
117 | if (( (flags & CLI_FLAG_REQVAL) == CLI_FLAG_REQVAL )) && ! [[ "$value" ]]; then
118 | log::err "Option '$longname' requires an argument..." ; exit 125
119 | fi
120 |
121 | if [[ ${#__values[$longname]} -gt 0 ]]; then
122 | log::err "Option '$longname' defined more than once..." ; exit 125
123 | fi
124 |
125 | __values[$longname]=$value
126 | fi
127 |
128 | shift $shiftcount
129 | done
130 |
131 | # for _ in "${!__values[@]}"; do
132 | # echo "$_ == ${__values[$_]}"
133 | # done
134 |
135 | # for _ in "${!__flags[@]}"; do
136 | # echo "$_ == ${__flags[$_]}"
137 | # done
138 |
139 | # for (( iter=0; iter<${#__positional[@]}; ++iter )); do
140 | # echo "${__positional[$iter]}"
141 | # done
142 | }
143 |
144 | function cli::usage
145 | {
146 | local -a map_entry
147 | local i maxlen=0 len=0
148 |
149 | for _ in "${!__map[@]}"; do
150 | map_entry=(${__map[$_][@]})
151 | let len=${#map_entry[1]}+${#map_entry[2]}
152 | maxlen=$((len>maxlen?len:maxlen))
153 | done
154 | let maxlen+=2
155 |
156 | printf "%s\n\n" "Usage: ${BASH_SOURCE[1]##*/} ${1:-[OPTION...]}"
157 | for _ in "${!__map[@]}"; do
158 | map_entry=(${__map[$_][@]})
159 | printf " %s, %s" "${map_entry[1]}" "${map_entry[2]}"
160 | printf "%*s %s\n" $(( maxlen - ${#map_entry[1]} - ${#map_entry[2]} )) " " "${map_entry[3]}"
161 | done
162 | }
163 |
164 | function cli::usage_from_commentblock
165 | {
166 | [[ -n "$1" ]] && script="$1" || script="$0"
167 |
168 | local script_name
169 | script_name=$(basename "$script")
170 |
171 | local synopsis='false'
172 | local options='false'
173 |
174 | while read -r line
175 | do
176 | # Break at first non-comment line
177 | [[ "${line:0:1}" = '#' ]] || break
178 |
179 | [[ "${line##* }" == "Synopsis:" ]] && {
180 | synopsis='true'
181 | continue
182 | }
183 | [[ "${line##* }" == "Options:" ]] && {
184 | printf "\n"
185 | options='true'
186 | continue
187 | }
188 |
189 | if $synopsis; then
190 | line=${line:4}
191 | line=${line//\$\{SCRIPT_NAME\} /}
192 | line=${line//\$0 /}
193 | echo "Usage: $script_name $line"
194 | synopsis='false'
195 | continue
196 | fi
197 |
198 | if $options; then
199 | [[ "${line:0:4}" != "# " ]] && {
200 | printf "\n"
201 | options='false'
202 | continue
203 | }
204 |
205 | echo "${line:1}"
206 | fi
207 | done < "$script"
208 | }
209 |
--------------------------------------------------------------------------------
/utils/color.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility funtions for colors
4 | # jaagr
5 | #
6 |
7 | include utils/math.sh
8 | include utils/log.sh
9 |
10 | function color::brightness {
11 | local hex=${1//[^[:xdigit:]]/}; shift
12 | local perc=$((100-$1))
13 |
14 | [[ ${#hex} -eq 3 ]] && {
15 | hex="${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}"
16 | }
17 |
18 | [[ ${#hex} -ne 6 ]] && {
19 | log::err "Invalid hex color \"${hex}\""; return 1
20 | }
21 |
22 | local rgb str val i;
23 |
24 | for (( i=0 ; i<3 ; i+=1 )); do
25 | val="$(printf "%2f" "0x${hex:$((i*2)):2}")"
26 | val="$(math::float "${val}-(${perc}*(${val}/100))")"
27 | val="$(math::round "$val")"
28 | val="$(math::min "$val" 255)"
29 | val="$(math::max "$val" 0)"
30 | str="0$(printf "%x" "$val")"
31 | rgb="${rgb}${str:(-2)}"
32 | done
33 |
34 | echo "#${rgb}"
35 | }
36 |
--------------------------------------------------------------------------------
/utils/json.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility funtions for json data
4 | # jaagr
5 | #
6 |
7 | function json::get_value {
8 | echo "$1" | jq ".$2"
9 | }
10 |
--------------------------------------------------------------------------------
/utils/keycode.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # shellcheck disable=SC2155
3 | #
4 | # Utility funtions for keyboard data
5 | # jaagr
6 | #
7 |
8 | test '[post-pass:require-fn=keycode::match_esc]'
9 | declare -r -g K_ESC="$(echo -ne "\033")"
10 | test '[/post-pass:require-fn]'
11 | test '[post-pass:require-fn=keycode::match_enter]'
12 | declare -r -g K_RETURN="$(echo -ne "\n")"
13 | test '[/post-pass:require-fn]'
14 |
15 | function keycode::is
16 | {
17 | local input="$1" ; shift
18 |
19 | typeset -n ref="$1" ; shift
20 |
21 | [[ "$input" == "$ref" ]] \
22 | && return 0 \
23 | || return 1
24 | }
25 |
26 | function keycode::match_esc {
27 | keycode::is "$1" K_ESC
28 | }
29 | function keycode::match_enter {
30 | keycode::is "$1" K_RETURN
31 | }
32 |
--------------------------------------------------------------------------------
/utils/log.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | include utils/ansi.sh
4 | include utils/log/log.sh
5 | include utils/log/format/slim.sh
6 |
--------------------------------------------------------------------------------
/utils/log/_tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/ansi.sh
6 | include utils/log/banner.sh
7 | include utils/log/defer.sh
8 |
9 | function main {
10 | [[ $1 == "pending" || $# -eq 0 ]] && {
11 | echo -e "[utils/log/pending.sh]\n"
12 |
13 | log::defer "Pending..." ; sleep 0.25
14 | log::defer::success
15 |
16 | log::defer "Pending..." ; sleep 0.25
17 | log::defer::failure
18 |
19 | log::defer "Pending..." ; sleep 0.25
20 | log::defer::success "Success" "Lorem ipsum..."
21 |
22 | log::defer "Pending..." ; sleep 0.25
23 | log::defer::failure "Failure" "Lorem ipsum..."
24 |
25 | log::defer "Pending..." ; sleep 0.25
26 | log::defer::other "Replace message"
27 | }
28 |
29 | [[ $1 == "plain" || $# -eq 0 ]] && {
30 | [[ $# -eq 0 ]] && ansi::draw_line
31 |
32 | echo -e "[utils/log/format/plain.sh]\n"
33 |
34 | load utils/log/format/plain.sh
35 |
36 | log "Lorem ipsum dolor sit amet"
37 | log::debug "Lorem ipsum dolor sit amet"
38 | log::info "Lorem ipsum dolor sit amet"
39 | log::ok "Lorem ipsum dolor sit amet"
40 | log::warn "Lorem ipsum dolor sit amet"
41 | log::err "Lorem ipsum dolor sit amet"
42 | log::fatal "Lorem ipsum dolor sit amet"
43 |
44 | echo -e "\n[utils/log/pending.sh + utils/log/format/plain.sh]\n"
45 |
46 | log::defer "Pending..." ; sleep 0.25
47 | log::defer::success
48 |
49 | log::defer "Pending..." ; sleep 0.25
50 | log::defer::failure
51 |
52 | log::defer "Pending..." ; sleep 0.25
53 | log::defer::success "Success" "Lorem ipsum..."
54 |
55 | log::defer "Pending..." ; sleep 0.25
56 | log::defer::failure "Failure" "Lorem ipsum..."
57 |
58 | log::defer "Pending..." ; sleep 0.25
59 | log::defer::other "Replace message"
60 | }
61 |
62 | [[ $1 == "tags" || $# -eq 0 ]] && {
63 | [[ $# -eq 0 ]] && ansi::draw_line
64 |
65 | echo -e "[utils/log/format/tags.sh]\n"
66 |
67 | load utils/log/format/tags.sh
68 |
69 | log "Lorem ipsum dolor sit amet"
70 | log::debug "Lorem ipsum dolor sit amet"
71 | log::info "Lorem ipsum dolor sit amet"
72 | log::ok "Lorem ipsum dolor sit amet"
73 | log::warn "Lorem ipsum dolor sit amet"
74 | log::err "Lorem ipsum dolor sit amet"
75 | log::fatal "Lorem ipsum dolor sit amet"
76 |
77 | echo -e "\n[utils/log/format/pending.sh + utils/log/format/tags.sh]\n"
78 |
79 | log::defer "Pending..." ; sleep 0.25
80 | log::defer::success
81 |
82 | log::defer "Pending..." ; sleep 0.25
83 | log::defer::failure
84 |
85 | log::defer "Pending..." ; sleep 0.25
86 | log::defer::success "Success" "Lorem ipsum..."
87 |
88 | log::defer "Pending..." ; sleep 0.25
89 | log::defer::failure "Failure" "Lorem ipsum..."
90 |
91 | log::defer "Pending..." ; sleep 0.25
92 | log::defer::other "Message"
93 | }
94 |
95 | [[ $1 == "blocks" || $# -eq 0 ]] && {
96 | [[ $# -eq 0 ]] && ansi::draw_line
97 |
98 | echo -e "[utils/log/format/blocks.sh]\n"
99 |
100 | load utils/log/format/blocks.sh
101 |
102 | log "Lorem ipsum dolor sit amet"
103 | log::debug "Lorem ipsum dolor sit amet"
104 | log::info "Lorem ipsum dolor sit amet"
105 | log::ok "Lorem ipsum dolor sit amet"
106 | log::warn "Lorem ipsum dolor sit amet"
107 | log::err "Lorem ipsum dolor sit amet"
108 | log::fatal "Lorem ipsum dolor sit amet"
109 |
110 | echo -e "\n[utils/log/format/pending.sh + utils/log/format/blocks.sh]\n"
111 |
112 | log::defer "Pending..." ; sleep 0.25
113 | log::defer::success
114 |
115 | log::defer "Pending..." ; sleep 0.25
116 | log::defer::failure
117 |
118 | log::defer "Pending..." ; sleep 0.25
119 | log::defer::success "Success" "Lorem ipsum..."
120 |
121 | log::defer "Pending..." ; sleep 0.25
122 | log::defer::failure "Failure" "Lorem ipsum..."
123 |
124 | log::defer "Pending..." ; sleep 0.25
125 | log::defer::other "Message"
126 | }
127 |
128 | [[ $1 == "icons" || $# -eq 0 ]] && {
129 | [[ $# -eq 0 ]] && ansi::draw_line
130 |
131 | echo -e "[utils/log/format/icons.sh]\n"
132 |
133 | load utils/log/format/icons.sh
134 |
135 | log "Lorem ipsum dolor sit amet"
136 | log::debug "Lorem ipsum dolor sit amet"
137 | log::info "Lorem ipsum dolor sit amet"
138 | log::ok "Lorem ipsum dolor sit amet"
139 | log::warn "Lorem ipsum dolor sit amet"
140 | log::err "Lorem ipsum dolor sit amet"
141 | log::fatal "Lorem ipsum dolor sit amet"
142 |
143 | echo -e "\n[utils/log/format/pending.sh + utils/log/format/icons.sh]\n"
144 |
145 | log::defer "Pending..." ; sleep 0.25
146 | log::defer::success
147 |
148 | log::defer "Pending..." ; sleep 0.25
149 | log::defer::failure
150 |
151 | log::defer "Pending..." ; sleep 0.25
152 | log::defer::success "Success" "Lorem ipsum..."
153 |
154 | log::defer "Pending..." ; sleep 0.25
155 | log::defer::failure "Failure" "Lorem ipsum..."
156 |
157 | log::defer "Pending..." ; sleep 0.25
158 | log::defer::other "Message"
159 | }
160 |
161 | [[ $1 == "slim" || $# -eq 0 ]] && {
162 | [[ $# -eq 0 ]] && ansi::draw_line
163 |
164 | echo -e "[utils/log/format/slim.sh]\n"
165 |
166 | load utils/log/format/slim.sh
167 |
168 | log "Lorem ipsum dolor sit amet"
169 | log::debug "Lorem ipsum dolor sit amet"
170 | log::info "Lorem ipsum dolor sit amet"
171 | log::ok "Lorem ipsum dolor sit amet"
172 | log::warn "Lorem ipsum dolor sit amet"
173 | log::err "Lorem ipsum dolor sit amet"
174 | log::fatal "Lorem ipsum dolor sit amet"
175 |
176 | echo -e "\n[utils/log/format/pending.sh + utils/log/format/slim.sh]\n"
177 |
178 | log::defer "Pending..." ; sleep 0.25
179 | log::defer::success
180 |
181 | log::defer "Pending..." ; sleep 0.25
182 | log::defer::failure
183 |
184 | log::defer "Pending..." ; sleep 0.25
185 | log::defer::success "Success" "Lorem ipsum..."
186 |
187 | log::defer "Pending..." ; sleep 0.25
188 | log::defer::failure "Failure" "Lorem ipsum..."
189 |
190 | log::defer "Pending..." ; sleep 0.25
191 | log::defer::other "Message"
192 | }
193 |
194 | [[ $1 == "banner" || $# -eq 0 ]] && {
195 | [[ $# -eq 0 ]] && ansi::draw_line
196 |
197 | echo -e "[utils/log/banner.sh]\n"
198 |
199 | log::banner 13 "test odd 1"; echo
200 | log::banner 13 "test odd2"; echo
201 | log::banner 10 "test even1"; echo
202 | log::banner 10 "test even 2"; echo
203 |
204 | log::banner 30 " " "44;37;1"
205 | log::banner 30 "test" "44;37;1"
206 | log::banner 30 " " "44;37;1"
207 | }
208 | }
209 |
210 | main "$@"
211 |
--------------------------------------------------------------------------------
/utils/log/banner.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # shellcheck disable=2155
4 | function log::banner
5 | {
6 | local spaces=$1 ; shift
7 | local msg="$1" ; shift
8 | local ansi_attrs="${1:-41;37;1}"
9 | local length="${#msg}"
10 | local padding=$(printf "%*s" $(( (spaces - length) / 2 )))
11 | local diff=$(( ${#padding} * 2 + length - spaces ))
12 |
13 | if [[ ${diff:0:1} == "-" ]]; then
14 | diff=${diff:1}
15 | fi
16 |
17 | if [[ $diff -eq 1 ]]; then
18 | msg="$msg "
19 | elif [[ $diff -gt 1 ]]; then
20 | hdiff=$((diff/2))
21 | echo $diff
22 | msg="$(printf "%*s" $hdiff " ")$msg$(printf "%*s" $hdiff " ")"
23 | fi
24 |
25 | echo -e "\033[${ansi_attrs}m${padding}${msg}${padding}\033[0m"
26 | }
27 |
--------------------------------------------------------------------------------
/utils/log/defer.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | include utils/log.sh
4 | include utils/ansi.sh
5 | include utils/keycode.sh
6 |
7 | test '[post-pass:require-fn=log::defer]'
8 | declare -gx __LOG_PENDING=0
9 | declare -gx __LOG_PENDING_MSG
10 | test '[/post-pass:require-fn]'
11 |
12 | function log::defer
13 | {
14 | # assume success for last log since no error was reported
15 | log::defer::_finish_pending
16 | ansi::beginning
17 | printf "%s" "$(log "$@")"
18 | __LOG_PENDING_MSG="$*"
19 | __LOG_PENDING=1
20 | trap 'log::defer::_finish_pending' EXIT
21 | }
22 |
23 | function log::defer::_finish_pending
24 | {
25 | if [[ $__LOG_PENDING -eq 1 ]]; then
26 | log::defer::success
27 | fi
28 | }
29 |
30 | function log::defer::_describe
31 | {
32 | local color="$1" ; shift
33 | printf "%${__LOG_PENDING_PAD}s"
34 | [[ "$__LOG_FORMAT" == "tags" ]] && printf " "
35 | if ansi::check_support; then
36 | printf "\033[1;${color}m\U2570\U2500\U2500\U2578\033[0m %s\n" "$@"
37 | else
38 | printf "%s\n" "$@"
39 | fi
40 | }
41 |
42 | function log::defer::success
43 | {
44 | local msg=${1:-$__LOG_PENDING_MSG} ; shift
45 | ansi::beginning
46 | if [[ "$msg" ]]; then
47 | ansi::check_support && ansi::clear_line
48 | ansi::check_support || printf "\n"
49 | fi
50 | log::ok "$msg"
51 | [[ $# -gt 0 ]] && log::defer::_describe "32" "$@"
52 | __LOG_PENDING=0
53 | }
54 |
55 | function log::defer::failure
56 | {
57 | local msg=${1:-$__LOG_PENDING_MSG} ; shift
58 | ansi::beginning
59 | if [[ "$msg" ]]; then
60 | ansi::check_support && ansi::clear_line
61 | ansi::check_support || printf "\n"
62 | fi
63 | log::err "$msg"
64 | [[ $# -gt 0 ]] && 1>&2 log::defer::_describe "31" "$@"
65 | __LOG_PENDING=0
66 | }
67 |
68 | function log::defer::other
69 | {
70 | local msg=$1 ; shift
71 | ansi::beginning
72 | if [[ "$msg" ]]; then
73 | ansi::check_support && ansi::clear_line
74 | ansi::check_support || printf "\n"
75 | fi
76 | log "$msg"
77 | [[ $# -gt 0 ]] && log::defer::_describe "32" "$@"
78 | __LOG_PENDING=0
79 | }
80 |
81 | function log::defer::countdown
82 | {
83 | local -n retval=$1 ; shift
84 | local -i seconds=$1 ; shift
85 | local -i timer
86 | local key
87 |
88 | ansi::extend_buffer
89 | log::defer "$(ansi::save_position)" "${@//%s/0}"
90 |
91 | seconds+=1;
92 |
93 | while (( --seconds > 0 )); do
94 | ansi::restore_position
95 |
96 | echo "${@//%s/$seconds}"
97 |
98 | read -s -r -N1 -t 1 key
99 | timer=$?
100 |
101 | if [[ $seconds -eq 1 ]]; then
102 | retval=2 ; break
103 | elif keycode::match_esc "$key" || [[ "$key" == "q" ]]; then
104 | retval=1 ; break
105 | elif [[ $timer -ne 142 ]]; then
106 | retval=0 ; break
107 | fi
108 | done
109 |
110 | ansi::restore_position
111 | }
112 |
113 | function log::defer::cmd
114 | {
115 | local fail_with_details='true'
116 | local err
117 |
118 | if [[ "$1" == 'true' ]]; then
119 | fail_with_details='true'; shift
120 | elif [[ "$1" == 'false' ]]; then
121 | fail_with_details='false'; shift
122 | fi
123 |
124 | err=$(/bin/sh -c "$@" 2>&1 >/dev/null)
125 |
126 | if [[ -n "$err" ]]; then
127 | if $fail_with_details; then
128 | log::defer::failure "" "$err"
129 | else
130 | log::defer::failure
131 | fi
132 | return 1
133 | fi
134 |
135 | log::defer::success
136 | }
137 |
--------------------------------------------------------------------------------
/utils/log/format/blocks.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | test '[post-pass:require-fn=log::_format]'
4 | declare -gx __LOG_FORMAT="blocks"
5 | declare -gx __LOG_TAG_FORMAT=1
6 | declare -gx __LOG_PENDING_PAD=5
7 | test '[/post-pass:require-fn]'
8 |
9 | function log::_format
10 | {
11 | local ansi=$1 ; shift
12 | local tag=$1 ; shift
13 |
14 | printf "\033[%sm%6s \033[0;1;37m \033[0m%s" "$ansi" "$tag" "$*"
15 | }
16 |
17 | function log::prefix::log {
18 | echo "log"
19 | }
20 | function log::prefix::debug {
21 | echo "debug"
22 | }
23 | function log::prefix::info {
24 | echo "info"
25 | }
26 | function log::prefix::ok {
27 | echo "ok"
28 | }
29 | function log::prefix::warn {
30 | echo "warn"
31 | }
32 | function log::prefix::err {
33 | echo "err"
34 | }
35 | function log::prefix::fatal {
36 | echo "fatal"
37 | }
38 |
39 | function log::format::log {
40 | echo "30;47"
41 | }
42 | function log::format::debug {
43 | echo "30;45"
44 | }
45 | function log::format::info {
46 | echo "30;46"
47 | }
48 | function log::format::ok {
49 | echo "30;42"
50 | }
51 | function log::format::warn {
52 | echo "30;43"
53 | }
54 | function log::format::err {
55 | echo "30;41"
56 | }
57 | function log::format::fatal {
58 | echo "30;41"
59 | }
60 |
--------------------------------------------------------------------------------
/utils/log/format/icons.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | test '[post-pass:require-fn=log::_format]'
4 | declare -gx __LOG_FORMAT="icons"
5 | declare -gx __LOG_PENDING_PAD=0
6 | test '[/post-pass:require-fn]'
7 |
8 | function log::_format
9 | {
10 | local ansi=$1 ; shift
11 | local icon=$1 ; shift
12 | printf "\033[%sm%s\033[22;39m %s\033[0m" "$ansi" "$icon" "$*"
13 | }
14 |
15 | function log::format::log {
16 | echo "0"
17 | }
18 | function log::format::debug {
19 | echo "1;35"
20 | }
21 | function log::format::info {
22 | echo "1;36"
23 | }
24 | function log::format::ok {
25 | echo "1;32"
26 | }
27 | function log::format::warn {
28 | echo "1;33"
29 | }
30 | function log::format::err {
31 | echo "1;31"
32 | }
33 | function log::format::fatal {
34 | echo "1;31"
35 | }
36 |
37 | function log::prefix::log {
38 | echo "+"
39 | }
40 | function log::prefix::debug {
41 | echo "d"
42 | }
43 | function log::prefix::info {
44 | echo "i"
45 | }
46 | function log::prefix::ok {
47 | echo "✓"
48 | }
49 | function log::prefix::warn {
50 | echo "!"
51 | }
52 | function log::prefix::err {
53 | echo "✘"
54 | }
55 | function log::prefix::fatal {
56 | echo "✘"
57 | }
58 |
--------------------------------------------------------------------------------
/utils/log/format/plain.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | test '[post-pass:require-fn=log::_format]'
4 | declare -gx __LOG_FORMAT="plain"
5 | declare -gx __LOG_PENDING_PAD=0
6 | test '[/post-pass:require-fn]'
7 |
8 | function log::_format
9 | {
10 | local ansi=$1 ; shift
11 | shift
12 | printf "\033[%sm%s\033[0m" "$ansi" "$*"
13 | }
14 |
15 | function log::format::log {
16 | echo "0"
17 | }
18 | function log::format::debug {
19 | echo "1;35"
20 | }
21 | function log::format::info {
22 | echo "1;36"
23 | }
24 | function log::format::ok {
25 | echo "1;32"
26 | }
27 | function log::format::warn {
28 | echo "1;33"
29 | }
30 | function log::format::err {
31 | echo "1;31"
32 | }
33 | function log::format::fatal {
34 | echo "1;31"
35 | }
36 |
37 | function log::prefix::log {
38 | :
39 | }
40 | function log::prefix::debug {
41 | :
42 | }
43 | function log::prefix::info {
44 | :
45 | }
46 | function log::prefix::ok {
47 | :
48 | }
49 | function log::prefix::warn {
50 | :
51 | }
52 | function log::prefix::err {
53 | :
54 | }
55 | function log::prefix::fatal {
56 | :
57 | }
58 |
--------------------------------------------------------------------------------
/utils/log/format/slim.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | test '[post-pass:require-fn=log::_format]'
4 | declare -gx __LOG_FORMAT="slim"
5 | declare -gx __LOG_TAG_FORMAT=1
6 | declare -gx __LOG_PENDING_PAD=1
7 | test '[/post-pass:require-fn]'
8 |
9 | function log::_format
10 | {
11 | local ansi="$1"; shift
12 | local tag="$1"; shift
13 | printf "\033[%sm ┃\033[0m %s" "$ansi" "$*"
14 | }
15 |
16 | function log::format::log {
17 | echo "2;37"
18 | }
19 | function log::format::debug {
20 | echo "1;35"
21 | }
22 | function log::format::info {
23 | echo "1;36"
24 | }
25 | function log::format::ok {
26 | echo "1;32"
27 | }
28 | function log::format::warn {
29 | echo "1;33"
30 | }
31 | function log::format::err {
32 | echo "1;31"
33 | }
34 | function log::format::fatal {
35 | echo "1;31"
36 | }
37 |
38 | function log::prefix::log {
39 | :
40 | }
41 | function log::prefix::debug {
42 | :
43 | }
44 | function log::prefix::info {
45 | :
46 | }
47 | function log::prefix::ok {
48 | :
49 | }
50 | function log::prefix::warn {
51 | :
52 | }
53 | function log::prefix::err {
54 | :
55 | }
56 | function log::prefix::fatal {
57 | :
58 | }
59 |
--------------------------------------------------------------------------------
/utils/log/format/tags.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | test '[post-pass:require-fn=log::_format]'
4 | declare -gx __LOG_FORMAT="tags"
5 | declare -gx __LOG_TAG_FORMAT=1
6 | declare -gx __LOG_TAG_PAD=5
7 | declare -gx __LOG_PENDING_PAD=3
8 | test '[/post-pass:require-fn]'
9 |
10 | function log::_format
11 | {
12 | local ansi=$1 ; shift
13 | local tag=$1 ; shift
14 |
15 | if [[ "$__LOG_TAG_FORMAT" -eq 2 ]]; then
16 | printf "\033[%sm%*s** \033[0m%s" "$ansi" "$__LOG_TAG_PAD" "" "$*"
17 | else
18 | printf "\033[%sm%*s \033[0;1;37m** \033[0m%s" "$ansi" "$__LOG_TAG_PAD" "$tag" "$*"
19 | fi
20 | }
21 |
22 | function log::format::log {
23 | echo "2;37"
24 | }
25 | function log::format::debug {
26 | echo "1;35"
27 | }
28 | function log::format::info {
29 | echo "1;36"
30 | }
31 | function log::format::ok {
32 | echo "1;32"
33 | }
34 | function log::format::warn {
35 | echo "1;33"
36 | }
37 | function log::format::err {
38 | echo "1;31"
39 | }
40 | function log::format::fatal {
41 | echo "1;31"
42 | }
43 |
44 | function log::prefix::log {
45 | echo "log"
46 | }
47 | function log::prefix::debug {
48 | echo "debug"
49 | }
50 | function log::prefix::info {
51 | echo "info"
52 | }
53 | function log::prefix::ok {
54 | echo "ok"
55 | }
56 | function log::prefix::warn {
57 | echo "warn"
58 | }
59 | function log::prefix::err {
60 | echo "err"
61 | }
62 | function log::prefix::fatal {
63 | echo "fatal"
64 | }
65 |
--------------------------------------------------------------------------------
/utils/log/log.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | include utils/ansi.sh
4 |
5 | function log::_format {
6 | shift
7 | shift
8 | printf "%s" "$*"
9 | }
10 |
11 | function log::debug {
12 | if ansi::check_support; then
13 | echo -e "$(log::_format "$(log::format::debug)" "$(log::prefix::debug)" "$@")"
14 | else
15 | echo "[debug] $*"
16 | fi
17 | }
18 |
19 | function log::info {
20 | if ansi::check_support; then
21 | echo -e "$(log::_format "$(log::format::info)" "$(log::prefix::info)" "$@")"
22 | else
23 | echo "[info] $*"
24 | fi
25 | }
26 |
27 | function log::ok {
28 | if ansi::check_support; then
29 | echo -e "$(log::_format "$(log::format::ok)" "$(log::prefix::ok)" "$@")"
30 | else
31 | echo "[ok] $*"
32 | fi
33 | }
34 |
35 | function log::warn {
36 | if ansi::check_support; then
37 | echo 1>&2 -e "$(log::_format "$(log::format::warn)" "$(log::prefix::warn)" "$@")"
38 | else
39 | echo "[warn] $*"
40 | fi
41 | }
42 |
43 | function log::err {
44 | if ansi::check_support; then
45 | echo 1>&2 -e "$(log::_format "$(log::format::err)" "$(log::prefix::err)" "$@")"
46 | else
47 | echo "[err] $*"
48 | fi
49 | }
50 |
51 | function log::fatal {
52 | if ansi::check_support; then
53 | echo 1>&2 -e "$(log::_format "$(log::format::fatal)" "$(log::prefix::fatal)" "$@")"
54 | else
55 | echo "[fatal] $*"
56 | fi
57 | }
58 |
59 | function log {
60 | if ansi::check_support; then
61 | echo -e "$(log::_format "$(log::format::log)" "$(log::prefix::log)" "$@")"
62 | else
63 | echo "$@"
64 | fi
65 | }
66 |
67 | function log::prompt {
68 | prompt="$(log "$@")"
69 | read -p "$prompt" -N 1 -r __LOG_PROMPT_VALUE
70 | }
71 |
--------------------------------------------------------------------------------
/utils/math.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Math utility functions for
4 | # jaagr
5 | #
6 |
7 | function math::min {
8 | (( $(math::float "$1" .0) < $(math::float "$2" .0) )) && echo "$1" || echo "$2"
9 | }
10 |
11 | function math::max {
12 | (( $(math::float "$1" .0) > $(math::float "$2" .0) )) && echo "$1" || echo "$2"
13 | }
14 |
15 | function math::float {
16 | printf "%${2:-.2}f" "$(echo "$1" | bc -l)"
17 | }
18 |
19 | function math::round {
20 | printf "%1.0f" "$(math::float "$1")"
21 | }
22 |
23 | function math::percentage {
24 | local value="$1"
25 | local total="$2"
26 | local decimals="$3"
27 | math::float "$(echo "${value} / ${total} * 100.0" | bc -l)" "${decimals}"
28 | }
29 |
30 | function math::percentage_of {
31 | local percentage="$1"
32 | local value="$2"
33 | local decimals="$3"
34 | math::float "$(echo "${percentage} * ${value} / 100.0" | bc -l)" "${decimals}"
35 | }
36 |
37 | function math::percentage_to_hex {
38 | printf "%02X" "$(math::round "$1 / 100.0 * 255.0")"
39 | }
40 |
41 | function math::bytes {
42 | math::round "$(echo "$1" | sed 's/.*/\L\0/;s/t/Xg/;s/g/Xm/;s/m/Xk/;s/k/X/;s/b//;s/X/ *1024/g')"
43 | }
44 |
--------------------------------------------------------------------------------
/utils/notification.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Interface for sending notifications using libnotify
4 | # jaagr
5 | #
6 |
7 | function notification::__send {
8 | local urgency="$1" ; shift
9 | /usr/bin/notify-send -u "$urgency" "$@"
10 | }
11 |
12 | function notification::low {
13 | notification::__send "low" "$@"
14 | }
15 |
16 | function notification::normal {
17 | notification::__send "normal" "$@"
18 | }
19 |
20 | function notification::critical {
21 | notification::__send "critical" "$@"
22 | }
23 |
--------------------------------------------------------------------------------
/utils/pipe.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility functions for managing named pipes
4 | # jaagr
5 | #
6 |
7 | pipe=""
8 |
9 | trap 'pipe::close' EXIT
10 |
11 | # fd=3
12 | # eval "exec $fd<> $fifo"
13 |
14 | function pipe::open
15 | {
16 | [ -z "$pipe" ] && {
17 | pipe=$(mktemp -u);
18 | }
19 | [ -p "$pipe" ] || {
20 | mkfifo "$pipe"
21 | exec 3<> "$pipe"
22 | }
23 | }
24 |
25 | function pipe::close
26 | {
27 | [ -p "$pipe" ] && {
28 | rm "$pipe"
29 | exec 3>&-
30 | }
31 | }
32 |
33 | function pipe::push
34 | {
35 | pipe::open
36 | echo "$@" >&3
37 | }
38 |
39 | function pipe::peek
40 | {
41 | read -r "$1" <&3
42 | }
43 |
44 | function pipe::tail
45 | {
46 | while read -r line <&3; do
47 | if [[ "$line" == "EOF" ]]; then
48 | break;
49 | fi
50 | echo "$line"
51 | done
52 | }
53 |
--------------------------------------------------------------------------------
/utils/polybar.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Polybar utility funtions
4 | # jaagr
5 | #
6 |
7 | include utils/_.sh
8 |
9 | function polybar::config_value
10 | {
11 | if [[ $# -lt 3 ]]; then
12 | _::stderr "parameters: config bar parameter [fallback]"; exit 1
13 | fi
14 |
15 | local config="$1"; shift
16 | local bar="$1"; shift
17 | local parameter="$1"; shift
18 | local fallback="$1"
19 |
20 | polybar "$bar" --config="$config" --dump="$parameter" 2>/dev/null || echo "$fallback"
21 | }
22 |
23 | function polybar::alignment
24 | {
25 | if [[ $# -lt 2 ]]; then
26 | _::stderr "parameters: config bar"; exit 1
27 | fi
28 |
29 | local config="$1"; shift
30 | local bar="$1"; shift
31 |
32 | if [[ "$(polybar::config_value "$config" "$bar" bottom)" == "true" ]]; then
33 | echo bottom
34 | else
35 | echo top
36 | fi
37 | }
38 |
39 | function polybar::wm_name
40 | {
41 | if [[ $# -lt 2 ]]; then
42 | _::stderr "parameters: config bar"; exit 1
43 | fi
44 |
45 | polybar "$2" --config="$1" --print-wmname 2>/dev/null
46 | }
47 |
48 | # shellcheck disable=2155
49 | function polybar::drawline
50 | {
51 | if [[ $# -lt 4 ]]; then
52 | _::stderr "parameters: config monitor bar color [offset_y=0] [height=1]"; return 1
53 | fi
54 |
55 | local config="$1"; shift
56 | local monitor="$1"; shift
57 | local bar="$1"; shift
58 | local color="$1"; shift
59 | local offset_y="${1:-0}"
60 | local height="${2:-1}"
61 | local align="$(polybar::alignment "$config" "$bar")"
62 | local wmname="$(polybar::wm_name "$config" "$bar")"
63 | local w=$(polybar::config_value "$config" "$bar" width 100%)
64 | local h=$(polybar::config_value "$config" "$bar" height 0)
65 | local x=$(polybar::config_value "$config" "$bar" offset-x 0)
66 | local y=$(polybar::config_value "$config" "$bar" offset-y 0)
67 | local bt=$(polybar::config_value "$config" "$bar" border-top 0)
68 | local bb=$(polybar::config_value "$config" "$bar" border-bottom 0)
69 |
70 | xdrawrect "$monitor" "$align" "$w" "$height" "$x" "$((h+y+bt+bb+offset_y))" "$color" "effectline-${monitor}-${align}" "$wmname"
71 | }
72 |
--------------------------------------------------------------------------------
/utils/proc.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Helper functions for running processes
4 | # jaagr
5 | #
6 |
7 | include utils/log/defer.sh
8 | include utils/spinner.sh
9 |
10 | function proc::wait
11 | {
12 | local pid="$1" ; shift
13 | local outbuf
14 | local -i num=0
15 |
16 | ansi::extend_buffer
17 |
18 | log::defer "${1:-waiting for pid} $(ansi::colorize "31" "$pid") $(ansi::save_position)"
19 |
20 | while [ -d "/proc/${pid}" ]; do
21 | ansi::restore_position
22 |
23 | spinner::get outbuf num "spin_11"
24 |
25 | echo -e "]──${outbuf} "
26 |
27 | sleep 0.15
28 | done
29 |
30 | ansi::restore_position
31 |
32 | log::defer::success "Process finished"
33 | }
34 |
35 | function proc::run_and_wait
36 | {
37 | "$SHELL" -c "$1" &
38 | proc::wait "$!"
39 | }
40 |
--------------------------------------------------------------------------------
/utils/runit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | include utils/log.sh
4 | include utils/log/defer.sh
5 | include utils/pipe.sh
6 |
7 | # TODO: remove
8 | DEFAULT_RUNSVDIR_PREFIX=/var/service
9 | DEFAULT_CONTAINER_ROOT=/etc/sv
10 |
11 | function runit::test_user_container
12 | {
13 | log::defer "Checking if user container is running..."
14 |
15 | if ! sudo sv status "${DEFAULT_RUNSVDIR_PREFIX}/usercontainer-$(whoami)" >/dev/null 2>&1; then
16 | log::defer::failure; return 1
17 | fi
18 |
19 | log::defer::success
20 | }
21 |
22 | function runit::is_service
23 | {
24 | local service=$1 ; shift
25 | local svroot
26 |
27 | [[ $# -gt 0 ]] && {
28 | svroot=$service
29 | service=$1
30 | }
31 |
32 | [[ "$service" ]] || {
33 | log::err "Service not specified"; exit 1
34 | }
35 |
36 | [[ "$service" ]] && [[ -e "${svroot:-$DEFAULT_CONTAINER_ROOT}/${service}" ]]
37 | }
38 |
39 | function runit::validate
40 | {
41 | local service="$1" ; shift
42 | local svroot
43 |
44 | [[ $# -gt 0 ]] && {
45 | svroot=$service
46 | service=$1
47 | }
48 |
49 | runit::is_service "${svroot:-$DEFAULT_CONTAINER_ROOT}" "$service" || {
50 | log::err "Service \"${service}\" does not exist"; exit 2
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/utils/spinner.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Utility library for creating spinners
4 | # jaagr
5 | #
6 |
7 | # Style constants {{{
8 |
9 | test '[post-pass:require-fn=spinner::get]'
10 | declare -g -r SPINNER_STYLE_DOTS_1=("⣷" "⣯" "⣟" "⡿" "⢿" "⣻" "⣽" "⣾")
11 | declare -g -r SPINNER_STYLE_DOTS_2=("⠁" "⠂" "⠄" "⡀" "⢀" "⠠" "⠐" "⠈")
12 |
13 | declare -g -r SPINNER_STYLE_SPIN_1=("←" "↖" "↑" "↗" "→" "↘" "↓" "↙")
14 | declare -g -r SPINNER_STYLE_SPIN_2=("b" "ᓂ" "q" "ᓄ")
15 | declare -g -r SPINNER_STYLE_SPIN_3=("d" "ᓇ" "p" "ᓀ")
16 | declare -g -r SPINNER_STYLE_SPIN_4=("|" "/" "—" "\\\\\\")
17 | declare -g -r SPINNER_STYLE_SPIN_5=("x" "+")
18 | declare -g -r SPINNER_STYLE_SPIN_6=("◰" "◳" "◲" "◱")
19 | declare -g -r SPINNER_STYLE_SPIN_7=("◴" "◷" "◶" "◵")
20 | declare -g -r SPINNER_STYLE_SPIN_8=("◐" "◓" "◑" "◒")
21 | declare -g -r SPINNER_STYLE_SPIN_9=("⠂" "⠄" "⠠" "⠐")
22 | declare -g -r SPINNER_STYLE_SPIN_10=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
23 | declare -g -r SPINNER_STYLE_SPIN_11=("🌕" "🌔" "🌓" "🌒" "🌑" "🌘" "🌗" "🌖")
24 |
25 | declare -g -r SPINNER_STYLE_GROW_1=("|" "b" "O" "b")
26 | declare -g -r SPINNER_STYLE_GROW_2=("_" "o" "O" "o")
27 | declare -g -r SPINNER_STYLE_GROW_3=("." "o" "O" "@" "*" " ")
28 | declare -g -r SPINNER_STYLE_GROW_4=("▁" "▂" "▃" "▄" "▅" "▆" "▇" "█" "▇" "▆" "▅" "▄" "▃" "▂")
29 | declare -g -r SPINNER_STYLE_GROW_5=("▉" "▊" "▋" "▌" "▍" "▎" "▏" "▎" "▍" "▌" "▋" "▊" "▉")
30 | declare -g -r SPINNER_STYLE_GROW_6=(" " "▏" "▎" "▍" "▌" "▋" "▊" "▉" "▉" "█" "▉" "▊" "▋" "▌" "▍" "▎" "▏")
31 |
32 | declare -g -r SPINNER_STYLE_MISC_1=("d" "|" "b" "|")
33 | declare -g -r SPINNER_STYLE_MISC_2=("q" "|" "p" "|")
34 | declare -g -r SPINNER_STYLE_MISC_3=("ᓂ" "—" "ᓄ" "—")
35 | declare -g -r SPINNER_STYLE_MISC_4=("ᓇ" "—" "ᓀ" "—")
36 | test '[/post-pass:require-fn]'
37 |
38 | # }}}
39 |
40 | function spinner::get
41 | {
42 | # reference variables to names
43 | # passed in as arguments
44 | local -n output=$1 ; shift
45 | local -n index=$1 ; shift
46 | local -u -n style=SPINNER_STYLE_${1:-dots_1} ; shift
47 |
48 | output=${style[$((index % ${#style[@]}))]}
49 | index+=1
50 | }
51 |
52 | function spinner::print
53 | {
54 | local buffer
55 | spinner::get buffer "$1" "$2"
56 | echo "$buffer"
57 | }
58 |
--------------------------------------------------------------------------------
/utils/str.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function str::unicode {
4 | printf "%b" "\u$1"
5 | }
6 |
7 | function str::upper {
8 | tr '[:lower:]' '[:upper:]' <<< "$@"
9 | }
10 |
11 | function str::lower {
12 | tr '[:upper:]' '[:lower:]' <<< "$@"
13 | }
14 |
15 | function str::trim {
16 | sed -r 's/^\s*(\S)|(\S*)\s*$/\1\2/g' <<< "$@"
17 | }
18 |
19 | function str::pad
20 | {
21 | local width="$1" ; shift
22 | local str="$1" ; shift
23 | printf "%*b" "$width" "$str"
24 | }
25 |
26 | function str::right {
27 | str::pad "$(tput cols)" "$@"
28 | }
29 |
30 | function str::center
31 | {
32 | local str cols rows
33 | str="$1" ; shift
34 | cols=$(tput cols)
35 | rows=$(tput lines)
36 | tput cup $(( rows / 2 )) $(( cols / 2 - ${#str} / 2 ))
37 | printf "%b" "${str}"
38 | }
39 |
40 | function str::shift_right
41 | {
42 | local -i width=$1
43 | local fill="${2:- }"
44 | local shift_str
45 |
46 | shift_str="$(printf "%*s" "$width" "$fill")"
47 | shift_str="${shift_str// /$fill}"
48 |
49 | while read -r line; do
50 | echo -e "${shift_str}${line}"
51 | done
52 | }
53 |
--------------------------------------------------------------------------------
/utils/testkit.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | include utils/log.sh
4 | include utils/log/defer.sh
5 |
6 | load utils/log/format/icons.sh
7 |
8 | export __LOG_TAG_PAD=3
9 |
10 | function testkit::equals
11 | {
12 | local input=$1
13 | local expected_result=$2
14 | local actual_result
15 |
16 | actual_result="$(eval "${input}" 2>/dev/null)"
17 |
18 | if [[ "${actual_result}" == "${expected_result}" ]]; then
19 | log::ok "${input} \e[2m=\e[0m ${expected_result}"
20 | else
21 | log::err "Test failed"
22 | echo -e "\e[2m Input\e[0m ${input}"
23 | echo -e "\e[2mExpected\e[0m ${expected_result}"
24 | echo -e "\e[2m Actual\e[0m ${actual_result}"
25 | fi
26 | }
27 |
28 | function testkit::match_strings
29 | {
30 | local str=$1
31 | local expected_str=$2
32 |
33 | if [[ "${str}" == "${expected_str}" ]]; then
34 | log::ok "${str} \e[2m=\e[0m matched the expected string"
35 | else
36 | log::err "Test failed"
37 | echo -e "\e[2mExpected\e[0m ${expected_str}"
38 | echo -e "\e[2mActual \e[0m ${str}"
39 | fi
40 | }
41 |
--------------------------------------------------------------------------------
/utils/tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function is_root {
4 | [[ "$(id -u)" -eq "0" ]]
5 | }
6 |
7 | function previous_cmd_successful {
8 | [[ "$?" -eq "0" ]]
9 | }
10 |
11 | function in_array
12 | {
13 | for item in $2; do
14 | [[ "${item}" = "$1" ]] && return 0
15 | done
16 | return 1
17 | }
18 |
--------------------------------------------------------------------------------
/utils/tests/algo.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/algo.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | testkit::equals "algo::luhn 551001253" "6"
13 | testkit::equals "algo::luhn 6602020015" "0"
14 | }
15 |
16 | main "$@"
17 |
--------------------------------------------------------------------------------
/utils/tests/ansi.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/ansi.sh
7 |
8 | bootstrap::finish
9 |
10 | # force ansi support
11 | function ansi::check_support {
12 | return 0
13 | }
14 |
15 | function main
16 | {
17 | testkit::equals "ansi::colorize 31 foobar" "$(echo -ne "\033[31mfoobar\033[0m")"
18 | testkit::equals "ansi::colorize 31 foo bar" "$(echo -ne "\033[31mfoo bar\033[0m")"
19 | testkit::equals "ansi::bold foobar" "$(echo -ne "\033[1mfoobar\033[0m")"
20 | testkit::equals "ansi::bold foo bar" "$(echo -ne "\033[1mfoo bar\033[0m")"
21 | testkit::equals "ansi::italic foobar" "$(echo -ne "\033[3mfoobar\033[0m")"
22 | testkit::equals "ansi::italic foo bar" "$(echo -ne "\033[3mfoo bar\033[0m")"
23 | testkit::equals "ansi::conceal foobar" "$(echo -ne "\033[8mfoobar\033[0m")"
24 | testkit::equals "ansi::conceal foo bar" "$(echo -ne "\033[8mfoo bar\033[0m")"
25 | testkit::equals "ansi::strikethrough foobar" "$(echo -ne "\033[9mfoobar\033[0m")"
26 | testkit::equals "ansi::strikethrough foo bar" "$(echo -ne "\033[9mfoo bar\033[0m")"
27 | }
28 |
29 | main "$@"
30 |
--------------------------------------------------------------------------------
/utils/tests/color.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/color.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | testkit::equals "color::brightness '#ffffff' 25" "#404040"
13 | testkit::equals "color::brightness '#ffffff' 100" "#ffffff"
14 | testkit::equals "color::brightness '#000000' 13" "#000000"
15 | testkit::equals "color::brightness '#f9213c' 100" "#f9213c"
16 | testkit::equals "color::brightness '#c89abd' 50" "#644d5e"
17 | testkit::equals "color::brightness '#000' 50" "#000000"
18 | testkit::equals "color::brightness '#pp' 50" ""
19 | }
20 |
21 | main "$@"
22 |
--------------------------------------------------------------------------------
/utils/tests/json.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/json.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | json=$(cat <<-EOF
13 | {
14 | \"x\": {
15 | \"real\": 1844,
16 | \"fake\": -5
17 | },
18 | \"y\": 547,
19 | \"width\": 677,
20 | \"height\": 504
21 | }
22 | EOF
23 | )
24 | json=${json// /}
25 | testkit::equals "json::get_value \"$json\" \"x.fake\"" "-5" | tr -d '\\\n'
26 | echo
27 | testkit::equals "json::get_value \"$json\" \"width\"" "677" | tr -d '\\\n'
28 | echo
29 | }
30 |
31 | main "$@"
32 |
--------------------------------------------------------------------------------
/utils/tests/math.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/math.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | testkit::equals "math::min 3 9" "3"
13 | testkit::equals "math::min 3.300 3.5" "3.300"
14 |
15 | testkit::equals "math::max 9 8" "9"
16 | testkit::equals "math::max 3.300 3.5" "3.5"
17 |
18 | testkit::equals "math::float '1 / 5'" "0.20"
19 | testkit::equals "math::float '1 / 5' 0.5" "0.20000"
20 |
21 | testkit::equals "math::round 1" "1"
22 | testkit::equals "math::round 3.25" "3"
23 | testkit::equals "math::round 5.893" "6"
24 |
25 | testkit::equals "math::percentage 3.25 50" "6.50"
26 | testkit::equals "math::percentage 25 100 .0" "25"
27 |
28 | testkit::equals "math::percentage_of 1 125 0.4" "1.2500"
29 | testkit::equals "math::percentage_of 80 10" "8.00"
30 | testkit::equals "math::percentage_of 120 10" "12.00"
31 |
32 | testkit::equals "math::percentage_to_hex 100" "FF"
33 | testkit::equals "math::percentage_to_hex 0" "00"
34 | }
35 |
36 | main "$@"
37 |
--------------------------------------------------------------------------------
/utils/tests/pipe.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/pipe.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | pipe::open
13 |
14 | pipe::push "value1"
15 | pipe::push "value2"
16 | pipe::push "value3"
17 |
18 | testkit::equals "pipe::peek 'tmp'; echo \$tmp" "value1"
19 | testkit::equals "pipe::peek 'tmp'; echo \$tmp" "value2"
20 |
21 | pipe::close
22 |
23 | testkit::equals "pipe::peek 'tmp'; echo \$tmp" ""
24 |
25 | pipe::open
26 |
27 | pipe::push "tail1"
28 | pipe::push "tail2"
29 | pipe::push "tail3"
30 | pipe::push "EOF"
31 |
32 | testkit::equals "tmp=\$(pipe::tail); echo \$tmp" "tail1 tail2 tail3"
33 |
34 | pipe::close
35 | }
36 |
37 | main "$@"
38 |
--------------------------------------------------------------------------------
/utils/tests/proc.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/proc.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | proc::run_and_wait "sleep 3 ; echo"
13 | }
14 |
15 | main "$@"
16 |
--------------------------------------------------------------------------------
/utils/tests/spinner.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/spinner.sh
7 |
8 | bootstrap::finish
9 |
10 | function test_name_ref_update
11 | {
12 | local a
13 | local -i b=0
14 | spinner::get a b misc_1
15 | echo "$a"
16 | }
17 |
18 | function test_name_ref_update2
19 | {
20 | local a
21 | local -i b=1
22 | spinner::get a b
23 | echo "$b"
24 | }
25 |
26 | function main
27 | {
28 | local -i frame=0
29 |
30 | # test that get() sets the output reference
31 | testkit::equals "test_name_ref_update" "d"
32 |
33 | # test that get() increments the index reference
34 | testkit::equals "test_name_ref_update2" "2"
35 |
36 | testkit::equals "spinner::print frame" "⣷"
37 | let frame++ # Fake the name ref update
38 |
39 | testkit::equals "spinner::print frame" "⣯"
40 | let frame++ # Fake the name ref update
41 |
42 | testkit::equals "spinner::print frame" "⣟"
43 | let frame++ # Fake the name ref update
44 |
45 | testkit::equals "spinner::print frame" "⡿"
46 |
47 |
48 | local buffer out
49 |
50 | let frame=0
51 | spinner::get out frame misc_2 q
52 | buffer+=$out
53 |
54 | let frame=4
55 | spinner::get out frame grow_3
56 | buffer+=$out
57 |
58 | testkit::match_strings "$buffer" "q*"
59 | }
60 |
61 | main "$@"
62 |
--------------------------------------------------------------------------------
/utils/tests/str.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source bootstrap.sh
4 |
5 | include utils/testkit.sh
6 | include utils/str.sh
7 |
8 | bootstrap::finish
9 |
10 | function main
11 | {
12 | testkit::equals "str::upper abc" "ABC"
13 | testkit::equals "str::upper 178abbb%" "178ABBB%"
14 |
15 | testkit::equals "str::lower ABC" "abc"
16 | testkit::equals "str::lower 178ABBB%" "178abbb%"
17 |
18 | testkit::equals 'echo -e "1\n2" | str::shift_right 2' "$(echo -e " 1\n 2")"
19 | testkit::equals 'echo -e "1\n2\n3" | str::shift_right 3 "a"' "$(echo -e "aaa1\naaa2\naaa3")"
20 | }
21 |
22 | main "$@"
23 |
--------------------------------------------------------------------------------
/utils/x11.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # x11 utility functions
4 | # jaagr
5 |
6 | function x11::monitor_connected {
7 | xrandr --query | grep -q "^$1 connected" || \
8 | xrandr --query | grep -q "^${1//-/} connected"
9 | }
10 |
11 | function x11::monitor_geom {
12 | xrandr --query \
13 | | egrep "^$1 (dis)?connected" \
14 | | egrep -o "[0-9]+x[0-9]+\+[0-9]*\+[0-9]*"
15 | }
16 |
17 | function x11::wmname_win {
18 | 2>/dev/null xwininfo -name "$1" \
19 | | sed -nr "/Window id/s/.*0x([[:xdigit:]]+).*/\1/p" \
20 | | xargs -r printf "0x%8s\n" \
21 | | tr " " "0"
22 | }
23 |
24 | function x11::root_win {
25 | 2>/dev/null xwininfo -root \
26 | | sed -nr "/Window id/s/.*(0x[[:xdigit:]]+).*/\1/p" \
27 | | xargs -r printf "0x%8s\n" \
28 | | tr " " "0"
29 | }
30 |
31 | # In bspwm, the root window for the specified monitor
32 | # can be matched against a window with the same geometry
33 | # and WM_CLASS instance set to "root"
34 | function x11::root_win_bspwm {
35 | if x11::monitor_connected "$1"; then
36 | xwininfo -root -children \
37 | | grep "root.*[bB]spwm" \
38 | | grep "$(x11::monitor_geom "$1")" \
39 | | sed -nr "s/^[ ]+ 0x([[:xdigit:]]+).*/\1/p" \
40 | | xargs -r printf "0x%8s\n" \
41 | | tr " " "0"
42 | fi
43 | }
44 |
45 | # In i3, the root window for the specified monitor
46 | # can be matched against the wm_name "[i3 con] output ${monitor}"
47 | function x11::root_win_i3 {
48 | if x11::monitor_connected "$1"; then
49 | x11::wmname_win "[i3 con] output $1"
50 | fi
51 | }
52 |
--------------------------------------------------------------------------------