lcdproc-0.5.9/0000755000175100017510000000000013121562647010165 500000000000000lcdproc-0.5.9/install-sh0000755000175100017510000003413713037436401012113 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) # $RANDOM is not portable (e.g. dash); use it when possible to # lower collision chance tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 # As "mkdir -p" follows symlinks and we work in /tmp possibly; so # create the $tmpdir first (and fail if unsuccessful) to make sure # that nobody tries to guess the $tmpdir name. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: lcdproc-0.5.9/depcomp0000755000175100017510000005601613037436407011472 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: lcdproc-0.5.9/TODO0000644000175100017510000000425612505300405010567 00000000000000NOTE: Use of this TODO list is obsolete! A list of things to be done is automatically created by Doxygen. You may create the Doxygen documentation yourself by running the doxygen command from the docs/ directory. Ideas for new features can be entered at the IdeaTorrent: http://sourceforge.net/apps/ideatorrent/lcdproc/ ------------------------------------------------------------------------------ Stuff planned for future releases... (in no particular order) Feel free to help out with any of this stuff! :) Please send a message to the mailing list if you have any question. Things for the short term ========================= - Use non-standard serial baud rates (57600 and higher) only optional. Things for the longer term ========================== lcdproc client -------------- - allow more than one instance of a screen with different configuration sections (implementation should be possible similar to the one with the drivers in LCDd where File=... points to the original driver file) - more options in the config file (clocks with offsets from localtime, ...) - more options changeable in the lcdproc client menu - rewrite machine_get_fs() in machine_Linux.c to use functions from mntent.h - get rid of MTAB_FILE compile time definition (for Linux & SunOS) lcdexec client -------------- more flexbibility: do not just only execute commands, but maybe also display their result in a screen, get a command's parameters interactively using the builtin input menus, confirmation of commands, jumping between commands depending on the output of a command (wizards), ... Client driver ------------- An LCDproc client can connect, request the "client" driver, then get all screen information sent to it! This allows things such as logging in remotely and starting up a curses display of LCDproc. It also gives another method for writing drivers. In a sense, it could even let you write and link in new drivers without having to recompile and restart LCDproc... Another bonus is that LCDproc will come with a client which can, for example, start up a "client" driver to send "keypresses" from the command line. Or, lcdtool -key A would have the same result as pressing a key on the keypad. lcdproc-0.5.9/scripts/0000755000175100017510000000000013121562650011646 500000000000000lcdproc-0.5.9/scripts/init-lcdproc.rpm.in0000644000175100017510000000430312505300405015273 00000000000000#!/bin/sh # This is the lcdproc init-script for RPM based (RedHat, Mandrake) systems # # Copyright (C) 2001 Rene Wagner # 2001 Guillaume Filion # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # any later version. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this file; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # # # chkconfig: 345 71 20 # description: LCDd(8) is the LCDproc server used for displaying text and other data to LCDs. \ # Apart from the main client lcdproc(1) there are various clients. \ # See http://lcdproc.omnipotent.net for details. # processname: lcdproc # pidfile: /var/run/lcdproc.pid # config: /etc/sysconfig/lcdproc # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. if [ ${NETWORKING} = "no" ]; then exit 0 fi RETVAL=0 prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ lcdproc=${bindir}/lcdproc [ -x ${lcdproc} ] || exit 0 start() { echo -n "Starting up lcdproc: " daemon ${lcdproc} $SCREENS RETVAL=$? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/lcdproc echo } stop() { echo -n "Shutting down lcdproc: " killproc lcdproc RETVAL=$? [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/lcdproc echo } dostatus() { status lcdproc RETVAL=$? } restart() { stop start RETVAL=$? } condrestart() { [ -e /var/lock/subsys/lcdproc ] && restart || : } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) dostatus ;; restart) restart ;; condrestart) condrestart ;; *) echo "Usage: $0 {start|stop|status|restart|condrestart}" exit 1 esac exit $RETVAL lcdproc-0.5.9/scripts/init-LCDd.rpm.in0000644000175100017510000000424012505300405014413 00000000000000#!/bin/sh # This is the LCDd init-script for RPM based (RedHat, Mandrake) systems # # Copyright (C) 2001 Rene Wagner # 2001 Guillaume Filion # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # any later version. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this file; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # # # chkconfig: 345 70 21 # description: LCDd(8) is the LCDproc server used for displaying text and other data to LCDs. \ # Apart from the main client lcdproc(1) there are various clients. \ # See http://lcdproc.omnipotent.net for details. # processname: LCDd # config: @sysconfdir@/LCDd.conf # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. if [ ${NETWORKING} = "no" ]; then exit 0 fi RETVAL=0 prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ LCDd=${sbindir}/LCDd configfile=${etc}/LCDd.conf [ -x ${LCDd} ] || exit 0 start() { echo -n "Starting up LCDd: " daemon ${LCDd} -c ${configfile} RETVAL=$? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/LCDd echo } stop() { echo -n "Shutting down LCDd: " killproc LCDd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/LCDd echo } dostatus() { status LCDd RETVAL=$? } restart() { stop start RETVAL=$? } condrestart() { [ -e /var/lock/subsys/LCDd ] && restart || : } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) dostatus ;; restart) restart ;; condrestart) condrestart ;; *) echo "Usage: $0 {start|stop|status|restart|condrestart}" exit 1 esac exit $RETVAL lcdproc-0.5.9/scripts/init-lcdvc.LSB.in0000644000175100017510000000253112505300405014563 00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: lcdvc # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Should-Start: LCDd # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc virtual console # Description: LSB init script for lcdvc, the virtual # console client in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ PATH=/sbin:/bin:/usr/sbin:/usr/bin NAME=lcdvc DAEMON=${bindir}/$NAME DESC="LCDproc virtual console" DEFAULTS=/etc/default/$NAME START=no # Source defaults file; edit that file to configure this script. if [ -e "${DEFAULTS}" ]; then . "${DEFAULTS}" fi # If we're not to start the daemon, simply exit if [ "${START}" != "yes" ]; then exit 0 fi # installation check test -x $DAEMON || exit 5 # load LSB 3.x init functions . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" start_daemon $DAEMON $OPTIONS log_end_msg $? ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" killproc $DAEMON log_end_msg $? ;; restart|reload|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|restart|reload|force-reload}" >&2 exit 2 ;; esac exit 0 lcdproc-0.5.9/scripts/init-lcdproc.LSB.in0000644000175100017510000000260112505300405015114 00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: lcdproc # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Should-Start: LCDd # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc system status information viewer # Description: LSB init script for lcdproc, the system # status information viewer in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ PATH=/sbin:/bin:/usr/sbin:/usr/bin NAME=lcdproc DAEMON=${bindir}/$NAME DESC="LCDproc system status monitor" DEFAULTS=/etc/default/$NAME START=yes # Source defaults file; edit that file to configure this script. if [ -e "${DEFAULTS}" ]; then . "${DEFAULTS}" fi # If we're not to start the daemon, simply exit if [ "${START}" != "yes" ]; then exit 0 fi # installation check test -x $DAEMON || exit 5 # load LSB 3.x init functions . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" start_daemon $DAEMON $OPTIONS log_end_msg $? ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" killproc $DAEMON log_end_msg $? ;; restart|reload|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|restart|reload|force-reload}" >&2 exit 2 ;; esac exit 0 lcdproc-0.5.9/scripts/Makefile.am0000644000175100017510000000060313041134720013613 00000000000000## Process this file with automake to produce Makefile.in EXTRA_DIST = README \ init-LCDd.LSB.in \ init-lcdproc.LSB.in \ init-lcdexec.LSB.in \ init-lcdvc.LSB.in \ init-LCDd.debian.in \ init-lcdproc.debian.in \ init-lcdexec.debian.in \ init-lcdvc.debian.in \ init-LCDd.rpm.in \ init-lcdproc.rpm.in ## EOF lcdproc-0.5.9/scripts/init-LCDd.debian.in0000644000175100017510000000207112505300405015037 00000000000000#!/bin/sh -e ### BEGIN INIT INFO # Provides: LCDd # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc Server Daemon # Description: Debian init script for LCDd, the display # server daemon in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ NAME=LCDd DAEMON=${sbindir}/${NAME} DESC="LCDproc display server daemon" OPTIONS="" # installation check test -x ${DAEMON} || exit 0 case "$1" in start) printf "Starting ${DESC}: " start-stop-daemon --start --quiet --exec ${DAEMON} -- ${OPTIONS} printf "${NAME}.\n" ;; stop) printf "Stopping ${DESC}: " start-stop-daemon --stop --oknodo --quiet --exec ${DAEMON} printf "${NAME}.\n" ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) printf "Usage: $0 {start|stop|restart|force-reload}\n" >&2 exit 1 ;; esac exit 0 lcdproc-0.5.9/scripts/init-lcdexec.debian.in0000644000175100017510000000214212505300405015677 00000000000000#!/bin/sh -e ### BEGIN INIT INFO # Provides: lcdexec # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc program starter from the LCDd menu # Description: Debian init script for lcdexec, the client to # start programs from the LCDd menu in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ NAME=lcdexec DAEMON=${bindir}/${NAME} DESC="LCDproc program starter" OPTIONS="" # installation check test -x ${DAEMON} || exit 0 case "$1" in start) printf "Starting ${DESC}: " start-stop-daemon --start --quiet --exec ${DAEMON} -- ${OPTIONS} printf "${NAME}." ;; stop) printf "Stopping ${DESC}: " start-stop-daemon --stop --oknodo --quiet --exec ${DAEMON} printf "${NAME}." ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) printf "Usage: $0 {start|stop|restart|force-reload}\n" >&2 exit 1 ;; esac exit 0 lcdproc-0.5.9/scripts/init-lcdproc.debian.in0000644000175100017510000000213712505300405015722 00000000000000#!/bin/sh -e ### BEGIN INIT INFO # Provides: lcdproc # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc system status information viewer # Description: Debian init script for lcdproc, the system # status information viewer in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ NAME=lcdproc DAEMON=${bindir}/${NAME} DESC="LCDproc system status monitor" OPTIONS="" # installation check test -x ${DAEMON} || exit 0 case "$1" in start) printf "Starting ${DESC}: " start-stop-daemon --start --quiet --exec ${DAEMON} -- ${OPTIONS} printf "${NAME}.\n" ;; stop) printf "Stopping ${DESC}: " start-stop-daemon --stop --oknodo --quiet --exec ${DAEMON} printf "${NAME}.\n" ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) printf "Usage: $0 {start|stop|restart|force-reload}\n" >&2 exit 1 ;; esac exit 0 lcdproc-0.5.9/scripts/init-lcdvc.debian.in0000644000175100017510000000206412505300405015366 00000000000000#!/bin/sh -e ### BEGIN INIT INFO # Provides: lcdvc # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc virtual console # Description: Debian init script for lcdvc, the virtual # console client in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ NAME=lcdvc DAEMON=${bindir}/${NAME} DESC="LCDproc virtual console" OPTIONS="" # installation check test -x ${DAEMON} || exit 0 case "$1" in start) printf "Starting ${DESC}: " start-stop-daemon --start --quiet --exec ${DAEMON} -- ${OPTIONS} printf "${NAME}." ;; stop) printf "Stopping ${DESC}: " start-stop-daemon --stop --oknodo --quiet --exec ${DAEMON} printf "${NAME}." ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) printf "Usage: $0 {start|stop|restart|force-reload}\n" >&2 exit 1 ;; esac exit 0 lcdproc-0.5.9/scripts/init-lcdexec.LSB.in0000644000175100017510000000260712505300405015103 00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: lcdexec # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Should-Start: LCDd # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc program starter from the LCDd menu # Description: LSB init script for lcdexec, the client to # start programs from the LCDd menu in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ PATH=/sbin:/bin:/usr/sbin:/usr/bin NAME=lcdexec DAEMON=${bindir}/$NAME DESC="LCDproc program starter" DEFAULTS=/etc/default/$NAME START=no # Source defaults file; edit that file to configure this script. if [ -e "${DEFAULTS}" ]; then . "${DEFAULTS}" fi # If we're not to start the daemon, simply exit if [ "${START}" != "yes" ]; then exit 0 fi # installation check test -x $DAEMON || exit 5 # load LSB 3.x init functions . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" start_daemon $DAEMON $OPTIONS log_end_msg $? ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" killproc $DAEMON log_end_msg $? ;; restart|reload|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|restart|reload|force-reload}" >&2 exit 2 ;; esac exit 0 lcdproc-0.5.9/scripts/init-LCDd.LSB.in0000644000175100017510000000253312505300405014240 00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: LCDd # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Should-Start: udev # Default-Start: 2 3 4 5 # Default-Stop: S 0 1 6 # Short-Description: LCDproc Server Daemon # Description: LSB init script for LCDd, the display # server daemon in the LCDproc suite ### END INIT INFO # local variables prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ etc=@sysconfdir@ PATH=/sbin:/bin:/usr/sbin:/usr/bin NAME=LCDd DAEMON=${sbindir}/$NAME DESC="LCDproc display server daemon" DEFAULTS=/etc/default/$NAME START=yes # Source defaults file; edit that file to configure this script. if [ -e "${DEFAULTS}" ]; then . "${DEFAULTS}" fi # If we're not to start the daemon, simply exit if [ "${START}" != "yes" ]; then exit 0 fi # installation check test -x $DAEMON || exit 5 # load LSB 3.x init functions . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" start_daemon $DAEMON $OPTIONS log_end_msg $? ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" killproc $DAEMON log_end_msg $? ;; restart|reload|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|restart|reload|force-reload}" >&2 exit 2 ;; esac exit 0 lcdproc-0.5.9/scripts/README0000644000175100017510000000136713041151565012455 00000000000000This directory contains * init-script templates for various system types (These templates are adapted to the confugration parameters passed to configure at configure-run-time.) - init-*.LSB.in templates for systems conforming to LSB (Linux Standard Base) 3.x. Among others the following distributions support LSB 3.x: - SuSE Linux 10.x - SuSE Linux Enterprise Server 10 - SuSE Linux Enterprise Server 9 SP3 - Ubuntu 6.06 - Debian Etch - RedHat Enterprise Linux4 Update2 - init-*.debian.in templates for older Debian systems (or modern Debian systems without the lsb-core package installed) - init-*.rpm init-scripts for RPM based distributions that are not LSB 3.x conforming. Please try the LSB scripts first. lcdproc-0.5.9/missing0000755000175100017510000001533013037436402011501 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: lcdproc-0.5.9/CREDITS.md0000644000175100017510000002163413117601626011526 00000000000000# Introduction LCDproc wouldn't have been possible without the efforts and work of many dedicated enthusiasts and dabblers who have contributed to its development over the years. We acknowledge their contributions here. Please help us keeping this file up to date. If you're submitting a pull request for the project, be sure to update this file to include yourself if you're not already listed. Include a brief bio if you'd like, and be sure to highlight the contributions you've made to the project. It's your spotlight! If you're absent, misattributed or your name and/or contact information is inaccurate, please let us know (or submit a pull request to fix it)! If you'd like to be removed from this file for some reason, please let us know so we can take care of it. You're also welcome to list only your name (or profile name) with no email address or other contact information as well. We love putting our contributors' names up in lights, but we're flexible :) # Contributors (listed in order of appearance) - [William Ferrell (willfe)](mailto:willfe@gmail.com) - Project founder, author of first versions and much documentation, design for V0.4, "benevolent dictator for life" (to shamelessly borrow a page from Linus Torvald's playbook). > It's willfe's fault that LCDproc exists. He wanted his computer to have a heartbeat, like some HP workstations and servers do. So he found a nice LCD, wrote some amazingly spiffy software for it, and life was good. - [Selene Scriven (ToyKeeper)](mailto:lcdproc@toykeeper.net) - Wrote V0.3 and most of V0.4, and helped procrastinate the rest of the time... > ToyKeeper was the main programmer for LCDproc 0.2 - 0.4-pre9. She took willfe's idea and put it in its current form. - Gareth Watts (Xeno42) - Patches, mailing list, ideas, web hosting, CVS, etc. - [Matrix Orbital Corporation](http://www.matrixorbital.com/) - Free displays for many of the developers, and immeasurable help (especially early on). - [Crystalfontz America, Inc.](http://www.crystalfontz.com/) - Sends us sample/test units to get LCDproc running on all their models - Rescued the lcdproc.org/com/net domains when their registrations expired and they were "ransomed" by a domain squatter - [Lorand Bruhacs](mailto:bruhacs@ip23.net) - Developed LCDproc v0.3.5, which added lots of nifty stuff while keeping the old program model - [Benjamin Tse](mailto:blt@Comports.com), [Matthias Prinke](mailto:m.prinke@trashcan.mcnet.de) - HD44780 driver and predecessors - [Richard Rognlie](mailto:rrognlie@gamerz.net) - Work on HD44780 driver - GIF driver (lost code) - Tom Wheeley - IRMan input driver - Bjoern Andersson - Autoconf/automake build system - Curses driver - [Andrew McMeikan](mailto:andrewm@engineer.com) - HD44780 driver - David Glaude - Lirc driver (not the current version) - IRMAN driver, - lcdproc big clocK screen. - Matrix Orbital enhancement: Big Number, general-purpose output, dynamic custom char allocation, i2c support (lost) - Crystal Fontz drivers - Matrix orbital GLK driver - Todd Porter - Windows 95/98 and NT version - Jason Dale Woodward - widget scrolling - Ethan Dicks - PIC-an-LCD original driver (later merged into HD44780 driver) - fixes & tests to the MtxOrb driver and some clients - lcdident.pl client - Michael Reinelt - SED1520 (copied work of him) - Simon Harrison - SVGAlib driver - Horizon Technologies - WIRZ-SLI driver - Charles Steinkuehler - Work on HD44780 timing code - Harald Klein - Lirc driver (initial version of the current code) - Metar Client - Philip Pokorny - Crystal Fontz driver - Matrix Orbital driver - Matrix Orbital GLK driver - Curses driver - Glen Gray - David Douthitt - Crystal Fontz driver - Matrix Orbital driver - Matrix Orbital GLK driver - Curses driver - Eddie Sheldrake - Crystal Fontz driver - Rene Wagner - LCDM001 driver - ASCII emulation of BigNum - CFontz v2.0 patches merging, - LIRC driver updates (new API, merged David's code) - Lots of driver updates for v0.4.3 (configfile, reporting): - CFontz - curses - glk - MtxOrb - EPM list file for automatic package generation, - current documentation in docbook format - v0.4.3 backlight and heartbeat implementation - Lots of other stuff for the v0.4.3 release - Andre Breiler - Matrix Orbital driver - Joris Robijn - HD44780 driver maintenance and enhancement - Config file stuff - Reporting stuff - Work on API v0.5 architecture and implementation, loadable drivers. - Menu stuff of v0.5 - SED1330 driver - Guillaume Filion - Portability bug fixes on the curses, HD44780, SED1520 and STV5730 drivers. - Partially implemented Thomas Runge's BSD port of lcdproc. - Ported the parallel functions in port.h to BSD. - Autoconf/automake stuff. - Various small 0.4.3 changes. - Chris Debenham - Matrix Orbital GLK driver - LB216 driver - Mark Haemmerling - HD44780 character conversion table - Robin Adams - SED1520 driver - STV5730 driver - Manuel Stahl - T6963 driver - Mike Patnode - Crystal Fontz - Various 0.4.3 changes - Peter Marschall - new drivers: IOWarrior, xosdlib - bwctusb connectiontype for the HD44780 driver - extensions to CFontz* drivers: support CF631 & CF635 - various fixes in preparation of 0.5 - lcd2usb connectiontype for the HD44780 driver - Markus Dolze - project maintainer - various fixes (especially for *BSD) - merged and extended network interface statistics to lcdproc client - new LCDd network input buffering - Volker Boerchers - fixes and extensions to the menu system - Lucian Muresan - glcdlib meta driver - Matteo Pillon - lcdserializer connectiontype to the hd44780 driver - various improvements to the serial connections of the hd44780 driver - Laurent Arnal - connectiontype for LIS2 displays from VLSystem (http://www.vlsys.co.kr) - Simon Funke - driver for Noritake VFD - Matthias Goebl - I2C connectiontype for the HD44780 driver - Stefan Herdler - serialVFD driver - bignum library - Bernhard Walle - driver for the ULA-200 device from ELV (http://www.elv.de) - Andrew Foss - menu support for lcdproc client - Anthony J. Mirabella - Logitech g15 driver - Cedric Tessier - EyeBoxOne driver - John Sanders - iMon driver graphics support - Eric Pooch - Mac OS X / Darwin support - serialPOS driver - uss720 connection type for hd44780 driver - driver for SoundGraph iMON OEM LCD Modules - Benjamin Wiedmann - Added functionality for HITACHI SP14Q002 gLCD (320x240) - Implemented dynamic wiring scheme selection for SED1330 driver ("ConnectionType") - Frank Jepsen - vdr-wakeup support in hd44780 driver (originally for v0.4.5) - new options for the hd44780 driver - Karsten Festag - ea65 driver - Gatewood Green - picolcd driver - Dave Platt - overhauled CwLnx driver - Nicu Pavel - overhauled & extended picolcd driver - Daryl Fonseca-Holt - lis driver - Thien Vu - shuttleVFD driver - Thomas Jarosch - support reporting in hd44780's ConnectionType functions - build-system clean up: use pkg-config for some libs - HD44780 connection type for a USB connection via a FTDI FT2232D chip - i2500vfd driver - Christian Jodar - mx5000 driver - Mariusz Bialonczyk - ethlcd connection type for HD44780 - Jack Cleaver - LIRC support in picolcd - Aron Parsons (Phant0m) -IRtrans driver - Malte Poeggel - support for ST7036 controller in hd44780 - Dean Harding, Christian Leuschen, Jonathan Kyler - driver for SoundGraph iMON OEM LCD Modules - Laurent Latil - SureElec driver for devices made by SURE Electronics - Christoph Rasim - MDM166A driver for Futaba/Targa USB VFD - bjo81 - Driver for lcm162-module (by H. Rasch) (https://github.com/lcdproc/lcdproc/pull/6) - [Harald Geyer](http://friends.ccbib.org/harald/supporting/) - Driver for the linux input subsystem - Driver and font for Olimex MOD-LCD1x9 14 segment display - Various minor and not-so-minor cleanups and fixes - M. Feser and R. Geigenberger - Driver for YARD2 display devices - Colin Munro (colinmunro) - Shane Spencer (hardwire) - Jim McCracken (merlin_jim) - Luis Llorente (luisllo) - [Sam Bingner](mailto:sam@bingner.com) - Updated icp_a106 driver to support icp_a125 used in QNAP devices and to add button support - [Fatih Aşıcı](mailto:fatih.asici@gmail.com) - Driver for hd44780 connection type using linux GPIO interface - Guillaume Membré - Documentation updates - [Alex Wood](mailto:thetewood@gmail.com) - Driver for the Futaba TOSD-5711BB VFDisplay on Elonex Artisan/Scaleo/FIC Spectra Media Cenre PCs amoungst others - [Francois Mertz](mailto:fireboxled@gmail.com) - Parallel Port LCD driver for the Watchguard/Lanner firewall appliances (sdeclcd) - Supplemented HD44780 serial driver to support Portwell EZIO-100 and EZIO-300 LCDs found in Portwell, Caswell and Check Point firewall appliances lcdproc-0.5.9/LCDd.conf0000644000175100017510000011503713076230100011512 00000000000000# LCDd.conf -- configuration file for the LCDproc server daemon LCDd # # This file contains the configuration for the LCDd server. # # The format is ini-file-like. It is divided into sections that start at # markers that look like [section]. Comments are all line-based comments, # and are lines that start with '#' or ';'. # # The server has a 'central' section named [server]. For the menu there is # a section called [menu]. Further each driver has a section which # defines how the driver acts. # # The drivers are activated by specifying them in a driver= line in the # server section, like: # # Driver=curses # # This tells LCDd to use the curses driver. # The first driver that is loaded and is capable of output defines the # size of the display. The default driver to use is curses. # If the driver is specified using the -d command line option, # the Driver= options in the config file are ignored. # # The drivers read their own options from the respective sections. ## Server section with all kinds of settings for the LCDd server ## [server] # Where can we find the driver modules ? # IMPORTANT: Make sure to change this setting to reflect your # specific setup! Otherwise LCDd won't be able to find # the driver modules and will thus not be able to # function properly. # NOTE: Always place a slash as last character ! DriverPath=server/drivers/ # Tells the server to load the given drivers. Multiple lines can be given. # The name of the driver is case sensitive and determines the section # where to look for further configuration options of the specific driver # as well as the name of the dynamic driver module to load at runtime. # The latter one can be changed by giving a File= directive in the # driver specific section. # # The following drivers are supported: # bayrad, CFontz, CFontzPacket, curses, CwLnx, ea65, EyeboxOne, futaba, # g15, glcd, glcdlib, glk, hd44780, icp_a106, imon, imonlcd,, IOWarrior, # irman, joy, lb216, lcdm001, lcterm, linux_input, lirc, lis, MD8800, # mdm166a, ms6931, mtc_s16209x, MtxOrb, mx5000, NoritakeVFD, # Olimex_MOD_LCD1x9, picolcd, pyramid, rawserial, sdeclcd, sed1330, # sed1520, serialPOS, serialVFD, shuttleVFD, sli, stv5730, svga, t6963, # text, tyan, ula200, vlsys_m428, xosd, yard2LCD Driver=curses # Tells the driver to bind to the given interface. [default: 127.0.0.1] Bind=127.0.0.1 # Listen on this specified port. [default: 13666] Port=13666 # Sets the reporting level; defaults to warnings and errors only. # [default: 2; legal: 0-5] #ReportLevel=3 # Should we report to syslog instead of stderr? [default: no; legal: yes, no] #ReportToSyslog=yes # User to run as. LCDd will drop its root privileges and run as this user # instead. [default: nobody] User=nobody # The server will stay in the foreground if set to yes. # [default: no, legal: yes, no] #Foreground=yes # Hello message: each entry represents a display line; default: builtin #Hello=" Welcome to" #Hello=" LCDproc!" # GoodBye message: each entry represents a display line; default: builtin #GoodBye="Thanks for using" #GoodBye=" LCDproc!" # Sets the interval in microseconds for updating the display. # [default: 125000 meaning 8Hz] #FrameInterval=125000 # Sets the default time in seconds to displays a screen. [default: 4] WaitTime=5 # If set to no, LCDd will start with screen rotation disabled. This has the # same effect as if the ToggleRotateKey had been pressed. Rotation will start # if the ToggleRotateKey is pressed. Note that this setting does not turn off # priority sorting of screens. [default: on; legal: on, off] #AutoRotate=off # If yes, the the serverscreen will be rotated as a usual info screen. If no, # it will be a background screen, only visible when no other screens are # active. The special value 'blank' is similar to no, but only a blank screen # is displayed. [default: on; legal: on, off, blank] #ServerScreen=no # Set master backlight setting. If set to 'open' a client may control the # backlight for its own screens (only). [default: open; legal: off, open, on] #Backlight=open # Set master heartbeat setting. If set to 'open' a client may control the # heartbeat for its own screens (only). [default: open; legal: off, open, on] #Heartbeat=open # set title scrolling speed [default: 10; legal: 0-10] #TitleSpeed=10 # The "...Key=" lines define what the server does with keypresses that # don't go to any client. The ToggleRotateKey stops rotation of screens, while # the PrevScreenKey and NextScreenKey go back / forward one screen (even if # rotation is disabled. # Assign the key string returned by the driver to the ...Key setting. These # are the defaults: ToggleRotateKey=Enter PrevScreenKey=Left NextScreenKey=Right #ScrollUpKey=Up #ScrollDownKey=Down ## The menu section. The menu is an internal LCDproc client. ## [menu] # If true the server allows transitions between different client's menus # [default: false; legal: true, false] #PermissiveGoto=false # You can configure what keys the menu should use. Note that the MenuKey # will be reserved exclusively, the others work in shared mode. # Up to six keys are supported. The MenuKey (to enter and exit the menu), the # EnterKey (to select values) and at least one movement keys are required. # These are the default key assignments: MenuKey=Escape EnterKey=Enter UpKey=Up DownKey=Down #LeftKey=Left #RightKey=Right ### Driver sections are below this line, in alphabetical order ### ## EMAC BayRAD driver ## [bayrad] # Select the output device to use [default: /dev/lcd] Device=/dev/lcd # Set the communication speed [default: 9600; legal: 1200, 2400, 9600, 19200] Speed=9600 ## CrystalFontz driver (for CF632 & CF634) ## [CFontz] # Select the output device to use [default: /dev/lcd] Device=/dev/ttyS0 # Select the LCD size [default: 20x4] Size=20x4 # Set the initial contrast [default: 560; legal: 0 - 1000] Contrast=350 # Set the initial brightness [default: 1000; legal: 0 - 1000] Brightness=1000 # Set the initial off-brightness [default: 0; legal: 0 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive OffBrightness=0 # Set the communication speed [default: 9600; legal: 1200, 2400, 9600, 19200, # 115200] Speed=9600 # Set the firmware version (New means >= 2.0) [default: no; legal: yes, no] NewFirmware=no # Reinitialize the LCD's BIOS [default: no; legal: yes, no] # normally you shouldn't need this Reboot=no ## CrystalFontz packet driver (for CFA533, CFA631, CFA633 & CFA635) ## [CFontzPacket] # Select the LCD model [default: 633; legal: 533, 631, 633, 635] Model=633 # Select the output device to use [default: /dev/lcd] Device=/dev/ttyUSB0 # Set the initial contrast [default: 560; legal: 0 - 1000] Contrast=350 # Set the initial brightness [default: 1000; legal: 0 - 1000] Brightness=1000 # Set the initial off-brightness [default: 0; legal: 0 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive OffBrightness=50 # Reinitialize the LCD's BIOS on driver start. [default: no; legal: yes, no] Reboot=yes # Enable the USB flag if the device is connected to an USB port. For # serial ports leave it disabled. [default: no; legal: yes, no] #USB=yes # Very old 633 firmware versions do not support partial screen updates using # 'Send Data to LCD' command (31). For those devices it may be necessary to # enable this flag. [default: no; legal: yes, no] #OldFirmware=yes # Override the LCD size known for the selected model. Usually setting this # value should not be necessary. #Size=20x4 # Override the default communication speed known for the selected model. # Default value depends on model [legal: 19200, 115200] #Speed=115200 ## Curses driver ## [curses] # color settings # foreground color [default: blue] Foreground=blue # background color when "backlight" is off [default: cyan] Background=cyan # background color when "backlight" is on [default: red] Backlight=red # display size [default: 20x4] Size=20x4 # What position (X,Y) to start the left top corner at... # Default: (7,7) TopLeftX=7 TopLeftY=7 # use ASC symbols for icons & bars [default: no; legal: yes, no] UseACS=no # draw Border [default: yes; legal: yes, no] DrawBorder=yes ## Cwlinux driver ## [CwLnx] # Select the LCD model [default: 12232; legal: 12232, 12832, 1602] Model=12232 # Select the output device to use [default: /dev/lcd] Device=/dev/ttyUSB0 # Select the LCD size. Default depends on model: # 12232: 20x4 # 12832: 21x4 # 1602: 16x2 Size=20x4 # Set the communication speed [default: 19200; legal: 9600, 19200] Speed=19200 # Reinitialize the LCD's BIOS [default: no; legal: yes, no] # normally you shouldn't need this Reboot=no # If you have a keypad connected. Keypad layout is currently not # configureable from the config file. Keypad=yes # If you have a non-standard keypad you can associate any keystrings to keys. # There are 6 input keys in the CwLnx hardware that generate characters # from 'A' to 'F'. # # The following is the built-in default mapping hardcoded in the driver. # You can leave those unchanged if you have a standard keypad. # You can change it if you want to report other keystrings or have a non # standard keypad. # KeyMap_A=Up # KeyMap_B=Down # KeyMap_C=Left # KeyMap_D=Right # KeyMap_E=Enter # KeyMap_F=Escape # keypad_test_mode permits one to test keypad assignment # Default value is no #keypad_test_mode=yes ## ea65 driver for the display in AOpen XC Cube AV EA65 media barebones ## [ea65] # Device is fixed /dev/ttyS1 # Width and Height are fixed 9x1 # As the VFD is self luminescent we don't have a backlight # But we can use the backlight functions to control the front LEDs # Brightness 0 to 299 -> LEDs off # Brightness 300 to 699 -> LEDs half bright # Brightness 700 to 1000 -> LEDs full bright Brightness=500 # OffBrightness is the the value used for the 'backlight off' state OffBrightness=0 ## EyeboxOne driver ## [EyeboxOne] # Select the output device to use [default: /dev/ttyS1] # Device=/dev/cua01 Device=/dev/ttyS1 # Set the display size [default: 20x4] Size=20x4 # Switch on the backlight? [default: yes] Backlight=yes # Switch on the cursor? [default: no] Cursor=no # Set the communication speed [default: 19200; legal: 1200, 2400, 9600, 19200] Speed=19200 # Enter Key is a \r character, so it's hardcoded in the driver LeftKey=D RightKey=C UpKey=A DownKey=B EscapeKey=P # You can find out which key of your display sends which # character by setting keypad_test_mode to yes and running # LCDd. LCDd will output all characters it receives. # Afterwards you can modify the settings above and set # keypad_set_mode to no again. keypad_test_mode=no ## Futaba TOSD-5711BB VFD Driver ## [futaba] ## g15 driver for Logitech G15 Keyboard LCDs ## [g15] # Display size (currently unused) size=20x5 ## glcd generic graphical display driver [glcd] # Select what type of connection. See documentation for types. ConnectionType=t6963 # Width and height of the display in pixel. The supported sizes may depend on # the ConnectionType. [default: 128x64; legal: 1x1 - 640x480] #Size=128x64 # Width and height of a character cell in pixels. This value is only used if # the driver has been compiled with FreeType and it is enabled. Otherwise the # default 6x8 cell is used. #CellSize=12x16 # If LCDproc has been compiled with FreeType 2 support this option can be used # to turn if off intentionally. [default: yes; legal: yes, no] #useFT2=no # Path to font file to use for FreeType rendering. This font must be monospace # and should contain some special Unicode characters like arrows (Andale Mono # is recommended and can be fetched at http://corefonts.sf.net). #normal_font=/usr/local/lib/X11/fonts/TTF/andalemo.ttf # Some fonts miss the Unicode characters used to represent icons. In this case # the built-in 5x8 font can used if this option is turned off. [default: yes; # legal: yes, no] #fontHasIcons=no # Set the initial contrast if supported by connection type. # [default: 600; legal: 0 - 1000] #Contrast=600 # Set brightness of the backlight if the backlight is switched 'on'. # [default: 800; legal: 0 - 1000] #Brightness=1000 # Set brightness of the backlight if the backlight is switched 'off'. Set this # to zero to completely turn off the backlight. [default: 100; legal: 0 - 1000] #OffBrightness=0 # Time (ms) from first key report to first repeat. Set to 0 to disable repeated # key reports. [default: 500; legal: 0 - 3000] #KeyRepeatDelay=500 # Time (ms) between repeated key reports. Ignored if KeyRepeatDelay is disabled # (set to zero). [default: 300; legal: 0 - 3000] #KeyRepeatInterval=300 # Assign key strings to keys. There may be up to 16 keys numbered 'A' to 'Z'. # By default keys 'A' to 'F' are assigned Up, Down, Left, Right, Enter, Escape. KeyMap_A=Up KeyMap_B=Down KeyMap_C=Enter KeyMap_D=Escape # --- t6963 options --- # Parallel port to use [default: 0x378; legal: 0x200 - 0x400] #Port=0x378 # Use LPT port in bi-directional mode. This should work on most LPT port # and is required for proper timing! [default: yes; legal: yes, no] #bidirectional=yes # Insert additional delays into reads / writes. [default: no; legal: yes, no] #delayBus=no # --- serdisplib options --- # Name of the underlying serdisplib driver, e.g. ctinclud. See # serdisplib documentation for details. serdisp_name=t6963 # The display device to use, e.g. serraw:/dev/ttyS0, # parport:/dev/parport0 or USB:07c0/1501. serdisp_device=/dev/ppi0 # Options string to pass to serdisplib during initialization. Use # this to set any display related options (e.g. wiring). The display size is # always set based on the Size configured above! By default, no options are # set. # Important: The value must be quoted as it contains equal signs! #serdisp_options="INVERT=1" # --- x11 options --- # PixelSize is size of each dot in pixels + a pixel gap. [default: 3+1] #x11_PixelSize=3+1 # Colors are in RRGGBB format prefixed with "0x". # PixelColor: The color of each dot at full contrast. [default: 0x000000] #x11_PixelColor=0x000000 # BacklightColor: The color of the backlight as full brightness. # [default: 0x80FF80] #x11_BacklightColor=0x80FF80 # Border: Adds a border (empty space) around the LCD portion of X11 window. # [default: 20] #x11_Border=20 # Inverted: inverts the pixels [default: no; legal: yes, no] #x11_Inverted=no # --- picolcdgfx options --- # Time in ms for usb_read to wait on a key press. [default: 125; legal: >0] #picolcdgfx_KeyTimeout=125 # Inverted: Inverts the pixels. [default: no; legal: yes or no] #picolcdgfx_Inverted=no ## glcdlib meta driver for graphical LCDs ## [glcdlib] ## mandatory: # which graphical display supported by graphlcd-base to use [default: image] # (see /etc/graphlcd.conf for possible drivers) Driver=noritake800 # no=use graphlcd bitmap fonts (they have only one size / font file) # yes=use fonts supported by FreeType2 (needs Freetype2 support in # libglcdprocdriver and its dependants) UseFT2=yes # text resolution in fixed width characters [default: 16x4] # (if it won't fit according to available physical pixel resolution # and the minimum available font face size in pixels, then # 'DebugBorder' will automatically be turned on) TextResolution=20x4 # path to font file to use FontFile=/usr/share/fonts/corefonts/courbd.ttf ## these only apply if UseFT2=yes: # character encoding to use CharEncoding=iso8859-2 # minimum size in pixels in which fonts should be rendered MinFontFaceSize=7x12 ## optional: Brightness=50 # Brightness (in %) if applicable Contrast=50 # Contrast (in %) if applicable Backlight=no # Backlight if applicable UpsideDown=no # flip image upside down Invert=no # invert light/dark pixels ShowDebugFrame=no # turns on/off 1 pixel thick debugging # border within the usable text area, # for setting up TextResolution and # MinFontFaceSize (if using FT2); ShowBigBorder=no # border around the unused area ShowThinBorder=yes # border around the unused area PixelShiftX=0 PixelShiftY=2 ## Matrix Orbital GLK driver ## [glk] # select the serial device to use [default: /dev/lcd] Device=/dev/lcd # set the initial contrast value [default: 560; legal: 0 - 1000] Contrast=560 # set the serial port speed [default: 19200; legal: 9600, 19200, 38400] Speed=19200 ## Hitachi HD44780 driver ## [hd44780] # Select what type of connection. See documentation for available types. ConnectionType=4bit # I/O address of the LPT port. Usual values are: 0x278, 0x378 and 0x3BC. # For I2C connections this sets the slave address (usually 0x20). Port=0x378 # Device of the serial, I2C, or SPI interface [default: /dev/lcd] Device=/dev/ttyS0 # Bitrate of the serial port (0 for interface default) Speed=0 # If you have a keypad connected. # You may also need to configure the keypad layout further on in this file. Keypad=no # Set the initial contrast (bwctusb, lcd2usb, and usb4all) # [default: 800; legal: 0 - 1000] #Contrast=0 # Set brightness of the backlight (lcd2usb and usb4all): # Brightness is the brightness while the backlight is set to 'on'. # [default: 800; legal: 0 - 1000] #Brightness=1000 # OffBrightness is the brightness while the backlight is set to 'off'. # [default: 300; legal: 0 - 1000] #OffBrightness=0 # If you have a switchable backlight. Backlight=no # If you have the additional output port ("bargraph") and you want to # be able to control it with the lcdproc OUTPUT command OutputPort=no # Specifies if the last line is pixel addressable (yes) or it controls an # underline effect (no). [default: yes; legal: yes, no] #Lastline=yes # Specifies the size of the LCD. # In case of multiple combined displays, this should be the total size. Size=20x4 # For multiple combined displays: how many lines does each display have. # Vspan=2,2 means both displays have 2 lines. #vspan=2,2 # If you have an HD66712, a KS0073 or another controller with 'extended mode', # set this flag to get into 4-line mode. On displays with just two lines, do # not set this flag. # As an additional restriction, controllers with and without extended mode # AND 4 lines cannot be mixed for those connection types that support more # than one display! #ExtendedMode=yes # In extended mode, on some controllers like the ST7036 (in 3 line mode) # the next line in DDRAM won't start 0x20 higher. [default: 0x20] #LineAddress=0x10 # Character map to to map ISO-8859-1 to the LCD's character set # [default: hd44780_default; legal: hd44780_default, hd44780_euro, ea_ks0073, # sed1278f_0b, hd44780_koi8_r, hd44780_cp1251, hd44780_8859_5, upd16314 ] # (hd44780_koi8_r, hd44780_cp1251, hd44780_8859_5 and upd16314 are possible if # compiled with additional charmaps) CharMap=hd44780_default # If your display is slow and cannot keep up with the flow of data from # LCDd, garbage can appear on the LCDd. Set this delay factor to 2 or 4 # to increase the delays. Default: 1. #DelayMult=2 # Some displays (e.g. vdr-wakeup) need a message from the driver to that it # is still alive. When set to a value bigger then null the character in the # upper left corner is updated every seconds. Default: 0. #KeepAliveDisplay=0 # If you experience occasional garbage on your display you can use this # option as workaround. If set to a value bigger than null it forces a # full screen refresh seconds. Default: 0. #RefreshDisplay=5 # You can reduce the inserted delays by setting this to false. # On fast PCs it is possible your LCD does not respond correctly. # Default: true. DelayBus=true # If you have a keypad you can assign keystrings to the keys. # See documentation for used terms and how to wire it. # For example to give directly connected key 4 the string "Enter", use: # KeyDirect_4=Enter # For matrix keys use the X and Y coordinates of the key: # KeyMatrix_1_3=Enter KeyMatrix_4_1=Enter KeyMatrix_4_2=Up KeyMatrix_4_3=Down KeyMatrix_4_4=Escape ## ICP Peripheral Comminication Protocol driver ## # Supports A125 and A106 # # Short Press Select: Down # Long Press Select: Up # Short Press Enter: Enter # Long Press Enter: Escape # [icp_a106] Device=/dev/ttyS1 # Display dimensions Size=20x2 ## Code Mercenaries IO-Warrior driver ## [IOWarrior] # display dimensions Size=20x4 # serial number. Must be exactly as listed by usbview # (if not given, the 1st IOWarrior found gets used) #SerialNumber=00000674 # If you have an HD66712, a KS0073 or another 'almost HD44780-compatible', # set this flag to get into extended mode (4-line linear). #ExtendedMode=yes # Specifies if the last line is pixel addressable (yes) or it controls an # underline effect (no). [default: yes; legal: yes, no] #Lastline=yes ## Soundgraph/Ahanix/Silverstone/Uneed/Accent iMON driver ## [imon] # select the device to use Device=/dev/lcd0 # display dimensions Size=16x2 # Character map to to map ISO-8859-1 to the displays character set. # [default: none; legal: none, hd44780_euro, upd16314, hd44780_koi8_r, # hd44780_cp1251, hd44780_8859_5 ] (upd16314, hd44780_koi8_r, # hd44780_cp1251, hd44780_8859_5 are possible if compiled with additional # charmaps) CharMap=hd44780_euro ## Soundgraph iMON LCD ## [imonlcd] # Specify which iMon protocol should be used # [legal: 0, 1; default: 0] # Choose 0 for 15c2:ffdc device, # Choose 1 for 15c2:0038 device Protocol=0 # Set the exit behavior [legal: 0-2; default: 1] # 0 means leave shutdown message, # 1 means show the big clock, # 2 means blank device #OnExit=2 # Select the output device to use [default: /dev/lcd0] Device=/dev/lcd0 # Select the displays contrast [default: 200; legal: 0-1000] Contrast=200 # Specify the size of the display in pixels [default: 96x16] #Size=96x16 # Set the backlight state [default: on; legal: on, off] #Backlight=on # Set the disc mode [legal: 0,1; default: 0] # 0 => spin the "slim" disc - two disc segments, # 1 => their complement spinning; #DiscMode=0 ## IrMan driver ## [IrMan] # in case of trouble with IrMan, try the Lirc emulator for IrMan # Select the input device to use #Device=/dev/irman # Select the configuration file to use #Config=/etc/irman.cfg ## IRtrans driver ## [irtrans] # Does the device have a backlight? [default: no; legal: yes, no] #Backlight=no # IRTrans device to connect to [default: localhost] #Hostname=localhost # display dimensions Size=16x2 ## Joystick driver ## [joy] # Select the input device to use [default: /dev/js0] Device=/dev/js0 # set the axis map Map_Axis1neg=Left Map_Axis1pos=Right Map_Axis2neg=Up Map_Axis2pos=Down # set the button map Map_Button1=Enter Map_Button2=Escape ## LB216 driver ## [lb216] # Select the output device to use [default: /dev/lcd] Device=/dev/lcd # Set the initial brightness [default: 255; legal: 0 - 255] Brightness=255 # Set the communication speed [default: 9600; legal: 2400, 9600] Speed=9600 # Reinitialize the LCD's BIOS [default: no; legal: yes, no] Reboot=no ## LCDM001 driver ## [lcdm001] Device=/dev/ttyS1 # keypad settings # Keyname Function # Normal context Menu context # ------- -------------- ------------ # PauseKey Pause/Continue Enter/select # BackKey Back(Go to previous screen) Up/Left # ForwardKey Forward(Go to next screen) Down/Right # MainMenuKey Open main menu Exit/Cancel PauseKey=LeftKey BackKey=UpKey ForwardKey=DownKey MainMenuKey=RightKey # You can rearrange the settings here. # If your device is broken, have a look at server/drivers/lcdm001.h ## HNE LCTerm driver ## [lcterm] Device=/dev/ttyS1 Size=16x2 ## Linux event device input driver ## [linux_input] # Select the input device to use [default: /dev/input/event0] # Device=/dev/input/event0 # specify a non-default key map #key=1,Escape #key=28,Enter #key=96,Enter #key=105,Left #key=106,Right #key=103,Up #key=108,Down ## LIRC input driver ## [lirc] # Specify an alternative location of the lircrc file [default: ~/.lircrc] #lircrc=/etc/lircrc.lcdproc # Must be the same as in your lircrc #prog=lcdd ## LIS MCE 2005 driver ## [lis] # Set the initial brightness [default: 1000; legal: 0 - 1000] # 0-250 = 25%, 251-500 = 50%, 501-750 = 75%, 751-1000 = 100% #Brightness=1000 # Columns by lines [default: 20x2] #Size=20x2 # USB Vendor ID [default: 0x0403] # Change only if testing a compatible device. #VendorID=0x0403 # USB Product ID [default: 0x6001] # Change only if testing a compatible device. #ProductID=0x6001 # Specifies if the last line is pixel addressable (yes) or it only controls an # underline effect (no). [default: yes; legal: yes, no] #Lastline=yes ##The driver for the VFD of the Medion MD8800 PC ## [MD8800] # device to use [default: /dev/ttyS1] #Device=/dev/ttyS1 # display size [default: 16x2] #Size=16x2 # Set the initial brightness [default: 1000; legal: 0 - 1000] Brightness=1000 # Set the initial off-brightness [default: 0; legal: 0 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive OffBrightness=50 ## Futuba MDM166A Display [mdm166a] # Show self-running clock after LCDd shutdown # Possible values: [default: no; legal: no, small, big] Clock=big # Dim display, no dimming gives full brightness [default: no, legal: yes, no] Dimming=no # Dim display in case LCDd is inactive [default: no, legal: yes, no] OffDimming=yes ## MSI MS-6931 driver for displays in 1HU servers ## [ms6931] # device to use [default: /dev/ttyS1] Device=/dev/ttyS1 # display size [default: 16x2] #Size=16x2 ## MTC-S16209x driver ## [mtc_s16209x] # Select the output device to use [default: /dev/lcd] Device=/dev/lcd # Set the initial brightness [default: 255; legal: 0 - 255] Brightness=255 # Reinitialize the LCD's BIOS [default: no; legal: yes, no] Reboot=no ## Matrix Orbital driver ## [MtxOrb] # Select the output device to use [default: /dev/lcd] Device=/dev/ttyS0 # Set the display size [default: 20x4] Size=20x4 # Set the display type [default: lcd; legal: lcd, lkd, vfd, vkd] Type=lkd # Set the initial contrast [default: 480] # NOTE: The driver will ignore this if the display # is a vfd or vkd as they don't have this feature Contrast=480 # Some old displays do not have an adjustable backlight but only can # switch the backlight on/off. If you experience randomly appearing block # characters, try setting this to false. [default: yes; legal: yes, no] hasAdjustableBacklight=no # Set the initial brightness [default: 1000; legal: 0 - 1000] Brightness=1000 # Set the initial off-brightness [default: 0; legal: 0 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive OffBrightness=0 # Set the communication speed [default: 19200; legal: 1200, 2400, 9600, 19200] Speed=19200 # The following table translates from MtxOrb key letters to logical key names. # By default no keys are mapped, meaning the keypad is not used at all. #KeyMap_A=Left #KeyMap_B=Right #KeyMap_C=Up #KeyMap_D=Down #KeyMap_E=Enter #KeyMap_F=Escape # See the [menu] section for an explanation of the key mappings # You can find out which key of your display sends which # character by setting keypad_test_mode to yes and running # LCDd. LCDd will output all characters it receives. # Afterwards you can modify the settings above and set # keypad_set_mode to no again. keypad_test_mode=no ## mx5000 driver for LCD display on the Logitech MX5000 keyboard ## [mx5000] # Select the output device to use [default: /dev/hiddev0] Device = /dev/hiddev0 # Time to wait in ms after the refresh screen has been sent [default: 1000] WaitAfterRefresh = 1000 ## Noritake VFD driver ## [NoritakeVFD] # device where the VFD is. Usual values are /dev/ttyS0 and /dev/ttyS1 # [default: /dev/lcd] Device=/dev/ttyS0 # Specifies the size of the LCD. Size=20x4 # Set the initial brightness [default: 1000; legal: 0 - 1000] Brightness=1000 # Set the initial off-brightness [default: 0; legal: 0 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive OffBrightness=50 # set the serial port speed [default: 9600, legal: 1200, 2400, 9600, 19200, 115200] Speed=9600 # Set serial data parity [default: 0; legal: 0-2 ] # Meaning: 0(=none), 1(=odd), 2(=even) Parity=0 # re-initialize the VFD [default: no; legal: yes, no] Reboot=no ## Olimex MOD-LCD1x9 driver ## [Olimex_MOD_LCD1x9] # device file of the i2c controler Device=/dev/i2c-0 ## Mini-box.com picoLCD (usblcd) driver ## [picolcd] # KeyTimeout is only used if the picoLCD driver is built with libusb-0.1. When # built with libusb-1.0 key and IR data is input asynchronously so there is no # need to wait for the USB data. # KeyTimeout is the time in ms that LCDd spends waiting for a key press before # cycling through other duties. Higher values make LCDd use less CPU time and # make key presses more detectable. Lower values make LCDd more responsive # but a little prone to missing key presses. 500 (.5 second) is the default # and a balanced value. [default: 500; legal: 0 - 1000] KeyTimeout=500 # Key auto repeat is only available if the picoLCD driver is built with # libusb-1.0. Use KeyRepeatDelay and KeyRepeatInterval to configure key auto # repeat. # # Key auto repeat delay (time in ms from first key report to first repeat). Use # zero to disable auto repeat. [default: 300; legal: 0 - 3000] KeyRepeatDelay=300 # Key auto repeat interval (time in ms between repeat reports). Only used if # KeyRepeatDelay is not zero. [default: 200; legal: 0 - 3000] KeyRepeatInterval=200 # Sets the initial state of the backlight upon start-up. # [default: on; legal: on, off] #Backlight=on # Set the initial brightness [default: 1000; legal: 0 - 1000]. Works only # with the 20x4 device Brightness=1000 # Set the brightness while the backlight is 'off' [default: 0; legal: 0 - 1000]. # Works only with the 20x4 device. #OffBrightness=0 # Set the initial contrast [default: 1000; legal: 0 - 1000] Contrast=1000 # Link the key lights to the backlight? [default: on; legal: on, off] #LinkLights=off # Light the keys? [default: on; legal: on, off] Keylights=on # If Keylights is on, the you can unlight specific keys below: # Key0 is the directional pad. Key1 - Key5 correspond to the F1 - F5 keys. # There is no LED for the +/- keys. This is a handy way to indicate to users # which keys are disabled. [default: on; legal: on, off] Key0Light=on Key1Light=on Key2Light=on Key3Light=on Key4Light=on Key5Light=on # Host name or IP address of the LIRC instance that is to receive IR codes # If not set, or set to an empty value, IR support is disabled. #LircHost=127.0.0.1 # UDP port on which LIRC is listening [default: 8765; legal: 1 - 65535] LircPort=8765 # UDP data time unit for LIRC [default: off; legal: on, off] # On: times sent in microseconds (requires LIRC UDP driver that accepts this). # Off: times sent in 'jiffies' (1/16384s) (supported by standard LIRC UDP driver). LircTime_us=on # Threshold in microseconds of the gap that triggers flushing the IR data # to lirc [default: 8000; legal: 1000 - ] # If LircTime_us is on values greater than 32.767ms will disable the flush # If LircTime_us is off values greater than 1.999938s will disable the flush LircFlushThreshold=10000 ## Pyramid LCD driver ## [pyramid] # device to connect to [default: /dev/lcd] Device=/dev/ttyUSB0 ## rawserial driver ## [rawserial] # Select the output device to use [default: /dev/cuaU0] Device=/dev/ttyS0 # Serial port baudrate [default: 9600] Speed=9600 # Specifies the size of the LCD. If this driver is loaded as a secondary driver # it always adopts to the size of the primary driver. If loaded as the only # (or primary) driver, the size can be set. [default: 40x4] #Size=16x2 # How often to dump the LCD contents out the port, in Hertz (times per second) # 1 = once per second, 4 is 4 times per second, 0.1 is once every 10 seconds. # [default: 1; legal: 0.0005 - 10] UpdateRate=1 ## SDEC driver for Watchguard Firebox ## [sdeclcd] # No options ## Seiko Epson 1330 driver ## [sed1330] # Port where the LPT is. Common values are 0x278, 0x378 and 0x3BC Port=0x378 # Type of LCD module (legal: G321D, G121C, G242C, G191D, G2446, SP14Q002) # Note: Currently only tested with G321D & SP14Q002. Type=G321D # Width x Height of a character cell in pixels [legal: 6x7 - 8x16; default: 6x10] CellSize=6x10 # Select what type of connection [legal: classic, bitshaker; default: classic] ConnectionType=classic ## Seiko Epson 1520 driver ## [sed1520] # Port where the LPT is. Usual values are 0x278, 0x378 and 0x3BC Port=0x378 # Select the interface type (wiring) for the display. Supported values are # 68 for 68-style connection (RESET level high) and 80 for 80-style connection # (RESET level low). [legal: 68, 80; default: 80] InterfaceType=80 # On fast machines it may be necessary to slow down transfer to the display. # If this value is set to zero, delay is disabled. Any value greater than # zero slows down each write by one microsecond. [legal: 0-1000; default: 1] DelayMult=0 # The original wiring used an inverter to drive the control lines. If you do # not use an inverter set haveInverter to no. [default: yes; legal: yes, no] HaveInverter=no # On some displays column data in memory is mapped to segment lines from right # to left. This is called inverted mapping (not to be confused with # 'haveInverter' from above). [default: no; legal: yes, no] #InvertedMapping=yes # At least one display is reported (Everbouquet MG1203D) that requires sending # three times 0xFF before a reset during initialization. # [default: no; legal: yes, no] #UseHardReset=yes ## serial POS display driver ## [serialPOS] # Device to use in serial mode [default: /dev/lcd] Device=/dev/lcd # Specifies the size of the display in characters. [default: 16x2] Size=16x2 # Set the communication protocol to use with the POS display. # [default: AEDEX; legal: IEE, Epson, Emax, IBM, LogicControls, Ultimate] Type=AEDEX # communication baud rate with the display [default: 9600; legal: 1200, 2400, # 19200, 115200] Speed=9600 ## Serial VFD driver ## ## Drives various (see below) serial 5x7dot VFD's. ## [serialVFD] # Specifies the displaytype.[default: 0] # 0 NEC (FIPC8367 based) VFDs. # 1 KD Rev 2.1. # 2 Noritake VFDs (*). # 3 Futaba VFDs # 4 IEE S03601-95B # 5 IEE S03601-96-080 (*) # 6 Futaba NA202SD08FA (allmost IEE compatible) # 7 Samsung 20S207DA4 and 20S207DA6 # 8 Nixdorf BA6x / VT100 # (* most should work, not tested yet.) Type=0 # "no" if display connected serial, "yes" if connected parallel. [default: no] # I.e. serial by default use_parallel=no # Number of Custom-Characters. default is display type dependent #Custom-Characters=0 # Portaddress where the LPT is. Used in parallel mode only. Usual values are # 0x278, 0x378 and 0x3BC. Port=0x378 # Set parallel port timing delay (us). Used in parallel mode only. # [default: 2; legal: 0 - 255] #PortWait=2 # Device to use in serial mode. Usual values are /dev/ttyS0 and /dev/ttyS1 Device=/dev/ttyS1 # Specifies the size of the VFD. Size=20x2 # Set the initial brightness [default: 1000; legal: 0 - 1000] # (4 steps 0-250, 251-500, 501-750, 751-1000) Brightness=1000 # Set the initial off-brightness [default: 0; legal: 0 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive # (4 steps 0-250, 251-500, 501-750, 751-1000) OffBrightness=0 # set the serial port speed [default: 9600; legal: 1200, 2400, 9600, 19200, 115200] Speed=9600 # enable ISO 8859 1 compatibility [default: yes; legal: yes, no] #ISO_8859_1=yes ## shuttleVFD driver ## [shuttleVFD] # No options ## stv5730 driver ## [stv5730] # Port the device is connected to [default: 0x378] Port=0x378 [SureElec] # Port the device is connected to (by default first USB serial port) Device=/dev/ttyUSB0 # Edition level of the device (can be 1, 2 or 3) [default: 2] #Edition=1 # set display size # Note: The size can be obtained directly from device for edition 2 & 3. #Size=16x2 # Set the initial contrast [default: 480; legal: 0 - 1000] #Contrast=200 # Set the initial brightness [default: 480; legal: 1 - 1000] #Brightness=480 # Set the initial off-brightness [default: 100; legal: 1 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive #OffBrightness=100 ## SVGAlib driver ## [svga] # svgalib mode to use [default: G320x240x256 ] # legal values are supported svgalib modes #Mode=G640x480x256 # set display size [default: 20x4] Size=20x4 # Set the initial contrast [default: 500; legal: 0 - 1000] # Can be set but does not change anything internally Contrast=500 # Set the initial brightness [default: 1000; legal: 1 - 1000] Brightness=1000 # Set the initial off-brightness [default: 500; legal: 1 - 1000] # This value is used when the display is normally # switched off in case LCDd is inactive OffBrightness=500 ## Text driver ## [text] # Set the display size [default: 20x4] Size=20x4 ## Toshiba T6963 driver ## [t6963] # set display size in pixels [default: 128x64] Size=128x64 # port to use [default: 0x378; legal: 0x200 - 0x400] Port=0x378 # Use LPT port in bi-directional mode. This should work on most LPT port and # is required for proper timing! [default: yes; legal: yes, no] #bidirectional=yes # Insert additional delays into reads / writes. [default: no; legal: yes, no] #delayBus=no # Clear graphic memory on start-up. [default: no; legal: yes, no] #ClearGraphic=no ## Tyan Barebones LCD driver (GS10 & GS12 series) ## [tyan] # Select the output device to use [default: /dev/lcd] Device=/dev/lcd # Set the communication speed [default: 9600; legal: 4800, 9600] Speed=9600 # set display size [default: 16x2] Size=16x2 ## ELV ula200 driver ## [ula200] # Select the LCD size [default: 20x4] Size=20x4 # If you have a non standard keypad you can associate any keystrings to keys. # There are 6 input key in the CwLnx hardware that generate characters # from 'A' to 'F'. # # The following it the built-in default mapping hardcoded in the driver. # You can leave those unchanged if you have a standard keypad. # You can change it if you want to report other keystrings or have a non # standard keypad. # KeyMap_A=Up # KeyMap_B=Down # KeyMap_C=Left # KeyMap_D=Right # KeyMap_E=Enter # KeyMap_F=Escape ## Wirz SLI LCD driver ## [sli] # Select the output device to use [default: /dev/lcd] Device=/dev/lcd # Set the communication speed [default: 19200; legal: 1200, 2400, 9600, 19200, # 38400, 57600, 115200] Speed=19200 ## vlsys_m428 for VFD/IR combination in Moneual MonCaso 320 ## [vlsys_m428] # Select the output device to use [default: /dev/ttyUSB0] #Device=/dev/ttyUSB0 ## OnScreen Display using libxosd ## [xosd] # set display size [default: 20x4] Size=20x4 # Offset in pixels from the top-left corner of the monitor [default: 0x0] Offset=200x200 # X font to use, in XLFD format, as given by "xfontsel" Font=-*-terminus-*-r-*-*-*-320-*-*-*-*-* ## Y.A.R.D.2 LCD section [yard2LCD] Size=20x4 # If rendering rate is too high, change in server\main.h #define RENDER_FREQ 8 to "1" # EOF lcdproc-0.5.9/shared/0000755000175100017510000000000013121562634011427 500000000000000lcdproc-0.5.9/shared/report.c0000644000175100017510000000547112505300405013024 00000000000000/** \file shared/report.c * Contains reporting functions. */ /*- * This file is part of LCDproc. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2001, Joris Robijn * 2005, Peter Marschall */ #include #include #include #include #include #include "report.h" static int report_level = RPT_INFO; static int report_dest = RPT_DEST_STORE; #define MAX_STORED_MSGS 200 static char *stored_msgs[MAX_STORED_MSGS]; static int stored_levels[MAX_STORED_MSGS]; static int num_stored_msgs = 0; /* local functions */ static void store_report_message(int level, const char *message); static void flush_messages(); void report(const int level, const char *format,... /* args */ ) { /* Check if we should report it */ if (level <= report_level || report_dest == RPT_DEST_STORE) { char buf[1024]; /* * Following functions appear to work on RedHat and Debian * Linux, FreeBSD and Solaris */ va_list ap; va_start(ap, format); switch (report_dest) { case RPT_DEST_STDERR: vfprintf(stderr, format, ap); fprintf(stderr, "\n"); break; case RPT_DEST_SYSLOG: vsyslog(LOG_USER | (level + 2), format, ap); break; case RPT_DEST_STORE: vsnprintf(buf, sizeof(buf), format, ap); buf[sizeof(buf) - 1] = 0; store_report_message(level, buf); break; } va_end(ap); } } int set_reporting(char *application_name, int new_level, int new_dest) { if (new_level < RPT_CRIT || new_level > RPT_DEBUG) { report(RPT_ERR, "report level invalid: %d", new_level); return -1; } if (report_dest != RPT_DEST_SYSLOG && new_dest == RPT_DEST_SYSLOG) { openlog(application_name, 0, LOG_USER); } else if (report_dest == RPT_DEST_SYSLOG && new_dest != RPT_DEST_SYSLOG) { closelog(); } report_level = new_level; report_dest = new_dest; /* * Flush all messages currently in the message store if the new * destination is not the store itself. */ if (report_dest != RPT_DEST_STORE) flush_messages(); return 0; } /** * Puts a message into the message store. If the store is full new messages * are silently discarded. */ static void store_report_message(int level, const char *message) { if (num_stored_msgs < MAX_STORED_MSGS) { stored_msgs[num_stored_msgs] = malloc(strlen(message) + 1); strcpy(stored_msgs[num_stored_msgs], message); stored_levels[num_stored_msgs] = level; num_stored_msgs++; } } /** * Report all messages contained in the message store to the current report * destination and release their memory. */ static void flush_messages() { int i; for (i = 0; i < num_stored_msgs; i++) { report(stored_levels[i], "%s", stored_msgs[i]); free(stored_msgs[i]); } num_stored_msgs = 0; } lcdproc-0.5.9/shared/defines.h0000644000175100017510000000110512505300405013121 00000000000000/** \file shared/defines.h * Define macros commonly used in other parts of LCDproc. */ /*- * This file is part of LCDproc. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. */ #ifndef SHARED_DEFINES_H #define SHARED_DEFINES_H /* Define min() and max() */ #ifndef min # define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef max # define max(a,b) (((a) > (b)) ? (a) : (b)) #endif /* Our own way of saying yes/no */ #ifndef bool # define bool short # define true 1 # define false 0 #endif #endif lcdproc-0.5.9/shared/LL.c0000644000175100017510000004670113100167541012025 00000000000000/** \file shared/LL.c * Define routines to deal with doubly linked lists */ /* This file is part of LCDproc. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright(c) 1994, Selene Scriven * (c) 1999, William Ferrell * (c) 2000, Guillaume Filion * (c) 2001, Joris Robijn * (c) 2008, Peter Marschall * */ #include #include #include "LL.h" #ifdef DEBUG #undef DEBUG #endif //TODO: Test everything? /** Create new linked list. * \return Pointer to freshly created list object; \c NULL on error. */ LinkedList * LL_new(void) { LinkedList *list; list = malloc(sizeof(LinkedList)); if (list == NULL) return NULL; list->head.data = NULL; list->head.prev = NULL; list->head.next = &list->tail; list->tail.data = NULL; list->tail.prev = &list->head; list->tail.next = NULL; list->current = &list->head; return list; } /** Destroy the entire list. * * \note * This does not free the data, only the list itself. * * \param list List object to be destroyed. * \retval <0 error * \retval 0 success */ int LL_Destroy(LinkedList *list) { LL_node *prev, *next; LL_node *node; if (!list) return -1; node = &list->head; for (node = node->next; node && node->next; node = next) { // Avoid accessing "node" after it's freed.. :) next = node->next; prev = node->prev; if (next != NULL) next->prev = prev; if (prev != NULL) prev->next = next; node->next = NULL; node->prev = NULL; free(node); } free(list); return 0; } /** Move to another entry in the list. * Set list's \c current pointer to the node denoted to by \c whereto. * \param list List object. * \param whereto Direction where to set the list's \c current pointer * \return New value of list's \c current pointer; * \c NULL on error or when moving beyond ends. */ LL_node * LL_GoTo(LinkedList *list, Direction whereto) { if (!list) return NULL; switch (whereto) { case HEAD: list->current = (list->head.next != &list->tail) ? list->head.next : NULL; break; case PREV: if (list->current->prev == &list->head) return NULL; list->current = list->current->prev; case CURRENT: break; case NEXT: if (list->current->next == &list->tail) return NULL; list->current = list->current->next; break; case TAIL: list->current = (list->tail.prev != &list->head) ? list->tail.prev : NULL; break; } return list->current; } /** Return to the beginning of the list. * Set list's \c current pointer to the first node in the list. * \param list List object. * \retval <0 error: no list given * \retval 0 success */ int LL_Rewind(LinkedList *list) { if (!list) return -1; list->current = (list->head.next != &list->tail) ? list->head.next : &list->head; return 0; } /** Jump to the end of the list. * Set list's \c current pointer to the last node in the list. * \param list List object. * \retval <0 error: no list given * \retval 0 success */ int LL_End(LinkedList *list) { if (!list) return -1; list->current = (list->tail.prev != &list->head) ? list->tail.prev : &list->tail; return 0; } /** Go to the next node of the list. * Advance list's \c current pointer to the next node in the list. * \param list List object. * \retval <0 error: no list given or no next node * \retval 0 success */ int LL_Next(LinkedList *list) { if (!list) return -1; if (!list->current) return -1; if (list->current->next == &list->tail) return -1; list->current = list->current->next; return 0; } /** Go to the previous node of the list. * Set list's \c current pointer to the previous node in the list. * \param list List object. * \retval <0 error: no list given or no previous node * \retval 0 success */ int LL_Prev(LinkedList *list) { if (!list) return -1; if (!list->current) return -1; if (list->current->prev == &list->head) return -1; list->current = list->current->prev; return 0; } /** Access current node's data. * Return pointer to list's \c current node's data. * \param list List object. * \return Pointer to \c current node's payload data; * \c NULL may be empty payload or an error. */ void * LL_Get(LinkedList *list) { if (!list) return NULL; if (!list->current) return NULL; return list->current->data; } /** Set/change current node's data. * \param list List object. * \param data Pointer to data to be set. * \retval <0 error: no list given, or no current node * \retval 0 success */ int LL_Put(LinkedList *list, void *data) { if (!list) return -1; if (!list->current) return -1; list->current->data = data; return 0; } /** Get current node in list. * \param list List object. * \return Pointer to current node. */ LL_node * LL_GetNode(LinkedList *list) { if (!list) return NULL; return list->current; } /** Set list's \c current pointer to a specific node. * * \warning * Don't use this unless you know what you're doing. * * \param list List object. * \param node Node to become new \c current. * \retval <0 error * \retval 0 success */ int LL_PutNode(LinkedList *list, LL_node *node) { if (!list) return -1; if (!node) return -1; list->current = node; return 0; } /** Access list's first node's data. * Set list's \c current pointer to the first node and return its data. * \param list List object. * \return Pointer to first node's data; \c NULL on error. */ void * LL_GetFirst(LinkedList *list) { if (!list) return NULL; if (0 > LL_Rewind(list)) return NULL; return LL_Get(list); } /** Access next node's data. * Advance list's \c current pointer to the next node and return its data. * \param list List object. * \return Pointer to next node's data; \c NULL on error. */ void * LL_GetNext(LinkedList *list) { if (!list) return NULL; if (0 > LL_Next(list)) return NULL; return LL_Get(list); } /** Access previous node's data. * Set list's \c current pointer to the previous node, and return its data. * \param list List object. * \return Pointer to previous node's data; \c NULL on error. */ void * LL_GetPrev(LinkedList *list) { if (!list) return NULL; if (0 > LL_Prev(list)) return NULL; return LL_Get(list); } /** Access list's last node's data. * Set list's \c current pointer to the last node and return its data. * \param list List object. * \return Pointer to last node's data; \c NULL on error. */ void * LL_GetLast(LinkedList *list) { if (!list) return NULL; if (0 > LL_End(list)) return NULL; return LL_Get(list); } /** Add/append a new node after current one in the list. * Update the list's \c current pointer to point to the freshly created node. * \param list List object. * \param add Pointer to new node's data. * \retval <0 error * \retval 0 success */ int LL_AddNode(LinkedList *list, void *add) { LL_node *node; if (!list) return -1; if (!list->current) return -1; node = malloc(sizeof(LL_node)); if (node == NULL) return -1; // we're behind the list's end, go to previous node if (list->current == &list->tail) list->current = list->current->prev; // Set node data node->next = list->current->next; node->prev = list->current; node->data = add; // Re-link if (node->next) node->next->prev = node; list->current->next = node; list->current = node; return 0; } /** Add/insert a new node before current one in the list. * Update the list's \c current pointer to point to the freshly created node. * \param list List object. * \param add Pointer to new node's data. * \retval <0 error * \retval 0 success */ int LL_InsertNode(LinkedList *list, void *add) { LL_node *node; if (!list) return -1; if (!add) return -1; if (!list->current) return -1; node = malloc(sizeof(LL_node)); if (node == NULL) return -1; // we're before the list's start, go to next node if (list->current == &list->head) list->current = list->current->next; node->next = list->current; node->prev = list->current->prev; node->data = add; if (list->current->prev) list->current->prev->next = node; list->current->prev = node; list->current = node; return 0; } /** Remove current node from the list. * Set the list's \c current pointer to the one denoted by \c whereto. * \param list List object. * \param whereto Direction where to set the list's \c current pointer * \return Pointer to data of deleted node; \c NULL on error. */ void * LL_DeleteNode(LinkedList *list, Direction whereto) { LL_node *next, *prev; void *data; if (!list) return NULL; if (!list->current) return NULL; if (list->current == &list->head) return NULL; if (list->current == &list->tail) return NULL; next = list->current->next; prev = list->current->prev; data = list->current->data; if (prev) prev->next = next; if (next) next->prev = prev; list->current->prev = NULL; list->current->next = NULL; // This should not free things; the user should do it explicitly. //if(list->current->data) free(list->current->data); list->current->data = NULL; free(list->current); switch (whereto) { case HEAD: list->current = list->head.next; break; case TAIL: list->current = list->tail.prev; break; case PREV: list->current = prev; break; default: case NEXT: list->current = next; } return data; } /** Remove a specific node from the list. * Find a node by a pointer to its data and remove it. * Set the list's \c current pointer to the one denoted by \c whereto. * \param list List object. * \param data Pointer to data of node to delete. * \param whereto Direction where to set the list's \c current pointer * \return Pointer to data of deleted node; \c NULL on error. */ void * LL_Remove(LinkedList *list, void *data, Direction whereto) { if (!list) return NULL; LL_Rewind(list); do { void *find = LL_Get(list); if (find == data) return LL_DeleteNode(list, whereto); } while (LL_Next(list) == 0); return NULL; } /** Add/append a new node after the last one in the list. * Jump to the last node in the list, append a new node * and make this new one the list's \c current one. * \param list List object. * \param add Pointer to new node's data. * \retval <0 error * \retval 0 success */ int LL_Push(LinkedList *list, void *add) { if (!list) return -1; if (!add) return -1; LL_End(list); return LL_AddNode(list, add); } /** Remove the last node from the list, and return its data. * Jump to the last node in the list, remove it from the list * and return its data. * \param list List object. * \return Pointer to data of deleted node; \c NULL on error. */ void * LL_Pop(LinkedList *list) { if (!list) return NULL; if (0 > LL_End(list)) return NULL; return LL_DeleteNode(list, PREV); } /** Access list's last node's data. * Set list's \c current pointer to the last node and return its data. * \param list List object. * \return Pointer to last node's data; \c NULL on error. */ void * LL_Top(LinkedList *list) { return LL_GetLast(list); } /** Remove the first node from the list, and return its data. * Jump to the first node in the list, remove it from the list and return its data. * \param list List object. * \return Pointer to data of deleted node; \c NULL on error. */ void * LL_Shift(LinkedList *list) { if (!list) return NULL; if (0 > LL_Rewind(list)) return NULL; return LL_DeleteNode(list, NEXT); } /** Access list's first node's data. * Set list's \c current pointer to the first node and return its data. * \param list List object. * \return Pointer to first node's data; \c NULL on error. */ void * LL_Look(LinkedList *list) { return LL_GetFirst(list); } /** Add/insert a new node before the first one in the list. * Jump to the first node in the list and insert a new node before that one. * \param list List object. * \param add Pointer to new node's data. * \retval <0 error * \retval 0 success */ int LL_Unshift(LinkedList *list, void *add) { if (!list) return -1; if (!add) return -1; LL_Rewind(list); return LL_InsertNode(list, add); } /** Add an item to the end of its "priority group" * The list is assumed to be sorted already. * \param list List object. * \param add Pointer to new node's data. * \param compare Pointer to a comparison function. * \retval <0 error * \retval 0 success */ int LL_PriorityEnqueue(LinkedList *list, void *add, int (*compare)(void *, void *)) { if (!list) return -1; if (!add) return -1; if (!compare) return -1; // From the end of the list, keep searching while we're "less than" // the given nodes... LL_End(list); do { void *data = LL_Get(list); if (data) { int i = compare(add, data); if (i >= 0) { // If we're in the right place, add it and exit LL_AddNode(list, add); return 0; } } } while (LL_Prev(list) == 0); // If we're less than *everything*, put it at the beginning LL_Unshift(list, add); return 0; } /** Switch two nodes positions. * \param one First list object. * \param two Second list object. * \return -1 on error, 0 on success */ int LL_SwapNodes(LL_node *one, LL_node *two) { LL_node *firstprev, *firstnext; LL_node *secondprev, *secondnext; if (!one || !two) return -1; if (one == two) return 0; // Do nothing firstprev = one->prev; // Look up the nodes neighbors... firstnext = one->next; secondprev = two->prev; secondnext = two->next; if (firstprev != NULL) firstprev->next = two; // Swap the neighboring if (firstnext != NULL) firstnext->prev = two; // nodes pointers... if (secondprev != NULL) secondprev->next = one; if (secondprev != NULL) secondnext->prev = one; one->next = secondnext; // Swap the nodes pointers one->prev = secondprev; two->next = firstnext; two->prev = firstprev; if (firstnext == two) one->prev = two; // Fix things in case if (firstprev == two) one->next = two; // they were next to if (secondprev == one) two->next = one; // each other... if (secondnext == one) two->prev = one; return 0; } /** Calculate the length of a list. * \param list List object. * \return Number of nodes in the list; \c -1 on error. */ int LL_Length(LinkedList *list) { LL_node *node; int num = 0; if (!list) return -1; node = &list->head; for (num = -1; node != &list->tail; num++) node = node->next; return num; } /** Find a node by giving a comparison function and a value. * Go to to the list node whose data matches the given value * and return the data. * * \note * This does \em not rewind the list first! * Do it yourself if you want to start from the beginning! * * \param list List object. * \param compare Pointer to a comparison function, that takes to void pointers * as arguments and returns an int. If must return \c 0 exactly * when the node's data matches \c value. * \param value Pointer to the value used for matching. * \return The found node's data pointer; \c NULL otherwise */ void * LL_Find(LinkedList *list, int (*compare)(void *, void *), void *value) { if (!list) return NULL; if (!compare) return NULL; if (!value) return NULL; for (void *data = LL_Get(list); data; data = LL_GetNext(list)) if (0 == compare(data, value)) return data; return NULL; } /** Perform an action for the all list elements. * Execute a function on the data of each node in the list. * Depending on the result of the function, new nodes may get added, * nodes may get deleted or simply changed by the function itself. * * The \c action() function is in turn called with each node's data * pointer as the first argument and \c value as its second argument. * If it returns \c NULL, the node will be deleted from the list, * otherwise, if the pointer returned from the function differs from * data, a new node gets added after the current node. * If the result equals the payload data, no addition or deletio happens. * * \note * Removing the client payload in case of deletion, or creation of * the payload for the new node in case of addition is up to the * \c action() function. * * \note * \c value can be used to report errors, pass additional information, ... * * \param list List object. * \param action Pointer to the action function that takes two void pointers * as arguments and returns a void pointer. * \param value Pointer to data that is used as second argument to * \c action(). */ void LL_ForAll(LinkedList *list, void *(*action)(void *, void *), void *value) { if (!list) return; if (!action) return; LL_Rewind(list); if (list->current != NULL) { do { void *data = LL_Get(list); void *result = action(data, value); if (result != data) { if (result != NULL) LL_AddNode(list, result); else LL_DeleteNode(list, PREV); } } while (LL_Next(list) == 0); } } /** Go to the n-th node in the list and return its data. * Go to to the list node with the given \c index * and return the data. * \param list List object. * \param index Index of the node whose data we want. * \return The found node's data pointer; \c NULL otherwise */ void * LL_GetByIndex(LinkedList *list, int index) { LL_node *node; int num = 0; if (!list) return NULL; if (index < 0) return NULL; for (node = list->head.next; node != &list->tail; node = node->next) { if (num == index) return node->data; num++; } return NULL; // got past the end } /** Sort list by its contents. * The list gets sorted using a comparison function for the data of its nodes. * After the sorting, the list's current pointer is set to the first node. * \param list List object. * \param compare Pointer to a comparison function, that takes to void pointers * as arguments and returns an int > \c 0 when the first argument * is considered greater than the second. * \retval <0 error * \retval 0 success. */ int LL_Sort(LinkedList *list, int (*compare)(void *, void *)) { int i, j; // Junk / loop variables int numnodes; // number of nodes in list LL_node *best, *last; // best match and last node in the list LL_node *current; if (!list) return -1; if (!compare) return -1; numnodes = LL_Length(list); // get the number of nodes... if (0 > LL_End(list)) return -1; // Find the last node. last = LL_GetNode(list); if (numnodes < 2) return 0; for (i = numnodes - 1; i > 0; i--) { LL_Rewind(list); // get the first node again best = last; // reset our "best" node for (j = 0; j < i; j++) { current = LL_GetNode(list); // If we found a better match... if (compare(current->data, best->data) > 0) { best = current; // keep track of the "best" match } LL_Next(list); // Go to the next node. } LL_SwapNodes(last, best); // Switch two nodes... if (best) last = best->prev; else return -1; } LL_Rewind(list); return 0; } void LL_dprint(LinkedList *list) { LL_node *current; current = &list->head; printf("Head: prev:\t0x%p\taddr:\t0x%p\tnext:\t0x%p\n", list->head.prev, &list->head, list->head.next); for (current = current->next; current != &list->tail; current = current->next) { printf("node: prev:\t0x%p\taddr:\t0x%p\tnext:\t0x%p\n", current->prev, current, current->next); } printf("Tail: prev:\t0x%p\taddr:\t0x%p\tnext:\t0x%p\n", list->tail.prev, &list->tail, list->tail.next); } lcdproc-0.5.9/shared/str.c0000644000175100017510000000232713063054535012330 00000000000000/** \file shared/str.c * Commmand / argument parsing functions (for use in clients). */ /*- * This file is part of LCDproc. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. */ #include #include #include #include "report.h" #include "str.h" /** Split elements of a string into an array of strings. * Elements are typically commands and arguments. * \param **argv Pointer to the array which will store the arguments * \param *str The string to be parsed * \param max_args Number of arguments to parse (typically the size of argv) * \retval <0 Error. * \retval >=0 The number of arguments parsed. */ int get_args (char **argv, char *str, int max_args) { char *delimiters = " \n"; char *item; int i = 0; if (!argv) return -1; if (!str) return 0; if (max_args < 1) return 0; debug(RPT_DEBUG, "get_args(%i): string=%s", max_args, str); /* Parse the command line... */ for (item = strtok (str, delimiters); item; item = strtok (NULL, delimiters)) { debug(RPT_DEBUG, "get_args: item=%s", item); if (i < max_args) { argv[i] = item; i++; } else return i; } return i; } lcdproc-0.5.9/shared/configfile.h0000644000175100017510000000712612505300405013622 00000000000000/** \file configfile.h * Declare routines to read INI-file like files. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 2001, Joris Robijn * (c) 2006,2007 Peter Marschall * */ #ifndef CONFIGFILE_H #define CONFIGFILE_H #ifdef HAVE_CONFIG_H #include "config.h" #endif /* Opens the specified file and reads everything into memory. * Returns 0 when config file was successfully parsed * Returns <0 on errors */ int config_read_file(const char *filename); #if defined(LCDPROC_CONFIG_READ_STRING) /* Reads everything in the string into memory. * Returns 0 when config file was successfully parsed * Returns <0 on errors */ int config_read_string(const char *sectionname, const char *str); #endif /* Tries to interpret a value in the config file as a boolean. * 0, false, off, no, n = false * 1, true, on, yes, y = true * If the key is not found or cannot be interpreted, the given default value is * returned. * The skip value can be used to iterate over multiple values with the same * key. Should be 0 to get the first one, 1 for the second etc. and -1 for the * last. */ short config_get_bool(const char *sectionname, const char *keyname, int skip, short default_value); /* Tries to interpret a value in the config file as a boolean. * 0, false, off, no, n = 0 * 1, true, on, yes, y = 1 * 2, or the given 3rd name = 2 * If the key is not found or cannot be interpreted, the given default value is * returned. * The skip value can be used to iterate over multiple values with the same * key. Should be 0 to get the first one, 1 for the second etc. and -1 for the * last. */ short config_get_tristate(const char *sectionname, const char *keyname, int skip, const char *name3rd, short default_value); /* Tries to interpret a value in the config file as an integer.*/ long int config_get_int(const char *sectionname, const char *keyname, int skip, long int default_value); /* Tries to interpret a value in the config file as a float.*/ double config_get_float(const char *sectionname, const char *keyname, int skip, double default_value); /* Returns a pointer to the string associated with the specified key. * The strings returned are always NUL-terminated. * The string should never be modified, and used only short-term. * In successive calls this function can * re-use the data space ! * * You can do some things with the returned string: * 1. Scan or parse it: * s = config_get_string(...); * sscanf( s, "%dx%d", &w, &h ); // scan format like: 20x4 * ...and check the w and h values... * 2. Copy it to a preallocated buffer like device[256]: * s = config_get_string(...); * strncpy( device, s, sizeof(device)); * device[sizeof(device)-1] = 0; * 3. Copy it to a newly allocated space in char *device: * s = config_get_string(...); * device = malloc(strlen(s)+1); * if( device == NULL ) return -5; // or whatever < 0 * strcpy( device, s ); */ const char *config_get_string(const char *sectionname, const char *keyname, int skip, const char *default_value); /* Checks if a specified section exists. * Returns whether it exists. */ int config_has_section(const char *sectionname); /* Checks if a specified key within the specified section exists. * Returns the number of times the key exists. */ int config_has_key(const char *sectionname, const char *keyname); /* Clears all data stored by the config_read_* functions. * Should be called if the config should be reread. */ void config_clear(void); #endif lcdproc-0.5.9/shared/LL.h0000644000175100017510000001424712505300405012026 00000000000000/** \file shared/LL.h * Define routines to deal with doubly linked lists */ /* This file is part of LCDproc. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright(c) 1994, Selene Scriven * (c) 1999, William Ferrell * */ #ifndef LL_H #define LL_H /*********************************************************************** Linked Lists! (Doubly-Linked Lists) ******************************************************************* To create a list, do the following: LinkedList *list; list = LL_new(); if(!list) handle_an_error(); The list can hold any type of data. You will need to typecast your datatype to a "void *", though. So, to add something to the list, the following would be a good way to start: typedef struct my_data { char string[16]; int number; } my_data; my_data *thingie; for(something to something else) { thingie = malloc(sizeof(my_data)); LL_AddNode(list, (void *)thingie); // typecast it to a "void *" } For errors, the general convention is that "0" means success, and a negative number means failure. Check LL.c to be sure, though. ******************************************************************* To change the data, try this: thingie = (my_data *)LL_Get(list); // typecast it back to "my_data" thingie->number = another_number; You don't need to "Put" the data back, but it doesn't hurt anything. LL_Put(list, (void *)thingie); However, if you want to point the node's data somewhere else, you'll need to get the current data first, keep track of it, then set the data to a new location: my_data * old_thingie, new_thingie; old_thingie = (my_data *)LL_Get(list); LL_Put(list, (void *)new_thingie); // Now, do something with old_thingie. (maybe, free it?) Or, you could just delete the node entirely and then add a new one: my_data * thingie; thingie = (my_data *)LL_DeleteNode(list, NEXT); free(thingie); thingie->number = 666; LL_InsertNode(list, (void *)thingie); ******************************************************************* To operate on each list item, try this: LL_Rewind(list); do { my_data = (my_data *)LL_Get(list); ... do something to it ... } while(LL_Next(list) == 0); ******************************************************************* You can also treat the list like a stack, or a queue. Just use the following functions: LL_Push() // Regular stack stuff: add, remove, peek, rotate LL_Pop() LL_Top() LL_Shift() // Other end of the stack (like in perl) LL_Unshift() LL_Look() LL_Enqueue() // Standard queue operations LL_Dequeue() There are also other goodies, like sorting and searching. ******************************************************************* That's about it, for now... Be sure to free the list when you're done! ***********************************************************************/ // See LL.c for more detailed descriptions of these functions. /** Symbolic values for directions */ typedef enum _direction { HEAD = -2, PREV = -1, CURRENT = 0, NEXT = +1, TAIL = +2 } Direction; /** Structure for a node in a linked list */ typedef struct LL_node { struct LL_node *prev; /**< Pointer to previous node */ struct LL_node *next; /**< Pointer to next node */ void *data; /**< Payload */ } LL_node; /** Structire for a linked list */ typedef struct LinkedList { LL_node head; /**< List's head anchor */ LL_node tail; /**< List's tail anchor */ LL_node *current; /**< Pointer to current node */ } LinkedList; // Creates a new list... LinkedList *LL_new(void); // Destroying lists... int LL_Destroy(LinkedList *list); // move "current" node LL_node *LL_GoTo(LinkedList *list, Direction whereto); // Returns to the beginning of the list... int LL_Rewind(LinkedList *list); // Goes to the end of the list... int LL_End(LinkedList *list); // Go to the next node int LL_Next(LinkedList *list); // Go to the previous node int LL_Prev(LinkedList *list); // Data manipulation void *LL_Get(LinkedList *list); int LL_Put(LinkedList *list, void *data); // Don't use these next two unless you really know what you're doing. LL_node *LL_GetNode(LinkedList *list); int LL_PutNode(LinkedList *list, LL_node *node); void *LL_GetFirst(LinkedList *list); // gets data from first node void *LL_GetNext(LinkedList *list); // ... next node void *LL_GetPrev(LinkedList *list); // ... prev node void *LL_GetLast(LinkedList *list); // ... last node int LL_AddNode(LinkedList *list, void *add); // Adds node AFTER current one int LL_InsertNode(LinkedList *list, void *add); // Adds node BEFORE current one // Removes a node from the link; returns the data from the node void *LL_DeleteNode(LinkedList *list, Direction whereto); // Removes a specific node... void *LL_Remove(LinkedList *list, void *data, Direction whereto); // Stack operations int LL_Push(LinkedList *list, void *add); // Add node to end of list void *LL_Pop(LinkedList *list); // Remove node from end of list void *LL_Top(LinkedList *list); // Peek at end node void *LL_Shift(LinkedList *list); // Remove node from start of list void *LL_Look(LinkedList *list); // Peek at first node int LL_Unshift(LinkedList *list, void *add); // Add node to beginning of list // Queue operations... #define LL_Enqueue(list,add) LL_Push(list,add) #define LL_Dequeue(list) LL_Shift(list) int LL_PriorityEnqueue(LinkedList * list, void *add, int (*compare)(void *, void *)); int LL_SwapNodes(LL_node *one, LL_node *two); // Switch two nodes positions... int LL_Length(LinkedList *list); // Returns # of nodes in entire list // Searching... void *LL_Find(LinkedList *list, int (*compare)(void *, void *), void *value); void LL_ForAll(LinkedList *list, void *(*action)(void *, void *), void *value); // Array operation... void *LL_GetByIndex(LinkedList *list, int index); // gets the nth node, 0 being the first // Sorts the list... int LL_Sort(LinkedList *list, int (*compare)(void *, void *)); // Debugging... void LL_dprint(LinkedList *list); #endif lcdproc-0.5.9/shared/report.h0000644000175100017510000000561212505300405013026 00000000000000/** \file shared/report.h * Contains reporting functions. *\verbatim * * To enable the debug() function on all of the software, just type: * ./configure --enable-debug * and recompile with 'make' * * To enable the debug() function only in specific files: * 1) Configure without enabling debug (that is without --enable-debug) * 2) Edit the source file that you want to debug and put the following * line at the top, before the #include "report.h" line: * #define DEBUG * 3) Then recompile with 'make' * * This way, the global DEBUG macro is off but is locally enabled in * certains parts of the software. *\endverbatim */ /*- * This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2001, Joris Robijn * */ #ifndef REPORT_H #define REPORT_H /* Reporting levels */ /** * \def RPT_CRIT * Critical conditions: the program stops right after this. * Only use this if the program is actually exited from the current * function. * * \def RPT_ERR * Error conditions: serious problem, program continues. * Use this just before you return -1 from a function. * * \def RPT_WARNING * Warning conditions: Something that the user should Fix, but the * program can continue without a real problem. * Ex: Protocol errors from a client. * * \def RPT_NOTICE * Major event in the program. * Ex: (un)loading of driver, client (dis)connect. * * \def RPT_INFO * Minor event in the program: the activation of a Setting, details of a * loaded driver, a key reservation, a keypress, a screen switch. * * \def RPT_DEBUG * Insignificant event. * Ex: What function has been called, what subpart of a function is being * executed, what was received and sent over the socket, etc. */ #define RPT_CRIT 0 #define RPT_ERR 1 #define RPT_WARNING 2 #define RPT_NOTICE 3 #define RPT_INFO 4 #define RPT_DEBUG 5 /* Don't modify these numbers, they're related to syslog! */ /* Reporting destinations */ #define RPT_DEST_STDERR 0 #define RPT_DEST_SYSLOG 1 #define RPT_DEST_STORE 2 /** Sets reporting level and message destination. */ int set_reporting( char *application_name, int new_level, int new_dest ); /** Report the message to the selected destination if important enough */ void report( const int level, const char *format, .../*args*/ ); /** * The code that this function generates will not be in the executable when * compiled without debugging. This way memory and CPU cycles are saved. */ static inline void dont_report( const int level, const char *format, .../*args*/ ) {} /** * Consider the debug function to be exactly the same as the report function. * The only difference is that it is only compiled in if DEBUG is defined. */ #ifdef DEBUG # define debug report #else # define debug dont_report #endif #endif /* REPORT_H */ lcdproc-0.5.9/shared/getopt1.c0000644000175100017510000001071712505300405013073 00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #else #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #endif #include "getopt.h" #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ lcdproc-0.5.9/shared/getopt.h0000644000175100017510000001353512505300405013020 00000000000000/* Declarations for getopt. Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if defined __STDC__ && __STDC__ const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined PROTOTYPES # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not ((defined __STDC__ && __STDC__) || defined PROTOTYPES) */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* (defined __STDC__ && __STDC__) || defined PROTOTYPES */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ lcdproc-0.5.9/shared/Makefile.am0000644000175100017510000000055612505300405013400 00000000000000## Process this file with automake to produce Makefile.in noinst_LIBRARIES = libLCDstuff.a libLCDstuff_a_SOURCES = LL.c LL.h sockets.c sockets.h str.c str.h configfile.c configfile.h report.c report.h snprintf.c snprintf.h sring.c sring.h libLCDstuff_a_LIBADD = @LIBOBJS@ AM_CPPFLAGS = -I$(top_srcdir) EXTRA_DIST = getopt.c getopt1.c getopt.h defines.h ## EOF lcdproc-0.5.9/shared/snprintf.c0000644000175100017510000013553312505300405013357 00000000000000/* * snprintf.c - a portable implementation of snprintf * * AUTHOR * Mark Martinec , April 1999. * * Copyright 1999-2002 Mark Martinec. All rights reserved. * * TERMS AND CONDITIONS * This program is free software; it is dual licensed, the terms of the * "Frontier Artistic License" or the "GNU General Public License" * can be chosen at your discretion. The chosen license then applies * solely and in its entirety. Both licenses come with this Kit. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the license for more details. * * You should have received a copy of the "Frontier Artistic License" * with this Kit in the file named LICENSE.txt, and the copy of * the "GNU General Public License" in the file named LICENSE-GPL.txt. * If not, I'll be glad to provide one. * * FEATURES * - careful adherence to specs regarding flags, field width and precision; * - good performance for large string handling (large format, large * argument or large paddings). Performance is similar to system's sprintf * and in several cases significantly better (make sure you compile with * optimizations turned on, tell the compiler the code is strict ANSI * if necessary to give it more freedom for optimizations); * - return value semantics per ISO/IEC 9899:1999 ("ISO C99"); * - written in standard ISO/ANSI C - requires an ANSI C compiler; * - works also with non-ASCII 8-bit character sets (e.g. EBCDIC) * provided strings are '\0'-terminated. * * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES * * This snprintf only supports the following conversion specifiers: * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) * with flags: '-', '+', ' ', '0' and '#'. * An asterisk is supported for field width and for the precision. * * Length modifiers 'h' (short int), 'l' (long int), * and 'll' (long long int) are supported. * NOTE: * If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the * length modifier 'll' is recognized but treated the same as 'l', * which may cause argument value truncation! Defining * SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also * handles length modifier 'll'. long long int is a language extension * which may not be portable. * * Conversion of numeric data (conversion specifiers d, u, o, x, X, p) * with length modifiers (none or h, l, ll) is left to the system routine * sprintf, but all handling of flags, field width and precision as well as * c and s conversions is done very carefully by this portable routine. * If a string precision (truncation) is specified (e.g. %.8s) it is * guaranteed the string beyond the specified precision will not be referenced. * * Length modifiers h, l and ll are ignored for c and s conversions (data * types wint_t and wchar_t are not supported). * * The following common synonyms for conversion characters are supported: * - i is a synonym for d * - D is a synonym for ld, explicit length modifiers are ignored * - U is a synonym for lu, explicit length modifiers are ignored * - O is a synonym for lo, explicit length modifiers are ignored * The D, O and U conversion characters are nonstandard, they are supported * for backward compatibility only, and should not be used for new code. * * The following is specifically NOT supported: * - flag ' (thousands' grouping character) is recognized but ignored * - numeric conversion specifiers: f, e, E, g, G and synonym F, * as well as the new a and A conversion specifiers * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead) * - wide character/string conversions: lc, ls, and nonstandard * synonyms C and S * - writeback of converted string length: conversion character n * - the n$ specification for direct reference to n-th argument * - locales * * It is permitted for str_m to be zero, and it is permitted to specify NULL * pointer for resulting string argument if str_m is zero (as per ISO C99). * * The return value is the number of characters which would be generated * for the given input, excluding the trailing null. If this value * is greater or equal to str_m, not all characters from the result * have been stored in str, output bytes beyond the (str_m-1) -th character * are discarded. If str_m is greater than zero it is guaranteed * the resulting string will be null-terminated. * * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1, * but is different from some older and vendor implementations, * and is also different from XPG, XSH5, SUSv2 specifications. * For historical discussion on changes in the semantics and standards * of snprintf see printf(3) man page in the Linux programmers manual. * * Routines asprintf and vasprintf return a pointer (in the ptr argument) * to a buffer sufficiently large to hold the resulting string. This pointer * should be passed to free(3) to release the allocated storage when it is * no longer needed. If sufficient space cannot be allocated, these functions * will return -1 and set ptr to be a NULL pointer. These two routines are a * GNU C library extensions (glibc). * * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf, * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1 * characters into the allocated output string, the last character in the * allocated buffer then gets the terminating null. If the formatted string * length (the return value) is greater than or equal to the str_m argument, * the resulting string was truncated and some of the formatted characters * were discarded. These routines present a handy way to limit the amount * of allocated memory to some sane value. * * AVAILABILITY * http://www.ijs.si/software/snprintf/ * * REVISION HISTORY * 1999-04 V0.9 Mark Martinec * - initial version, some modifications after comparing printf * man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10, * and checking how Perl handles sprintf (differently!); * 1999-04-09 V1.0 Mark Martinec * - added main test program, fixed remaining inconsistencies, * added optional (long long int) support; * 1999-04-12 V1.1 Mark Martinec * - support the 'p' conversion (pointer to void); * - if a string precision is specified * make sure the string beyond the specified precision * will not be referenced (e.g. by strlen); * 1999-04-13 V1.2 Mark Martinec * - support synonyms %D=%ld, %U=%lu, %O=%lo; * - speed up the case of long format string with few conversions; * 1999-06-30 V1.3 Mark Martinec * - fixed runaway loop (eventually crashing when str_l wraps * beyond 2^31) while copying format string without * conversion specifiers to a buffer that is too short * (thanks to Edwin Young for * spotting the problem); * - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) * to snprintf.h * 2000-02-14 V2.0 (never released) Mark Martinec * - relaxed license terms: The Artistic License now applies. * You may still apply the GNU GENERAL PUBLIC LICENSE * as was distributed with previous versions, if you prefer; * - changed REVISION HISTORY dates to use ISO 8601 date format; * - added vsnprintf (patch also independently proposed by * Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01) * 2000-06-27 V2.1 Mark Martinec * - removed POSIX check for str_m<1; value 0 for str_m is * allowed by ISO C99 (and GNU C library 2.1) - (pointed out * on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie). * Besides relaxed license this change in standards adherence * is the main reason to bump up the major version number; * - added nonstandard routines asnprintf, vasnprintf, asprintf, * vasprintf that dynamically allocate storage for the * resulting string; these routines are not compiled by default, * see comments where NEED_V?ASN?PRINTF macros are defined; * - autoconf contributed by Caolan McNamara * 2000-10-06 V2.2 Mark Martinec * - BUG FIX: the %c conversion used a temporary variable * that was no longer in scope when referenced, * possibly causing incorrect resulting character; * - BUG FIX: make precision and minimal field width unsigned * to handle huge values (2^31 <= n < 2^32) correctly; * also be more careful in the use of signed/unsigned/size_t * internal variables - probably more careful than many * vendor implementations, but there may still be a case * where huge values of str_m, precision or minimal field * could cause incorrect behaviour; * - use separate variables for signed/unsigned arguments, * and for short/int, long, and long long argument lengths * to avoid possible incompatibilities on certain * computer architectures. Also use separate variable * arg_sign to hold sign of a numeric argument, * to make code more transparent; * - some fiddling with zero padding and "0x" to make it * Linux compatible; * - systematically use macros fast_memcpy and fast_memset * instead of case-by-case hand optimization; determine some * breakeven string lengths for different architectures; * - terminology change: 'format' -> 'conversion specifier', * 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")', * 'alternative form' -> 'alternate form', * 'data type modifier' -> 'length modifier'; * - several comments rephrased and new ones added; * - make compiler not complain about 'credits' defined but * not used; * 2001-08 V2.3 Mark Martinec * .. 2002-02 - writeback conversion specifier 'n' is now supported; * - bump the size of a temporary buffer for simple * numeric->string conversion from 32 to 48 characters * in anticipation of 128-bit machines; * - added #include and to snprintf.h; * - fixed one assert in test.c * (thanks to Tuomo A Turunen for reporting this problem); * - portability fix: use isdigit() provided with * and do not assume character set is ASCII - call strtoul() * if needed to convert field width and precision; * - check for broken or non-ANSI native sprintf (e.g. SunOS) * which does not return string lenth, and work around it; * - shouldn't happen, but just in case (applies to numeric * conversions only): added assertion after a call to * system's sprintf to make sure we detect a problem * as it happens (or very shortly - but still - after a * buffer overflow occured for some strange reason * in system's sprintf); * - cleanup: avoid comparing signed and unsigned values * (ANSI c++ complaint); added a couple of 'const' qualifiers; * - changed few comments, new references to some other * implementations added to the README file; * - it appears the Artistic License and its variant the Frontier * Artistic License are incompatible with GPL and precludes * this work to be included with GPL-licensed work. This was * not my intention. The fact that this package is dual licensed * comes to the rescue. Changed the credits[] string, and * TERMS AND CONDITIONS to explicitly say so, stressing * the fact that this work is dual licensed. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* Define HAVE_SNPRINTF if your system already has snprintf and vsnprintf. * * If HAVE_SNPRINTF is defined this module will not produce code for * snprintf and vsnprintf, unless PREFER_PORTABLE_SNPRINTF is defined as well, * causing this portable version of snprintf to be called portable_snprintf * (and portable_vsnprintf). */ /* #define HAVE_SNPRINTF */ /* Define PREFER_PORTABLE_SNPRINTF if your system does have snprintf and * vsnprintf but you would prefer to use the portable routine(s) instead. * In this case the portable routine is declared as portable_snprintf * (and portable_vsnprintf) and a macro 'snprintf' (and 'vsnprintf') * is defined to expand to 'portable_v?snprintf' - see file snprintf.h . * Defining this macro is only useful if HAVE_SNPRINTF is also defined, * but does no harm if defined nevertheless. */ /* #define PREFER_PORTABLE_SNPRINTF */ /* Define SNPRINTF_LONGLONG_SUPPORT if you want to support * data type (long long int) and length modifier 'll' (e.g. %lld). * If undefined, 'll' is recognized but treated as a single 'l'. * * If the system's sprintf does not handle 'll' * the SNPRINTF_LONGLONG_SUPPORT must not be defined! * * This is off by default as (long long int) is a language extension. */ /* #define SNPRINTF_LONGLONG_SUPPORT */ /* Define NEED_SNPRINTF_ONLY if you only need snprintf, and not vsnprintf. * If NEED_SNPRINTF_ONLY is defined, the snprintf will be defined directly, * otherwise both snprintf and vsnprintf routines will be defined * and snprintf will be a simple wrapper around vsnprintf, at the expense * of an extra procedure call. */ /* #define NEED_SNPRINTF_ONLY */ /* Define NEED_V?ASN?PRINTF macros if you need library extension * routines asprintf, vasprintf, asnprintf, vasnprintf respectively, * and your system library does not provide them. They are all small * wrapper routines around portable_vsnprintf. Defining any of the four * NEED_V?ASN?PRINTF macros automatically turns off NEED_SNPRINTF_ONLY * and turns on PREFER_PORTABLE_SNPRINTF. * * Watch for name conflicts with the system library if these routines * are already present there. * * NOTE: vasprintf and vasnprintf routines need va_copy() from stdarg.h, as * specified by C99, to be able to traverse the same list of arguments twice. * I don't know of any other standard and portable way of achieving the same. * With some versions of gcc you may use __va_copy(). You might even get away * with "ap2 = ap", in this case you must not call va_end(ap2) ! * #define va_copy(ap2,ap) __va_copy((ap2),(ap)) * #define va_copy(ap2,ap) (ap2) = (ap) */ /* #define NEED_ASPRINTF */ /* #define NEED_ASNPRINTF */ /* #define NEED_VASPRINTF */ /* #define NEED_VASNPRINTF */ /* Define the following macros if desired: * SOLARIS_COMPATIBLE, SOLARIS_BUG_COMPATIBLE, * HPUX_COMPATIBLE, HPUX_BUG_COMPATIBLE, LINUX_COMPATIBLE, * DIGITAL_UNIX_COMPATIBLE, DIGITAL_UNIX_BUG_COMPATIBLE, * PERL_COMPATIBLE, PERL_BUG_COMPATIBLE, * * - For portable applications it is best not to rely on peculiarities * of a given implementation so it may be best not to define any * of the macros that select compatibility and to avoid features * that vary among the systems. * * - Selecting compatibility with more than one operating system * is not strictly forbidden but is not recommended. * * - 'x'_BUG_COMPATIBLE implies 'x'_COMPATIBLE . * * - 'x'_COMPATIBLE refers to (and enables) a behaviour that is * documented in a sprintf man page on a given operating system * and actually adhered to by the system's sprintf (but not on * most other operating systems). It may also refer to and enable * a behaviour that is declared 'undefined' or 'implementation specific' * in the man page but a given implementation behaves predictably * in a certain way. * * - 'x'_BUG_COMPATIBLE refers to (and enables) a behaviour of system's sprintf * that contradicts the sprintf man page on the same operating system. * * - I do not claim that the 'x'_COMPATIBLE and 'x'_BUG_COMPATIBLE * conditionals take into account all idiosyncrasies of a particular * implementation, there may be other incompatibilities. */ /* ============================================= */ /* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */ /* ============================================= */ #define PORTABLE_SNPRINTF_VERSION_MAJOR 2 #define PORTABLE_SNPRINTF_VERSION_MINOR 3 #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) # if defined(NEED_SNPRINTF_ONLY) # undef NEED_SNPRINTF_ONLY # endif # if !defined(PREFER_PORTABLE_SNPRINTF) # define PREFER_PORTABLE_SNPRINTF # endif #endif #if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE) #define SOLARIS_COMPATIBLE #endif #if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE) #define HPUX_COMPATIBLE #endif #if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE) #define DIGITAL_UNIX_COMPATIBLE #endif #if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE) #define PERL_COMPATIBLE #endif #if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE) #define LINUX_COMPATIBLE #endif #include #include #include #include #include #include #include #include /* For copying strings longer or equal to 'breakeven_point' * it is more efficient to call memcpy() than to do it inline. * The value depends mostly on the processor architecture, * but also on the compiler and its optimization capabilities. * The value is not critical, some small value greater than zero * will be just fine if you don't care to squeeze every drop * of performance out of the code. * * Small values favour memcpy & memset (extra procedure call, less code), * large values favour inline code (saves procedure call, more code). */ #if defined(__alpha__) || defined(__alpha) # define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc */ #endif #if defined(__i386__) || defined(__i386) # define breakeven_point 15 /* Intel Pentium/Linux - gcc 2.96 (12..30) */ #endif #if defined(__hppa) # define breakeven_point 10 /* HP-PA - gcc */ #endif #if defined(__sparc__) || defined(__sparc) # define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */ #endif /* some other values of possible interest: */ /* #define breakeven_point 8 */ /* VAX 4000 - vaxc */ /* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */ #ifndef breakeven_point # define breakeven_point 6 /* some reasonable one-size-fits-all value */ #endif #define fast_memcpy(d,s,n) \ { register size_t nn = (size_t)(n); \ if (nn >= breakeven_point) memcpy((d), (s), nn); \ else if (nn > 0) { /* call overhead is worth only for large strings*/ \ register char *dd; register const char *ss; \ for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } #define fast_memset(d,c,n) \ { register size_t nn = (size_t)(n); \ if (nn >= breakeven_point) memset((d), (int)(c), nn); \ else if (nn > 0) { /* call overhead is worth only for large strings*/ \ register char *dd; register const int cc=(int)(c); \ for (dd=(d); nn>0; nn--) *dd++ = cc; } } /* The following isdigit() is not portable (e.g. may not work * with non-ASCII character sets). Use the system-provided isdigit() * if available, otherwise uncomment: * #define isdigit(c) ((c) >= '0' && (c) <= '9') */ /* atosizet converts a span of decimal digits to a number of type size_t. * It is a macro, similar to: (but not quite, p will be modified!) * void atosizet(const char *p, const char **endp, size_t *result); * endp will point to just beyond the digits substring. * This is _not_ a general-purpose macro: * - the first argument will be modified; * - the first character must already be checked to be a digit! * NOTE: size_t could be wider than unsigned int; * but we treat numeric string like common implementations do! * If character set is ASCII (checking with a quick and simple-minded test) * we convert string to a number inline for speed, otherwise we call strtoul. */ #define atosizet(p, endp, result) \ if ((int)'0' == 48) { /* a compile-time constant expression, */ \ /* hoping the code from one branch */ \ /* will be optimized away */ \ /* looks like ASCII character set, let's hope it really is */ \ register unsigned int uj = (unsigned int)(*(p)++ - '0'); \ while (isdigit((int)(*(p)))) \ uj = 10*uj + (unsigned int)(*(p)++ - '0'); \ if ((endp) != NULL) *(endp) = (p); \ *(result) = (size_t) uj; \ } else { \ /* non-ASCII character set, play by the rules */ \ char *ep; /* NOTE: no 'const' to make strtoul happy! */ \ /* NOTE: clip (unsigned long) to (unsigned int) as is common !!! */ \ const unsigned int uj = (unsigned int) strtoul((p), &ep, 10); \ /* The following assignment is legal: the address of a non-const */ \ /* object can be assigned to a pointer to a const object, but */ \ /* that pointer cannot be used to alter the value of the object. */ \ if ((endp) != NULL) *(endp) = ep; \ /* if num too large the result will be ULONG_MAX and errno=ERANGE */ \ *(result) = (size_t) uj; \ } \ /* prototypes */ #if defined(NEED_ASPRINTF) int asprintf (char **ptr, const char *fmt, /*args*/ ...); #endif #if defined(NEED_VASPRINTF) int vasprintf (char **ptr, const char *fmt, va_list ap); #endif #if defined(NEED_ASNPRINTF) int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); #endif #if defined(NEED_VASNPRINTF) int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap); #endif #if defined(HAVE_SNPRINTF) /* declare our portable snprintf routine under name portable_snprintf */ /* declare our portable vsnprintf routine under name portable_vsnprintf */ #else /* declare our portable routines under names snprintf and vsnprintf */ #define portable_snprintf snprintf #if !defined(NEED_SNPRINTF_ONLY) #define portable_vsnprintf vsnprintf #endif #endif #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); #if !defined(NEED_SNPRINTF_ONLY) int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); #endif #endif /* declarations */ static const char credits[] = "\n\ @(#)snprintf.c, v2.3: Mark Martinec, \n\ @(#)snprintf.c, v2.3: Copyright 1999-2002 Mark Martinec. Dual licensed: Frontier Artistic License or GNU General Public License applies.\n\ @(#)snprintf.c, v2.3: http://www.ijs.si/software/snprintf/\n"; #if defined(NEED_ASPRINTF) int asprintf(char **ptr, const char *fmt, /*args*/ ...) { va_list ap; size_t str_m; int str_l; *ptr = NULL; va_start(ap, fmt); /* measure the required size */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); va_end(ap); assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ *ptr = (char *) malloc(str_m = (size_t)str_l + 1); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { int str_l2; va_start(ap, fmt); str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); va_end(ap); assert(str_l2 == str_l); } return str_l; } #endif #if defined(NEED_VASPRINTF) int vasprintf(char **ptr, const char *fmt, va_list ap) { size_t str_m; int str_l; *ptr = NULL; { va_list ap2; va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ va_end(ap2); } assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ *ptr = (char *) malloc(str_m = (size_t)str_l + 1); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { const int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); assert(str_l2 == str_l); } return str_l; } #endif #if defined(NEED_ASNPRINTF) int asnprintf(char **ptr, size_t str_m, const char *fmt, /*args*/ ...) { va_list ap; int str_l; *ptr = NULL; va_start(ap, fmt); /* measure the required size */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); va_end(ap); assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ if (str_m == 0) { /* not interested in resulting string, just return size */ } else { *ptr = (char *) malloc(str_m); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { int str_l2; va_start(ap, fmt); str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); va_end(ap); assert(str_l2 == str_l); } } return str_l; } #endif #if defined(NEED_VASNPRINTF) int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap) { int str_l; *ptr = NULL; { va_list ap2; va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ va_end(ap2); } assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ if (str_m == 0) { /* not interested in resulting string, just return size */ } else { *ptr = (char *) malloc(str_m); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { const int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); assert(str_l2 == str_l); } } return str_l; } #endif /* * If the system does have snprintf and the portable routine is not * specifically required, this module produces no code for snprintf/vsnprintf. */ #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) #if !defined(NEED_SNPRINTF_ONLY) int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { va_list ap; int str_l; va_start(ap, fmt); str_l = portable_vsnprintf(str, str_m, fmt, ap); va_end(ap); return str_l; } #endif #if defined(NEED_SNPRINTF_ONLY) int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { #else int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { #endif #if defined(NEED_SNPRINTF_ONLY) va_list ap; #endif size_t str_l = 0; const char *p = fmt; /* In contrast to POSIX, the ISO C99 now says * that str can be NULL and str_m can be 0. * This is more useful than the old: if (str_m < 1) return -1; */ #if defined(NEED_SNPRINTF_ONLY) va_start(ap, fmt); #endif if (!p) p = ""; while (*p) { if (*p != '%') { if (0) { /* compile time decision between two equivalent alternatives */ /* this is simple but slow */ if (str_l < str_m) str[str_l] = *p; p++; str_l++; } else { /* this usually achieves much better performance for cases * where format string is long and contains few conversions */ const char *const q = strchr(p+1,'%'); const size_t n = !q ? strlen(p) : (q-p); if (str_l < str_m) { const size_t avail = str_m-str_l; fast_memcpy(str+str_l, p, (n>avail?avail:n)); } p += n; str_l += n; } } else { const char *starting_p; size_t min_field_width = 0, precision = 0; int zero_padding = 0, precision_specified = 0, justify_left = 0; int alternate_form = 0, force_sign = 0; int space_for_positive = 1; /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored. */ char length_modifier = '\0'; /* allowed values: \0, h, l, L */ char tmp[48];/* temporary buffer for simple numeric->string conversion */ const char *str_arg; /* string address in case of string argument */ size_t str_arg_l; /* natural field width of arg without padding and sign */ unsigned char uchar_arg; /* unsigned char argument value - only defined for c conversion. N.B. standard explicitly states the char argument for the c conversion is unsigned */ size_t number_of_zeros_to_pad = 0; /* number of zeros to be inserted for numeric conversions as required by the precision or minimal field width */ size_t zero_padding_insertion_ind = 0; /* index into tmp where zero padding is to be inserted */ char fmt_spec = '\0'; /* current conversion specifier character */ str_arg = credits;/* just to make compiler happy (defined but not used)*/ str_arg = NULL; starting_p = p; p++; /* skip '%' */ /* parse flags */ while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' || *p == '#' || *p == '\'') { switch (*p) { case '0': zero_padding = 1; break; case '-': justify_left = 1; break; case '+': force_sign = 1; space_for_positive = 0; break; case ' ': force_sign = 1; /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ #ifdef PERL_COMPATIBLE /* ... but in Perl the last of ' ' and '+' applies */ space_for_positive = 1; #endif break; case '#': alternate_form = 1; break; case '\'': break; } p++; } /* If flags '0' and '-' both appear, the '0' flag should be ignored. */ /* parse field width */ if (*p == '*') { const int j = va_arg(ap, int); p++; if (j >= 0) min_field_width = j; else { min_field_width = -j; justify_left = 1; } } else if (isdigit((int)(*p))) { atosizet(p, &p, &min_field_width); } /* parse precision */ if (*p == '.') { p++; precision_specified = 1; if (*p == '*') { const int j = va_arg(ap, int); p++; if (j >= 0) precision = j; else { precision_specified = 0; precision = 0; /* NOTE: * Solaris 2.6 man page claims that in this case the precision * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page * claim that this case should be treated as unspecified precision, * which is what we do here. */ } } else if (isdigit((int)(*p))) { atosizet(p, &p, &precision); } } /* parse 'h', 'l' and 'll' length modifiers */ if (*p == 'h' || *p == 'l') { length_modifier = *p; p++; if (length_modifier == 'l' && *p == 'l') { /* double el = long long */ #ifdef SNPRINTF_LONGLONG_SUPPORT length_modifier = '2'; /* double letter el encoded as '2' */ #else length_modifier = 'l'; /* treat it as a single 'l' (letter el) */ #endif p++; } } fmt_spec = *p; /* common synonyms: */ switch (fmt_spec) { case 'i': fmt_spec = 'd'; break; case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; default: break; } /* get parameter value, do initial processing */ switch (fmt_spec) { case '%': /* % behaves similar to 's' regarding flags and field widths */ case 'c': /* c behaves similar to 's' regarding flags and field widths */ case 's': length_modifier = '\0'; /* wint_t and wchar_t not supported */ /* the result of zero padding flag with non-numeric conversion specifier*/ /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ /* Digital Unix and Linux does not. */ #if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE) zero_padding = 0; /* turn zero padding off for string conversions */ #endif str_arg_l = 1; switch (fmt_spec) { case '%': str_arg = p; break; case 'c': { const int j = va_arg(ap, int); uchar_arg = (unsigned char) j; /* standard demands unsigned char */ str_arg = (const char *) &uchar_arg; break; } case 's': str_arg = va_arg(ap, const char *); if (!str_arg) str_arg_l = 0; /* make sure not to address string beyond the specified precision !!! */ else if (!precision_specified) str_arg_l = strlen(str_arg); /* truncate string if necessary as requested by precision */ else if (precision == 0) str_arg_l = 0; else { /* memchr on HP does not like n > 2^31 !!! */ const char *const q = (const char *) memchr(str_arg, '\0', precision <= 0x7fffffff ? precision : 0x7fffffff); str_arg_l = !q ? precision : (q-str_arg); } break; default: break; } break; case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { /* NOTE: the u, o, x, X and p conversion specifiers imply the value is unsigned; d implies a signed value */ int arg_sign = 0; /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), +1 if greater than zero (or nonzero for unsigned arguments), -1 if negative (unsigned argument is never negative) */ int int_arg = 0; unsigned int uint_arg = 0; /* only defined for length modifier h, or for no length modifiers */ long int long_arg = 0; unsigned long int ulong_arg = 0; /* only defined for length modifier l (letter el) */ void *ptr_arg = NULL; /* pointer argument value - only defined for p conversion */ #ifdef SNPRINTF_LONGLONG_SUPPORT long long int long_long_arg = 0; unsigned long long int ulong_long_arg = 0; /* only defined for length modifier ll (double letter el) */ #endif if (fmt_spec == 'p') { /* HPUX 10: An l, h, ll or L before any other conversion character * (other than d, i, u, o, x, or X) is ignored. * Digital Unix: * not specified, but seems to behave as HPUX does. * Solaris: If an h, l, or L appears before any other conversion * specifier (other than d, i, u, o, x, or X), the behavior * is undefined. (Actually %hp converts only 16-bits of address * and %llp treats address as 64-bit data which is incompatible * with (void *) argument on a 32-bit system). */ #ifdef SOLARIS_COMPATIBLE # ifdef SOLARIS_BUG_COMPATIBLE /* keep length modifiers even if it represents 'll' */ # else if (length_modifier == '2') length_modifier = '\0'; # endif #else length_modifier = '\0'; #endif ptr_arg = va_arg(ap, void *); if (ptr_arg != NULL) arg_sign = 1; } else if (fmt_spec == 'd') { /* signed */ switch (length_modifier) { case '\0': case 'h': /* It is non-portable to specify char or short as the second argument * to va_arg, because arguments seen by the called function * are not char or short. C converts char and short arguments * to int before passing them to a function. */ int_arg = va_arg(ap, int); if (int_arg > 0) arg_sign = 1; else if (int_arg < 0) arg_sign = -1; break; case 'l': /* letter el */ long_arg = va_arg(ap, long int); if (long_arg > 0) arg_sign = 1; else if (long_arg < 0) arg_sign = -1; break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': long_long_arg = va_arg(ap, long long int); if (long_long_arg > 0) arg_sign = 1; else if (long_long_arg < 0) arg_sign = -1; break; #endif } } else { /* unsigned */ switch (length_modifier) { case '\0': case 'h': uint_arg = va_arg(ap, unsigned int); if (uint_arg) arg_sign = 1; break; case 'l': /* letter el */ ulong_arg = va_arg(ap, unsigned long int); if (ulong_arg) arg_sign = 1; break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': ulong_long_arg = va_arg(ap, unsigned long long int); if (ulong_long_arg) arg_sign = 1; break; #endif } } str_arg = tmp; str_arg_l = 0; /* NOTE: * For d, i, u, o, x, and X conversions, if precision is specified, * the '0' flag should be ignored. This is so with Solaris 2.6, * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. */ #ifndef PERL_COMPATIBLE if (precision_specified) zero_padding = 0; #endif if (fmt_spec == 'd') { if (force_sign && arg_sign >= 0) tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; /* leave negative numbers for sprintf to handle, to avoid handling tricky cases like (short int)(-32768) */ #ifdef LINUX_COMPATIBLE } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) { tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; #endif } else if (alternate_form) { if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } /* alternate form should have no effect for p conversion, but ... */ #ifdef HPUX_COMPATIBLE else if (fmt_spec == 'p' /* HPUX 10: for an alternate form of p conversion, * a nonzero result is prefixed by 0x. */ #ifndef HPUX_BUG_COMPATIBLE /* Actually it uses 0x prefix even for a zero value. */ && arg_sign != 0 #endif ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; } #endif } zero_padding_insertion_ind = str_arg_l; if (!precision_specified) precision = 1; /* default precision is 1 */ if (precision == 0 && arg_sign == 0 #if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE) && fmt_spec != 'p' /* HPUX 10 man page claims: With conversion character p the result of * converting a zero value with a precision of zero is a null string. * Actually HP returns all zeroes, and Linux returns "(nil)". */ #endif ) { /* converted to null string */ /* When zero value is formatted with an explicit precision 0, the resulting formatted string is empty (d, i, u, o, x, X, p). */ } else { static int sprintf_return_value_is_ansi_compliant = -1; /* unknown */ char f[5]; int f_l = 0, sprintf_l = 0; f[f_l++] = '%'; /* construct a simple format string for sprintf */ if (!length_modifier) { } else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } else f[f_l++] = length_modifier; f[f_l++] = fmt_spec; f[f_l++] = '\0'; if (sprintf_return_value_is_ansi_compliant < 0) { /* not yet known */ /* let's do a little run-time experiment (only once) to see if the * native sprintf returns a string length as required by ANSI, or has * some other ideas like the old SunOS which returns buffer address */ sprintf_return_value_is_ansi_compliant = (sprintf(tmp+str_arg_l, "%d", 19) == 2); } if (fmt_spec == 'p') sprintf_l=sprintf(tmp+str_arg_l, f, ptr_arg); else if (fmt_spec == 'd') { /* signed */ switch (length_modifier) { case '\0': case 'h': sprintf_l=sprintf(tmp+str_arg_l, f, int_arg); break; case 'l': sprintf_l=sprintf(tmp+str_arg_l, f, long_arg); break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': sprintf_l=sprintf(tmp+str_arg_l,f,long_long_arg); break; #endif } } else { /* unsigned */ switch (length_modifier) { case '\0': case 'h': sprintf_l=sprintf(tmp+str_arg_l, f, uint_arg); break; case 'l': sprintf_l=sprintf(tmp+str_arg_l, f, ulong_arg); break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': sprintf_l=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; #endif } } if (!sprintf_return_value_is_ansi_compliant) { /* broken sprintf? */ tmp[sizeof(tmp)-1] = '\0'; sprintf_l = strlen(tmp+str_arg_l); } assert(sprintf_l >= 0); /* should not happen; problem in sprintf? */ assert(sprintf_l+str_arg_l < sizeof(tmp)); /*better late then never*/ str_arg_l += sprintf_l; /* include the optional minus sign and possible "0x" in the region before the zero padding insertion point */ if (zero_padding_insertion_ind < str_arg_l && tmp[zero_padding_insertion_ind] == '-') { zero_padding_insertion_ind++; } if (zero_padding_insertion_ind+1 < str_arg_l && tmp[zero_padding_insertion_ind] == '0' && (tmp[zero_padding_insertion_ind+1] == 'x' || tmp[zero_padding_insertion_ind+1] == 'X') ) { zero_padding_insertion_ind += 2; } } { const size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; if (alternate_form && fmt_spec == 'o' #ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */ && (str_arg_l > 0) #endif #ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */ #else /* unless zero is already the first character */ && !(zero_padding_insertion_ind < str_arg_l && tmp[zero_padding_insertion_ind] == '0') #endif ) { /* assure leading zero for alternate-form octal numbers */ if (!precision_specified || precision < num_of_digits+1) { /* precision is increased to force the first character to be zero, except if a zero value is formatted with an explicit precision of zero */ precision = num_of_digits+1; precision_specified = 1; } } /* zero padding to specified precision? */ if (num_of_digits < precision) number_of_zeros_to_pad = precision - num_of_digits; } /* zero padding to specified minimal field width? */ if (!justify_left && zero_padding) { const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); if (n > 0) number_of_zeros_to_pad += n; } break; } case 'n': { void *const ptr = va_arg(ap, void *); if (ptr != NULL) { /* same problem of size_t -> int type conversion as with the * snprintf return value - see comment at the end of this procedure */ switch (length_modifier) { case '\0': *( int *const)ptr = str_l; break; case 'h': *(short int *const)ptr = str_l; break; case 'l': *(long int *const)ptr = str_l; break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': *(long long int *const)ptr = str_l; break; #endif } } /* no argument converted */ min_field_width = number_of_zeros_to_pad = str_arg_l = 0; break; } default: /* unrecognized conversion specifier, keep format string as-is*/ zero_padding = 0; /* turn zero padding off for non-numeric convers. */ #ifndef DIGITAL_UNIX_COMPATIBLE justify_left = 1; min_field_width = 0; /* reset flags */ #endif #if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE) /* keep the entire format string unchanged */ str_arg = starting_p; str_arg_l = p - starting_p; /* well, not exactly so for Linux, which does something inbetween, * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */ #else /* discard the unrecognized conversion, just keep * * the unrecognized conversion character */ str_arg = p; str_arg_l = 0; #endif if (*p) str_arg_l++; /* include invalid conversion specifier unchanged if not at end-of-string */ break; } if (*p) p++; /* step over the just processed conversion specifier */ /* insert padding to the left as requested by min_field_width; this does not include the zero padding in case of numerical conversions*/ if (!justify_left) { /* left padding with blank or zero */ const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); if (n > 0) { if (str_l < str_m) { const size_t avail = str_m-str_l; fast_memset(str+str_l, (zero_padding?'0':' '), ((unsigned int)n > avail ? avail : (unsigned int)n)); } str_l += n; } } /* is zero padding as requested by the precision or by the * minimal field width for numeric conversions required? */ if (number_of_zeros_to_pad <= 0) { /* will not copy the first part of numeric right now, * * force it to be copied later in its entirety */ zero_padding_insertion_ind = 0; } else { /* insert first part of numerics (sign or '0x') before zero padding */ { const int n = zero_padding_insertion_ind; if (n > 0) { if (str_l < str_m) { const size_t avail = str_m-str_l; fast_memcpy(str+str_l, str_arg, ((unsigned int)n > avail ? avail : (unsigned int)n)); } str_l += n; } } /* insert zero padding as requested by the precision or min field width */ { const int n = number_of_zeros_to_pad; if (n > 0) { if (str_l < str_m) { const size_t avail = str_m-str_l; fast_memset(str+str_l, '0', ((unsigned int)n > avail ? avail : (unsigned int)n)); } str_l += n; } } } /* insert formatted string * (or as-is conversion specifier for unknown conversions) */ { const int n = str_arg_l - zero_padding_insertion_ind; if (n > 0) { if (str_l < str_m) { const size_t avail = str_m-str_l; fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, ((unsigned int)n > avail ? avail : (unsigned int)n)); } str_l += n; } } /* insert right padding */ if (justify_left) { /* right blank padding to the field width */ const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); if (n > 0) { if (str_l < str_m) { const size_t avail = str_m-str_l; fast_memset(str+str_l, ' ', ((unsigned int)n > avail ? avail : (unsigned int)n)); } str_l += n; } } } } #if defined(NEED_SNPRINTF_ONLY) va_end(ap); #endif if (str_m > 0) { /* make sure the string is null-terminated, possibly at the expense of overwriting the last character */ str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; } /* Return the number of characters formatted (excluding trailing null * character), that is, the number of characters that would have been * written to the buffer if it were large enough. * * The value of str_l should be returned, but str_l is of unsigned type * size_t, and snprintf is int, possibly leading to an undetected * integer overflow, resulting in a negative return value, which is invalid. * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. * Should errno be set to EOVERFLOW and EOF returned in this case??? */ return (int) str_l; } #endif lcdproc-0.5.9/shared/str.h0000644000175100017510000000026512505300405012322 00000000000000/** \file shared/str.h * Commmand / argument parsing functions (for use in clients). */ #ifndef STR_H #define STR_H int get_args (char **argv, char *str, int max_args); #endif lcdproc-0.5.9/shared/snprintf.h0000644000175100017510000000173412505300405013357 00000000000000#ifndef _PORTABLE_SNPRINTF_H_ #define _PORTABLE_SNPRINTF_H_ #define PORTABLE_SNPRINTF_VERSION_MAJOR 2 #define PORTABLE_SNPRINTF_VERSION_MINOR 2 #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_SNPRINTF #include #else extern int snprintf(char *, size_t, const char *, /*args*/ ...); extern int vsnprintf(char *, size_t, const char *, va_list); #endif #if defined(HAVE_SNPRINTF) && defined(PREFER_PORTABLE_SNPRINTF) extern int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); extern int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); #define snprintf portable_snprintf #define vsnprintf portable_vsnprintf #endif extern int asprintf (char **ptr, const char *fmt, /*args*/ ...); extern int vasprintf (char **ptr, const char *fmt, va_list ap); extern int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); extern int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap); #endif lcdproc-0.5.9/shared/sring.c0000644000175100017510000001252312505300405012627 00000000000000/** \file shared/sring.c * Circular buffer implementation for string processing. * * \todo Implement sring_peek() and sring_skip(). */ /*- * This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 2009, Markus Dolze */ #include #include #ifdef DEBUG # include # include #endif #include "sring.h" /** * Allocate a new ring buffer data structure. * As this ring buffer is implemented using the 'Always Keep One Byte Open' * strategy, the internal data buffer is (iSize+1) large. * * \param iSize Initial size of the ring buffer * \return Pointer to the created ring buffer */ sring_buffer* sring_create(int iSize) { sring_buffer *buf; if ((buf = malloc(sizeof(*buf))) == NULL) return NULL; if ((buf->data = malloc(iSize + 1)) == NULL) return NULL; buf->size = iSize + 1; buf->w = 0; buf->r = 0; return buf; } /** * Free memory used by ring buffer. * \param buf Ring buffer to work on */ void sring_destroy(sring_buffer *buf) { if (buf == NULL) return; free(buf->data); buf->data = NULL; free(buf); } /** * Clears the internal ring buffer. * Existing data is overwritten with NUL bytes. * * \param buf Ring buffer to work on */ void sring_clear(sring_buffer *buf) { if (buf == NULL) return; buf->w = 0; buf->r = 0; memset(buf->data, '\0', buf->size); } /** * Get the number of bytes that can be written. * \param buf Ring buffer to work on * \return Byte count */ int sring_getMaxWrite(sring_buffer *buf) { int nBytes; if (buf == NULL) return 0; /* Use 'Always Keep One Byte Open' strategy */ if (buf->w < buf->r) nBytes = buf->r - buf->w - 1; else nBytes = (buf->size - buf->w) + buf->r - 1; return nBytes; } /** * Get the number of bytes that can be read. * \param buf Ring buffer to work on * \return Byte count */ int sring_getMaxRead(sring_buffer *buf) { int nBytes; if (buf == NULL) return 0; if (buf->r <= buf->w) nBytes = buf->w - buf->r; else nBytes = (buf->size - buf->r) + buf->w; return nBytes; } /** * Write src_len bytes from src into ring buffer. * Fails if not all bytes can be written. * * \param buf Ring buffer to work on * \param src Pointer to source buffer * \param src_len Number of bytes to write at most * \return -1 if not all bytes can be written, 0 otherwise */ int sring_write(sring_buffer *buf, char *src, int src_len) { if (buf == NULL || src == NULL || src_len <= 0) return -1; /* XXX: Modify it to write as much as possible? */ if (src_len > sring_getMaxWrite(buf)) return -1; if (buf->w + src_len < buf->size) { memcpy(buf->data + buf->w, src, src_len); buf->w += src_len; } else { int firstBlockLen = buf->size - buf->w; int secondBlockLen = src_len - firstBlockLen; memcpy(buf->data + buf->w, src, firstBlockLen); memcpy(buf->data, src + firstBlockLen, secondBlockLen); buf->w = secondBlockLen; } return 0; } /** * Read dst_len bytes from ring buffer into destination. * Fails if buffer does not contains dst_len bytes to read from. The target * buffer must be allocated by the application before calling this function. * * \param buf Ring buffer to work on * \param dst Pointer to target buffer * \param dst_len Number of bytes to read at most * \return The number of bytes actually read */ int sring_read(sring_buffer *buf, char *dst, int dst_len) { if (buf == NULL || dst == NULL || dst_len <= 0) return -1; /* Do not read more than available */ if (dst_len > sring_getMaxRead(buf)) dst_len = sring_getMaxRead(buf); if (buf->r + dst_len < buf->size) { memcpy(dst, buf->data + buf->r, dst_len); buf->r += dst_len; } else { int firstBlockLen = buf->size - buf->r; int secondBlockLen = dst_len - firstBlockLen; memcpy(dst, buf->data + buf->r, firstBlockLen); if (secondBlockLen > 0) memcpy(dst + firstBlockLen, buf->data, secondBlockLen); buf->r = secondBlockLen; } return dst_len; } /** * Return the next string from the ring buffer. * The next string is a sequence of bytes terminated by \\r, \\n or \\0. The * memory for the string is allocated dynamically and must be free'd by the * application. The string is always NUL terminated, but does not include the * end character. * * \param buf Ring buffer to work on * \return Pointer to allocated string, NULL if no string is available */ char * sring_read_string(sring_buffer *buf) { int n; char *border; char *p; char *dst; int dst_len; if (buf == NULL) return NULL; n = sring_getMaxRead(buf); border = buf->data + buf->size; p = buf->data + buf->r; while (--n >= 0) { if (*p == '\r' || *p == '\n' || *p == '\0') break; p++; if (p == border) p = buf->data; }; if (n == -1) return NULL; dst_len = sring_getMaxRead(buf) - n; if ((dst = malloc(dst_len)) == NULL) return NULL; sring_read(buf, dst, dst_len); dst[dst_len-1] = '\0'; return dst; } /** * Print content of buffer to stdout. * Only enabled, if DEBUG is defined. * * \param buf Ring buffer to work on */ void sring_dump(sring_buffer *buf) { #ifdef DEBUG int a; if (buf == NULL) return; for (a = 0; a < buf->size; a++) { if (isprint(buf->data[a])) printf("'%c' ", buf->data[a]); else printf("0x%02X ", buf->data[a]); } printf("\n"); #endif } lcdproc-0.5.9/shared/sockets.h0000644000175100017510000000221312505300405013160 00000000000000/** \file shared/sockets.h * Socket functions available to server and clients. */ #ifndef SOCKETS_H #define SOCKETS_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef LCDPORT # define LCDPORT 13666 #endif #ifndef SHUT_RDWR # define SHUT_RDWR 2 #endif /** Connect to server on host, port */ int sock_connect (char *host, unsigned short int port); /** Disconnect from server */ int sock_close (int fd); /** Send printf-like formatted output */ int sock_printf (int fd, const char *format, .../*args*/); /** Send lines of text */ int sock_send_string (int fd, char *string); /** Send raw data */ int sock_send (int fd, void *src, size_t size); /** Receive a line of text */ int sock_recv_string (int fd, char *dest, size_t maxlen); /** Receive raw data */ int sock_recv (int fd, void *dest, size_t maxlen); /** Return the error message for the last error occured */ char *sock_geterror(void); /** Send an already formatted error message to the client */ int sock_send_error(int fd, char* message); /** Print printf-like formatted output to logfile and send it to the client */ int sock_printf_error(int fd, const char *format, .../*args*/); #endif lcdproc-0.5.9/shared/getopt.c0000644000175100017510000007240612505300405013015 00000000000000/* Getopt for GNU. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include "config.h" #else # if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ # ifdef HAVE_LIBINTL_H # include # define _(msgid) gettext (msgid) # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } # ifdef text_set_element text_set_element (__libc_subinit, store_args_and_env); # endif /* text_set_element */ # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ lcdproc-0.5.9/shared/sring.h0000644000175100017510000000130312505300405012626 00000000000000#ifndef SRING_H #define SRING_H /** Ring buffer data structure */ typedef struct sring_buffer_t { char *data; /**< Dynamically allocated data storage */ unsigned int size; /**< The buffer's size */ unsigned int w; /**< write pointer */ unsigned int r; /**< read pointer */ } sring_buffer; sring_buffer* sring_create(int iSize); void sring_destroy(sring_buffer *buf); void sring_clear(sring_buffer *buf); int sring_getMaxWrite(sring_buffer *buf); int sring_getMaxRead(sring_buffer *buf); int sring_write(sring_buffer *buf, char *src, int src_len); int sring_read(sring_buffer *buf, char *dst, int dst_len); char* sring_read_string(sring_buffer *buf); void sring_dump(sring_buffer *buf); #endif lcdproc-0.5.9/shared/sockets.c0000644000175100017510000001615413063062414013171 00000000000000/** \file shared/sockets.c * Socket functions available to server and clients. */ /*- * This file is part of LCDproc. * * Feel free to use this in your own clients... :) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "report.h" #include "sockets.h" // Length of longest transmission allowed at once... #define MAXMSG 8192 typedef struct sockaddr_in sockaddr_in; /** * Tries to resolve a resolve a hostname. * \param name Pointer to resolves IP-address * \param hostname Hostname or IP-address (as string) * \param port Port number * \return 0 on success, -1 on error. */ static int sock_init_sockaddr (sockaddr_in *name, const char *hostname, unsigned short int port) { struct hostent *hostinfo; memset (name, '\0', sizeof (*name)); name->sin_family = AF_INET; name->sin_port = htons (port); hostinfo = gethostbyname (hostname); if (hostinfo == NULL) { report (RPT_ERR, "sock_init_sockaddr: Unknown host %s.", hostname); return -1; } name->sin_addr = *(struct in_addr *) hostinfo->h_addr; return 0; } /** * Connect to server. * \param host Hostname or IP-address * \param port Port number * \return socket file descriptor on success, -1 on error */ int sock_connect (char *host, unsigned short int port) { struct sockaddr_in servername; int sock; int err = 0; report (RPT_DEBUG, "sock_connect: Creating socket"); sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0) { report (RPT_ERR, "sock_connect: Error creating socket"); return sock; } debug (RPT_DEBUG, "sock_connect: Created socket (%i)", sock); if (sock_init_sockaddr (&servername, host, port) < 0) return -1; err = connect (sock, (struct sockaddr *) &servername, sizeof (servername)); if (err < 0) { report (RPT_ERR, "sock_connect: connect failed"); shutdown (sock, SHUT_RDWR); return -1; } fcntl (sock, F_SETFL, O_NONBLOCK); return sock; } /** * Disconnect from server. * \param fd Socket file descriptor * \return 0 on success, -1 on error. */ int sock_close (int fd) { int err; err = shutdown (fd, SHUT_RDWR); if (!err) close (fd); return err; } /** * Send printf-like formatted output. * \param fd Socket file descriptor * \param format Format string * \param ... Arguments to the format string * \return Number of bytes sent. */ int sock_printf(int fd, const char *format, .../*args*/ ) { char buf[MAXMSG]; va_list ap; int size = 0; va_start(ap, format); size = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); if (size < 0) { report(RPT_ERR, "sock_printf: vsnprintf failed"); return -1; } if (size > sizeof(buf)) report(RPT_WARNING, "sock_printf: vsnprintf truncated message"); return sock_send_string(fd, buf); } /** * Send lines of text. * \param fd Socket file descriptor * \param string Pointer to the string to send. * \return Number of bytes sent. */ int sock_send_string (int fd, char *string) { return sock_send(fd, string, strlen(string)); } /** * Receive a line of text. * Recv gives only one line per call... * \param fd Socket file descriptor * \param dest Pointer to buffer to store the received data * \param maxlen Number of bytes to read at most (size of buffer) * \return Number of bytes received. */ int sock_recv_string (int fd, char *dest, size_t maxlen) { char *ptr = dest; int recvBytes = 0; if (!dest) return -1; if (maxlen <= 0) return 0; while (1) { int err = read (fd, ptr, 1); if (err == -1) { if (errno == EAGAIN) { if (recvBytes) { // We've begun to read a string, but no bytes are // available. Loop. continue; } return 0; } else { report (RPT_ERR, "sock_recv_string: socket read error"); return err; } } else if (err == 0) { return recvBytes; } recvBytes++; // stop at max. bytes allowed, at NUL or at LF if (recvBytes == maxlen || *ptr == '\0' || *ptr == '\n') { *ptr = '\0'; break; } ptr++; } // Don't return an empty string if (recvBytes == 1 && dest[0] == '\0') return 0; if (recvBytes < maxlen - 1) dest[recvBytes] = '\0'; return recvBytes; } /** * Send raw data. * \param fd Socket file descriptor * \param src Buffer holding the data to send * \param size Number of bytes to send at most * \return Number of bytes sent. */ int sock_send (int fd, void *src, size_t size) { int offset = 0; if (!src) return -1; while (offset != size) { // write isn't guaranteed to send the entire string at once, // so we have to sent it in a loop like this int sent = write (fd, ((char *) src) + offset, size - offset); if (sent == -1) { if (errno != EAGAIN) { report (RPT_ERR, "sock_send: socket write error"); report (RPT_DEBUG, "Message was: '%.*s'", size-offset, (char *) src); return sent; } continue; } else if (sent == 0) { // when this returns zero, it generally means // we got disconnected return sent + offset; } offset += sent; } return offset; } /** * Receive raw data. * \param fd Socket file descriptor * \param dest Pointer to buffer to store the received data * \param maxlen Number of bytes to read at most (size of buffer) * \return Number of bytes received. */ int sock_recv (int fd, void *dest, size_t maxlen) { int err; if (!dest) return -1; if (maxlen <= 0) return 0; err = read (fd, dest, maxlen); if (err < 0) { //report (RPT_DEBUG,"sock_recv: socket read error"); return err; } //debug(RPT_DEBUG, "sock_recv: Got message \"%s\"", (char *)dest); return err; } /*****************************************************************************/ /** * Return the error message for the last error occured. * \return Error message string */ char* sock_geterror(void) { return strerror(errno); } /** * Send an already formatted error message to the client. * \param fd socket * \param message the message to send (without the "huh? ") */ int sock_send_error(int fd, char* message) { // simple: performance penalty isn't worth more work... return sock_printf_error(fd, "%s", message); } /** * Print printf-like formatted output to logfile and sends it to the client. * \note don't add a the "huh? " to the message. This is done by this * method * \param fd socket * \param format a printf format */ int sock_printf_error(int fd, const char *format, .../*args*/ ) { static const char huh[] = "huh? "; char buf[MAXMSG]; va_list ap; int size = 0; strncpy(buf, huh, sizeof(huh)); // note: sizeof(huh) < MAXMSG va_start(ap, format); size = vsnprintf(buf + (sizeof(huh)-1), sizeof(buf) - (sizeof(huh)-1), format, ap); buf[sizeof(buf)-1] = '\0'; va_end(ap); if (size < 0) { report(RPT_ERR, "sock_printf_error: vsnprintf failed"); return -1; } if (size >= sizeof(buf) - (sizeof(huh)-1)) report(RPT_WARNING, "sock_printf_error: vsnprintf truncated message"); report(RPT_INFO, "client error: %s", buf); return sock_send_string(fd, buf); } lcdproc-0.5.9/shared/configfile.c0000644000175100017510000005451313050420753013624 00000000000000/** \file configfile.c * Define routines to read INI-file like files. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright(c) 2001, Joris Robijn * (c) 2003, Rene Wagner * (c) 2006,2007 Peter Marschall * */ #include #include #include #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "shared/report.h" /** configuration key */ typedef struct _config_key { char *name; /**< name of the config key */ char *value; /**< value of the config key */ struct _config_key *next_key; /**< pointer to next config key */ } ConfigKey; /** configuration section */ typedef struct _config_section { char *name; /**< name of the config section */ ConfigKey *first_key; /**< config keys in the config section */ struct _config_section *next_section; /**< pointer to next config section */ } ConfigSection; static ConfigSection *first_section = NULL; /* Yes there is a static. It's C after all :)*/ static ConfigSection *find_section(const char *sectionname); static ConfigSection *add_section(const char *sectionname); static ConfigKey *find_key(ConfigSection *s, const char *keyname, int skip); static ConfigKey *add_key(ConfigSection *s, const char *keyname, const char *value); #if defined(LCDPROC_CONFIG_READ_STRING) static char get_next_char_f(FILE *f); static int process_config(ConfigSection **current_section, char(*get_next_char)(), const char *source_descr, FILE *f); #else static int process_config(ConfigSection **current_section, const char *source_descr, FILE *f); #endif /**** PUBLIC FUNCTIONS ****/ /** Parse configuration from INI-file style config file into memory. * \param filename Name of the config file. * \retval 0 config successfully parsed * \retval <0 error occurred */ int config_read_file(const char *filename) { FILE *f; ConfigSection *curr_section = NULL; int result = 0; report(RPT_NOTICE, "Using Configuration File: %s", filename); f = fopen(filename, "r"); if (f == NULL) { return -1; } #if defined(LCDPROC_CONFIG_READ_STRING) result = process_config(&curr_section, get_next_char_f, filename, f); #else result = process_config(&curr_section, filename, f); #endif fclose(f); return result; } #if defined(LCDPROC_CONFIG_READ_STRING) int config_read_string(const char *sectionname, const char *str) /* All the config parameters are placed in the given section in memory.*/ { int pos = 0; ConfigSection *s; /* We use a nested function to transfer the characters from buffer to parser*/ char get_next_char() { return str[pos++]; } if ((s = find_section(sectionname)) == NULL) s = add_section(sectionname); return process_config(&s, get_next_char, "command line", NULL); } #endif /** Get string from configuration in memory. * * The strings returned are always NUL-terminated. * They should never be modified, and used only short-term. * In successive calls this function can re-use the data space ! * * You can do some things with the returned string: * \li Scan or parse it: * \code * s = config_get_string(...); * sscanf(s, "%dx%d", &w, &h); // scan format like: 20x4 * \endcode * ...and check the w and h values... * \li Copy it to a pre-allocated buffer like \c device[256]: * \code * s = config_get_string(...); * strncpy(device, s, sizeof(device)); * device[sizeof(device)-1] = '\0'; // make sure it is terminated * \endcode * \li Copy it to a newly allocated space in \c char \c *device: * \code * s = config_get_string(...); * device = malloc(strlen(s)+1); * if (device == NULL) return -5; // or whatever < 0 * strcpy( device, s ); * \endcode * * \param sectionname Name of the section where the key is sought. * \param keyname Name of the key to look for. * \param skip Number of values to skip/ignore before returning the value. * This is used to iterate through the values of a multi-valued key: * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last. * \param default_value Default value if section/key is not found * or \c skip exceeds the number of values of the key. * \return Value found / \c default_value */ const char *config_get_string(const char *sectionname, const char *keyname, int skip, const char *default_value) { ConfigKey *k = find_key(find_section(sectionname), keyname, skip); if (k == NULL) return default_value; return k->value; /* This is the safer way:*/ /* Reallocate memory space for the return value*/ /* string_storage = realloc(string_storage,(strlen(k->value) / 256 + 1) * 256); strcpy(string_storage, k->value); But then you also need a global static string_storage = NULL; */ } /** Get boolean value from configuration in memory. * * Legal boolean values are: * \li \c 0 , \c false , \c off , \c no or \c n for FALSE. * \li \c 1 , \c true , \c on , \c yes or \c y for TRUE * * \param sectionname Name of the section where the key is sought. * \param keyname Name of the key to look for. * \param skip Number of values to skip/ignore before returning the value. * This is used to iterate through the values of a multi-valued key: * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last. * \param default_value Default value if section/key is not found, value is no legal boolean, * or \c skip exceeds the number of values of the key. * \return Value found / \c default_value */ short config_get_bool(const char *sectionname, const char *keyname, int skip, short default_value) { ConfigKey *k = find_key(find_section(sectionname), keyname, skip); if (k == NULL) return default_value; if ((strcasecmp(k->value, "0") == 0) || (strcasecmp(k->value, "false") == 0) || (strcasecmp(k->value, "n") == 0) || (strcasecmp(k->value, "no") == 0) || (strcasecmp(k->value, "off") == 0)) { return 0; } if ((strcasecmp(k->value, "1") == 0) || (strcasecmp(k->value, "true") == 0) || (strcasecmp(k->value, "y") == 0) || (strcasecmp(k->value, "yes") == 0) || (strcasecmp(k->value, "on") == 0)) { return 1; } return default_value; } /** Get tristate value from configuration in memory. * * Legal tristate values are: * \li \c 0 , \c false , \c off , \c no or \c n for 0. * \li \c 1 , \c true , \c on , \c yes or \c y for 1 * \li \c 2 or the given name of the third state for 2 * * \param sectionname Name of the section where the key is sought. * \param keyname Name of the key to look for. * \param skip Number of values to skip/ignore before returning the value. * This is used to iterate through the values of a multi-valued key: * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last. * \param name3rd Name of the 3rd state * \param default_value Default value if section/key is not found, value is no legal boolean, * or \c skip exceeds the number of values of the key. * \return Value found / \c default_value */ short config_get_tristate(const char *sectionname, const char *keyname, int skip, const char *name3rd, short default_value) { ConfigKey *k = find_key(find_section(sectionname), keyname, skip); if (k == NULL) return default_value; if ((strcasecmp(k->value, "0") == 0) || (strcasecmp(k->value, "false") == 0) || (strcasecmp(k->value, "n") == 0) || (strcasecmp(k->value, "no") == 0) || (strcasecmp(k->value, "off") == 0)) { return 0; } if ((strcasecmp(k->value, "1") == 0) || (strcasecmp(k->value, "true") == 0) || (strcasecmp(k->value, "y") == 0) || (strcasecmp(k->value, "yes") == 0) || (strcasecmp(k->value, "on") == 0)) { return 1; } if ((strcasecmp(k->value, "2") == 0) || ((name3rd != NULL) && (strcasecmp(k->value, name3rd) == 0))) { return 2; } return default_value; } /** Get integer from configuration in memory. * \param sectionname Name of the section where the key is sought. * \param keyname Name of the key to look for. * \param skip Number of values to skip/ignore before returning the value. * This is used to iterate through the values of a multi-valued key: * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last. * \param default_value Default value if section/key is not found, value is no integer, * or \c skip exceeds the number of values of the key. * \return Value found / \c default_value */ long int config_get_int(const char *sectionname, const char *keyname, int skip, long int default_value) { ConfigKey *k = find_key(find_section(sectionname), keyname, skip); if (k != NULL) { char *end; long int v = strtol(k->value, &end, 0); if ((end != NULL) && (end != k->value) && (*end == '\0')) /* Conversion successful */ return v; } return default_value; } /** Get floating point number from configuration in memory. * \param sectionname Name of the section where the key is sought. * \param keyname Name of the key to look for. * \param skip Number of values to skip/ignore before returning the value. * This is used to iterate through the values of a multi-valued key: * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last. * \param default_value Default value if section/key is not found, value is no floating point number * or \c skip exceeds the number of values of the key. * \return Value found / \c default_value */ double config_get_float(const char *sectionname, const char *keyname, int skip, double default_value) { ConfigKey *k = find_key(find_section(sectionname), keyname, skip); if (k != NULL) { char *end; double v = strtod(k->value, &end); if ((end != NULL) && (end != k->value) && (*end == '\0')) /* Conversion successful*/ return v; } return default_value; } /** Test whether the configuration contains a specific section. * \param sectionname Name of the section to look for. * \retval 0 section not in config * \retval 1 section in config */ int config_has_section(const char *sectionname) { return (find_section(sectionname) != NULL) ? 1 : 0; } /** Test whether the configuration contains a specific key in a specific section. * \param sectionname Name of the section where the key is sought. * \param keyname Name of the key to look for. * \retval 0 key or section not found * \retval n key found with \c n values (\c n > 0) */ int config_has_key(const char *sectionname, const char *keyname) { ConfigSection *s = find_section(sectionname); int count = 0; if (s != NULL) { ConfigKey *k; for (k = s->first_key; k != NULL; k = k->next_key) { /* Did we find the right key ?*/ if (strcasecmp(k->name, keyname) == 0) count++; } } return count; } /** Clear configuration. */ void config_clear(void) { ConfigSection *s; ConfigSection *next_s; for (s = first_section; s != NULL; s = next_s) { ConfigKey *k; ConfigKey *next_k; for (k = s->first_key; k != NULL; k = next_k) { /* Advance before we destroy the current key */ next_k = k->next_key; free(k->name); free(k->value); free(k); } /* Advance before we destroy the current section */ next_s = s->next_section; /* And destroy it */ free(s->name); free(s); } /* Finally make everything inaccessible */ first_section = NULL; } /**** INTERNAL FUNCTIONS ****/ static ConfigSection *find_section(const char *sectionname) { ConfigSection *s; for (s = first_section; s != NULL; s = s->next_section) { if (strcasecmp(s->name, sectionname) == 0) { return s; } } return NULL; /* not found */ } static ConfigSection *add_section(const char *sectionname) { ConfigSection *s; ConfigSection **place = &first_section; for (s = first_section; s != NULL; s = s->next_section) place = &(s->next_section); *place = (ConfigSection *) malloc(sizeof(ConfigSection)); if (*place != NULL) { (*place)->name = strdup(sectionname); (*place)->first_key = NULL; (*place)->next_section = NULL; } return(*place); } static ConfigKey *find_key(ConfigSection *s, const char *keyname, int skip) { ConfigKey *k; int count = 0; ConfigKey *last_key = NULL; /* Check for NULL section*/ if (s == NULL) return NULL; for (k = s->first_key; k != NULL; k = k->next_key) { /* Did we find the right key ?*/ if (strcasecmp(k->name, keyname) == 0) { if (count == skip) return k; count++; last_key = k; } } if (skip == -1) return last_key; return NULL; /* not found*/ } static ConfigKey *add_key(ConfigSection *s, const char *keyname, const char *value) { if (s != NULL) { ConfigKey *k; ConfigKey **place = &(s->first_key); for (k = s->first_key; k != NULL; k = k->next_key) place = &(k->next_key); *place = (ConfigKey *) malloc(sizeof(ConfigKey)); if (*place != NULL) { (*place)->name = strdup(keyname); (*place)->value = strdup(value); (*place)->next_key = NULL; } return(*place); } return NULL; } #if defined(LCDPROC_CONFIG_READ_STRING) static char get_next_char_f(FILE *f) { int c = fgetc(f); return((c == EOF) ? '\0' : c); } #endif /* Parser states */ #define ST_INITIAL 0 #define ST_COMMENT 257 #define ST_SECTIONLABEL 258 #define ST_KEYNAME 259 #define ST_ASSIGNMENT 260 #define ST_VALUE 261 #define ST_QUOTEDVALUE 262 #define ST_SECTIONLABEL_DONE 263 #define ST_VALUE_DONE 264 #define ST_INVALID_SECTIONLABEL 265 #define ST_INVALID_KEYNAME 266 #define ST_INVALID_ASSIGNMENT 267 #define ST_INVALID_VALUE 268 #define ST_END 999 /* Limits */ #define MAXSECTIONLABELLENGTH 40 #define MAXKEYNAMELENGTH 40 #define MAXVALUELENGTH 200 #if defined(LCDPROC_CONFIG_READ_STRING) static int process_config(ConfigSection **current_section, char(*get_next_char)(), const char *source_descr, FILE *f) #else static int process_config(ConfigSection **current_section, const char *source_descr, FILE *f) #endif { int state = ST_INITIAL; int ch; char sectionname[MAXSECTIONLABELLENGTH+1]; int sectionname_pos = 0; char keyname[MAXKEYNAMELENGTH+1]; int keyname_pos = 0; char value[MAXVALUELENGTH+1]; int value_pos = 0; int escape = 0; int line_nr = 1; int error = 0; #if !defined(LCDPROC_CONFIG_READ_STRING) if (f == NULL) return(0); #endif while (state != ST_END) { #if defined(LCDPROC_CONFIG_READ_STRING) ch = (f != NULL) ? get_next_char(f) : get_next_char(); #else ch = fgetc(f); if (ch == EOF) ch = '\0'; #endif /* Secretly keep count of the line numbers */ if (ch == '\n') line_nr++; switch (state) { case ST_INITIAL: switch (ch) { case '#': case ';': /* comment start */ state = ST_COMMENT; /* fall through */ case '\0': case '\n': case '\r': case '\t': case ' ': /* ignore spaces */ break; case '[': /* section name */ state = ST_SECTIONLABEL; sectionname_pos = 0; sectionname[sectionname_pos] = '\0'; break; default: /* key word */ state = ST_KEYNAME; keyname_pos = 0; keyname[keyname_pos++] = ch; keyname[keyname_pos] = '\0'; } break; case ST_SECTIONLABEL: /* section label: "["{non-space chars}+"]" */ switch (ch) { case '\0': case '\n': /* premature end of label */ report(RPT_WARNING, "Unterminated section label on line %d of %s: %s", line_nr, source_descr, sectionname); error = 1; state = ST_INITIAL; /* already at the end, no resync required */ break; case ']': /* label terminated: find/create section */ if (!(*current_section = find_section(sectionname))) { *current_section = add_section(sectionname); } state = ST_SECTIONLABEL_DONE; break; // case '\r': // case '\t': // case ' ': // /* no spaces allowed in section labels WHY? */ // report(RPT_WARNING, "Invalid character in section label on line %d of %s: %s", // line_nr, source_descr, sectionname); // error = 1; // state = ST_INVALID_SECTIONLABEL; /* resync required */ // break; default: /* append char to section label */ if (sectionname_pos < MAXSECTIONLABELLENGTH) { sectionname[sectionname_pos++] = ch; sectionname[sectionname_pos] = '\0'; break; } report(RPT_WARNING, "Section name too long on line %d of %s: %s", line_nr, source_descr, sectionname); error = 1; state = ST_INVALID_SECTIONLABEL; /* resync required */ } break; case ST_KEYNAME: /* key name: {non-space chars}+ */ switch (ch) { case '\r': case '\t': case ' ': /* ignore trailing spaces */ if (keyname_pos != 0) state = ST_ASSIGNMENT; break; case '\0': case '\n': /* premature end of line */ report(RPT_WARNING, "Loose word found on line %d of %s: %s", line_nr, source_descr, keyname); error = 1; state = ST_INITIAL; /* already at the end; no resync required */ break; case '=': /* end of key reached, "=" found, now we need a value */ state = ST_VALUE; value[0] = '\0'; value_pos = 0; break; // case '"': // case '[': // case ']': // /* character invalid in key names WHY ? */ // report(RPT_WARNING, "Invalid character in key name on line %d of %s: %s", // line_nr, source_descr, keyname); // error = 1; // state = ST_INVALID_KEYNAME; /* resync required */ // break; default: /* append char to key name */ if (keyname_pos < MAXKEYNAMELENGTH) { keyname[keyname_pos++] = ch; keyname[keyname_pos] = '\0'; break; } report(RPT_WARNING, "Key name too long on line %d of %s: %s", line_nr, source_descr, keyname); error = 1; state = ST_INVALID_KEYNAME; /* resync required */ } break; case ST_ASSIGNMENT: /* assignment: "=" */ switch (ch) { case '\t': case ' ': /* ignore leading spaces */ break; case '=': /* "=" found, now we need a value */ state = ST_VALUE; value[0] = '\0'; value_pos = 0; break; default: report(RPT_WARNING, "Assignment expected on line %d of %s: %s", line_nr, source_descr, keyname); error = 1; state = ST_INVALID_ASSIGNMENT; } break; case ST_VALUE: /* value: {non-space char}+ | "\""{any potentially-quoted char}+"\"" */ switch (ch) { case '#': case ';': /* allow comment if we already had a value */ /* WHY ONLY THEN ? 'xx=' can be seen as equivalent to 'xx=""' */ if (value_pos > 0) { state = ST_COMMENT; break; } /* fall through */ case '[': case ']': case '=': /* illegal characters WHY? */ report(RPT_WARNING, "Invalid character '%c' in value on line %d of %s, at key: %s", ch, line_nr, source_descr, keyname); error = 1; state = ST_INVALID_VALUE; break; case '\t': case ' ': /* ignore leading spaces */ if (value_pos == 0) break; /* fall through */ case '\0': case '\n': case '\r': /* value complete */ if (!*current_section) { report(RPT_WARNING, "Data outside sections on line %d of %s with key: %s", line_nr, source_descr, keyname); error = 1; } else { /* Store the value*/ (void) add_key(*current_section, keyname, value); } /* And be ready for next thing...*/ state = ((ch == ' ') || (ch == '\t')) ? ST_VALUE_DONE : ST_INITIAL; break; case '"': /* quoted string */ state = ST_QUOTEDVALUE; break; default: /* append char to value */ if (value_pos < MAXVALUELENGTH) { value[value_pos++] = ch; value[value_pos] = '\0'; break; } report(RPT_WARNING, "Value too long on line %d of %s, at key: %s", line_nr, source_descr, keyname); error = 1; state = ST_INVALID_VALUE; } break; case ST_QUOTEDVALUE: /* a quoted part of a string */ switch (ch) { case '\0': case '\n': report(RPT_WARNING, "Premature end of quoted string on line %d of %s: %s", line_nr, source_descr, keyname); error = 1; state = ST_INITIAL; break; case '\\': if (!escape) { escape = 1; break; } /* fall through */ case '"': if (!escape) { state = ST_VALUE; break; } /* fall through */ default: if (escape) { switch (ch) { case 'a': ch = '\a'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case 'v': ch = '\v'; break; /* default: literal char (i.e. ignore '\') */ } escape = 0; } value[value_pos++] = ch; value[value_pos] = '\0'; } break; case ST_SECTIONLABEL_DONE: case ST_VALUE_DONE: switch (ch) { case ';': case '#': state = ST_COMMENT; break; case '\0': case '\n': state = ST_INITIAL; break; case '\t': case ' ': break; default: /* illegal characters */ report(RPT_WARNING, "Invalid character '%c' on line %d of %s", ch, line_nr, source_descr); error = 1; state = ST_INVALID_VALUE; } case ST_INVALID_SECTIONLABEL: /* invalid section label: resync up to end of label/next line */ if (ch == ']') state = ST_INITIAL; /* fall through */ case ST_INVALID_ASSIGNMENT: case ST_INVALID_KEYNAME: case ST_INVALID_VALUE: case ST_COMMENT: /* comment or error: ignore anything up to the next line */ if (ch == '\n') state = ST_INITIAL; } if (ch == '\0') { if ((!error) && (state != ST_INITIAL) && (state != ST_COMMENT) && (state != ST_SECTIONLABEL_DONE) && (state != ST_VALUE_DONE)) { report(RPT_WARNING, "Premature end of configuration on line %d of %s: %d", line_nr, source_descr, state); error = 1; } state = ST_END; } } return (error) ? -1 : 0; } #if CONFIGFILE_DEBUGTEST void config_dump(void) { ConfigSection *s; for (s = first_section; s != NULL; s = s->next_section) { ConfigKey *k; fprintf(stderr, "[%s]\n", s->name); for (k = s->first_key; k != NULL; k = k->next_key) fprintf(stderr, "%s = \"%s\"\n", k->name, k->value); fprintf(stderr, "\n"); } } int main(int argc, char *argv[]) { if (argc > 0) config_read_file(argv[1]); config_dump(); } #endif lcdproc-0.5.9/server/0000755000175100017510000000000013121562645011471 500000000000000lcdproc-0.5.9/server/menuscreens.c0000644000175100017510000005572313076227531014121 00000000000000/** \file server/menuscreens.c * Creates the server menu screen(s) and creates the menus that should be * displayed on this screen. * It also handles its key presses and converts them to menu tokens for * easier processing. * * \note * menuscreens.c does not know whether a menuitem is displayed INSIDE * a menu or on a separate SCREEN, for flexibility. */ /*- * This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn * 2004, F5 Networks, Inc. - IP-address input * 2005, Peter Marschall - error checks, ... */ #include #include #include #include #include "screen.h" #include "screenlist.h" #include "menuscreens.h" #include "shared/configfile.h" #include "shared/report.h" #include "input.h" #include "driver.h" #include "drivers.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif /* Next include files are needed for settings that we can modify */ #include "render.h" char *menu_key; char *enter_key; char *up_key; char *down_key; char *left_key; char *right_key; static unsigned int keymask; /* mask of defined menu keys */ Screen *menuscreen = NULL; MenuItem *active_menuitem = NULL; /** the "real" main_menu */ Menu *main_menu = NULL; /** customizable entry point into the menu system (see menuscreen_set_main()). */ Menu *custom_main_menu = NULL; Menu *screens_menu = NULL; /* Local prototypes */ static void handle_quit(void); static void handle_close(void); static void handle_none(void); static void handle_enter(void); static void handle_successor(void); void menuscreen_switch_item(MenuItem *new_menuitem); void menuscreen_create_menu(void); #ifdef LCDPROC_TESTMENUS void menuscreen_create_testmenu(void); #endif Menu *menuscreen_get_main(void); MenuEventFunc(heartbeat_handler); MenuEventFunc(backlight_handler); MenuEventFunc(titlespeed_handler); MenuEventFunc(contrast_handler); MenuEventFunc(brightness_handler); int menuscreens_init(void) { const char *tmp; debug(RPT_DEBUG, "%s()", __FUNCTION__); menu_permissive_goto = config_get_bool("menu", "PermissiveGoto", 0, 0); /* * Get keys from config file: MenuKey, EnterKey, UpKey, DownKey, * LeftKey, RightKey. For a working menu at least 3 are necessary: * MenuKey, EnterKey, UpKey/DownKey. */ keymask = 0; menu_key = enter_key = NULL; tmp = config_get_string("menu", "MenuKey", 0, NULL); if (tmp != NULL) { menu_key = strdup(tmp); keymask |= MENUTOKEN_MENU; } tmp = config_get_string("menu", "EnterKey", 0, NULL); if (tmp != NULL) { enter_key = strdup(tmp); keymask |= MENUTOKEN_ENTER; } up_key = down_key = NULL; tmp = config_get_string("menu", "UpKey", 0, NULL); if (tmp != NULL) { up_key = strdup(tmp); keymask |= MENUTOKEN_UP; } tmp = config_get_string("menu", "DownKey", 0, NULL); if (tmp != NULL) { down_key = strdup(tmp); keymask |= MENUTOKEN_DOWN; } left_key = right_key = NULL; tmp = config_get_string("menu", "LeftKey", 0, NULL); if (tmp != NULL) { left_key = strdup(tmp); keymask |= MENUTOKEN_LEFT; } tmp = config_get_string("menu", "RightKey", 0, NULL); if (tmp != NULL) { right_key = strdup(tmp); keymask |= MENUTOKEN_RIGHT; } /* Now reserve the keys that were defined */ if (menu_key != NULL) input_reserve_key(menu_key, true, NULL); if (enter_key != NULL) input_reserve_key(enter_key, false, NULL); if (up_key != NULL) input_reserve_key(up_key, false, NULL); if (down_key != NULL) input_reserve_key(down_key, false, NULL); if (left_key != NULL) input_reserve_key(left_key, false, NULL); if (right_key != NULL) input_reserve_key(right_key, false, NULL); /* Create screen */ menuscreen = screen_create("_menu_screen", NULL); if (menuscreen != NULL) menuscreen->priority = PRI_HIDDEN; active_menuitem = NULL; screenlist_add(menuscreen); /* Build menu */ menuscreen_create_menu(); return 0; } int menuscreens_shutdown(void) { debug(RPT_DEBUG, "%s()", __FUNCTION__); /* Program shutdown before completed startup */ if (!menuscreen) return -1; /* Quit menu just to make sure */ menuscreen_switch_item(NULL); /* Destroy the menuscreen */ screenlist_remove(menuscreen); screen_destroy(menuscreen); menuscreen = NULL; /* Destroy all menus */ menuitem_destroy(main_menu); main_menu = NULL; custom_main_menu = NULL; screens_menu = NULL; /* Forget menu's key reservations */ input_release_client_keys(NULL); if (menu_key != NULL) free(menu_key); if (enter_key != NULL) free(enter_key); if (up_key != NULL) free(up_key); if (down_key != NULL) free(down_key); if (left_key != NULL) free(left_key); if (right_key != NULL) free(right_key); keymask = 0; return 0; } void menuscreen_inform_item_destruction(MenuItem * item) { MenuItem *i; debug(RPT_DEBUG, "%s(item=[%s])", __FUNCTION__, ((item != NULL) ? item->id : "(null)")); /* Are we currently in (a subitem of) the given item ? */ for (i = active_menuitem; i != NULL; i = i->parent) { if (i == item) { menuscreen_switch_item(item->parent); } } } void menuscreen_inform_item_modified(MenuItem * item) { debug(RPT_DEBUG, "%s(item=[%s])", __FUNCTION__, ((item != NULL) ? item->id : "(null)")); if ((active_menuitem == NULL) || (item == NULL)) return; /* Are we currently in the item or the parent of the item ? */ if (active_menuitem == item || active_menuitem == item->parent) { menuitem_rebuild_screen(active_menuitem, menuscreen); } } bool is_menu_key(const char *key) { if ((menu_key != NULL) && (key != NULL) && (strcmp(key, menu_key) == 0)) return true; else return false; } /** This function changes the menuitem to the given one, and does necessary * actions. * To leave the menu system, specify NULL for new_menuitem. * The item will not be reset when the new item is a child of the last one. */ void menuscreen_switch_item(MenuItem * new_menuitem) { MenuItem *old_menuitem = active_menuitem; debug(RPT_DEBUG, "%s(item=[%s]) from active_menuitem=[%s]", __FUNCTION__, ((new_menuitem != NULL) ? new_menuitem->id : "(null)"), ((old_menuitem != NULL) ? old_menuitem->id : "(null)")); /* First we do the switch */ active_menuitem = new_menuitem; /* What was the state change ? */ if (!old_menuitem && !new_menuitem) { /* Nothing to be done */ } else if (old_menuitem && !new_menuitem) { /* leave menu system */ menuscreen->priority = PRI_HIDDEN; } else if (!old_menuitem && new_menuitem) { /* Menu is becoming active */ menuitem_reset(active_menuitem); menuitem_rebuild_screen(active_menuitem, menuscreen); menuscreen->priority = PRI_INPUT; } else { /* We're left with the usual case: a menu level switch */ if (old_menuitem->parent != new_menuitem) { menuitem_reset(new_menuitem); } menuitem_rebuild_screen(active_menuitem, menuscreen); } if (old_menuitem && old_menuitem->event_func) old_menuitem->event_func(old_menuitem, MENUEVENT_LEAVE); if (new_menuitem && new_menuitem->event_func) new_menuitem->event_func(new_menuitem, MENUEVENT_ENTER); return; } static void handle_quit(void) { debug(RPT_DEBUG, "%s: Closing menu screen", __FUNCTION__); menuscreen_switch_item(NULL); } static void handle_close(void) { debug(RPT_DEBUG, "%s: Closing item", __FUNCTION__); menuscreen_switch_item( (active_menuitem == menuscreen_get_main()) ? NULL : active_menuitem->parent); } static void handle_none(void) { debug(RPT_DEBUG, "%s: Staying in item", __FUNCTION__); if (active_menuitem) { menuitem_update_screen(active_menuitem, menuscreen); /* No rebuild needed, only value can be changed */ } /* Nothing extra to be done */ } /** Enter the selected menuitem * Note: this is not for checkboxes etc that don't have their * own screen. The menuitem_process_input function should do * things like toggling checkboxes ! */ static void handle_enter(void) { debug(RPT_DEBUG, "%s: Entering subitem", __FUNCTION__); menuscreen_switch_item(menu_get_current_item(active_menuitem)); } static void handle_predecessor(void) { MenuItem *predecessor; MenuItem *item = (active_menuitem->type == MENUITEM_MENU) ? menu_get_item_for_predecessor_check(active_menuitem) : active_menuitem; assert(item != NULL); debug(RPT_DEBUG, "%s: Switching to registered predecessor '%s' of '%s'.", __FUNCTION__, item->predecessor_id, item->id); predecessor = menuitem_search(item->predecessor_id, (Client *) active_menuitem->client); if (predecessor == NULL) { /* * note: if _quit_, _close_, _none_ get here this would be an * implementation error - they should have been handled via * different MENURESULT codes. */ report(RPT_ERR, "%s: cannot find predecessor '%s' of '%s'.", __FUNCTION__, item->predecessor_id, item->id); return; } switch (predecessor->type) { case MENUITEM_ACTION: case MENUITEM_CHECKBOX: case MENUITEM_RING: if (active_menuitem != predecessor->parent) menuscreen_switch_item(predecessor->parent); /* this won't work for hidden subitems */ menu_select_subitem(active_menuitem, item->predecessor_id); menuitem_update_screen(active_menuitem, menuscreen); break; default: if ((predecessor->parent != NULL) && (predecessor->parent->type == MENUITEM_MENU)) { /* update parent menu too */ menu_select_subitem(predecessor->parent, predecessor->id); } menuscreen_switch_item(predecessor); break; } } static void handle_successor(void) { MenuItem *successor; MenuItem *item = (active_menuitem->type == MENUITEM_MENU) ? menu_get_item_for_successor_check(active_menuitem) : active_menuitem; assert(item != NULL); debug(RPT_DEBUG, "%s: Switching to registered successor '%s' of '%s'.", __FUNCTION__, item->successor_id, item->id); successor = menuitem_search(item->successor_id, (Client *) active_menuitem->client); if (successor == NULL) { /* * note: if _quit_, _close_, _none_ get here this would be an * implementation error - they should have been handled via * different MENURESULT codes. */ report(RPT_ERR, "%s: cannot find successor '%s' of '%s'.", __FUNCTION__, item->successor_id, item->id); return; } switch (successor->type) { case MENUITEM_ACTION: case MENUITEM_CHECKBOX: case MENUITEM_RING: if (active_menuitem != successor->parent) menuscreen_switch_item(successor->parent); /* this won't work for hidden subitems */ menu_select_subitem(active_menuitem, item->successor_id); menuitem_update_screen(active_menuitem, menuscreen); break; default: if ((successor->parent != NULL) && (successor->parent->type == MENUITEM_MENU)) { /* update parent menu too */ menu_select_subitem(successor->parent, successor->id); } menuscreen_switch_item(successor); break; } } void menuscreen_key_handler(const char *key) { MenuToken token = MENUTOKEN_NONE; MenuResult res; debug(RPT_DEBUG, "%s(\"%s\")", __FUNCTION__, key); if ((menu_key != NULL) && (strcmp(key, menu_key) == 0)) { token = MENUTOKEN_MENU; } else if ((enter_key != NULL) && (strcmp(key, enter_key) == 0)) { token = MENUTOKEN_ENTER; } else if ((up_key != NULL) && (strcmp(key, up_key) == 0)) { token = MENUTOKEN_UP; } else if ((down_key != NULL) && (strcmp(key, down_key) == 0)) { token = MENUTOKEN_DOWN; } else if ((left_key != NULL) && (strcmp(key, left_key) == 0)) { token = MENUTOKEN_LEFT; } else if ((right_key != NULL) && (strcmp(key, right_key) == 0)) { token = MENUTOKEN_RIGHT; } else { token = MENUTOKEN_OTHER; } /* Is the menu already active ? */ if (!active_menuitem) { debug(RPT_DEBUG, "%s: Activating menu screen", __FUNCTION__); menuscreen_switch_item(menuscreen_get_main()); return; } res = menuitem_process_input(active_menuitem, token, key, keymask); switch (res) { case MENURESULT_ERROR: report(RPT_ERR, "%s: Error from menuitem_process_input", __FUNCTION__); break; case MENURESULT_NONE: handle_none(); break; case MENURESULT_ENTER: handle_enter(); break; case MENURESULT_CLOSE: handle_close(); break; case MENURESULT_QUIT: handle_quit(); break; case MENURESULT_PREDECESSOR: handle_predecessor(); break; case MENURESULT_SUCCESSOR: handle_successor(); break; default: assert(!"unexpected menuresult"); break; } } void menuscreen_create_menu(void) { Menu *options_menu; Menu *driver_menu; MenuItem *checkbox; MenuItem *slider; Driver *driver; debug(RPT_DEBUG, "%s()", __FUNCTION__); main_menu = menu_create("mainmenu", NULL, "LCDproc Menu", NULL); if (main_menu == NULL) { report(RPT_ERR, "%s: Cannot create main menu", __FUNCTION__); return; } options_menu = menu_create("options", NULL, "Options", NULL); if (options_menu == NULL) { report(RPT_ERR, "%s: Cannot create options menu", __FUNCTION__); return; } menu_add_item(main_menu, options_menu); #ifdef LCDPROC_TESTMENUS /* * TODO: Menu items in the screens menu currently have no functions * assigned. Therefore only enable the menu for testing. If functions * are available, this code should be outside the #ifdef. */ screens_menu = menu_create("screens", NULL, "Screens", NULL); if (screens_menu == NULL) { report(RPT_ERR, "%s: Cannot create screens menu", __FUNCTION__); return; } menu_add_item(main_menu, screens_menu); menuscreen_create_testmenu(); #endif /* * add option menu contents: menu's client is NULL since we're in the * server */ checkbox = menuitem_create_checkbox("heartbeat", heartbeat_handler, "Heartbeat", NULL, true, heartbeat); menu_add_item(options_menu, checkbox); checkbox = menuitem_create_checkbox("backlight", backlight_handler, "Backlight", NULL, true, backlight); menu_add_item(options_menu, checkbox); slider = menuitem_create_slider("titlespeed", titlespeed_handler, "TitleSpeed", NULL, "0", "10", TITLESPEED_NO, TITLESPEED_MAX, 1, titlespeed); menu_add_item(options_menu, slider); /* * add driver specific option menus for each driver: menu's client is * NULL since we're in the server */ for (driver = drivers_getfirst(); driver; driver = drivers_getnext()) { int contrast_avail = (driver->get_contrast && driver->set_contrast) ? 1 : 0; int brightness_avail = (driver->get_brightness && driver->set_brightness) ? 1 : 0; if (contrast_avail || brightness_avail) { /* menu's client is NULL since we're in the server */ driver_menu = menu_create(driver->name, NULL, driver->name, NULL); if (driver_menu == NULL) { report(RPT_ERR, "%s: Cannot create menu for driver %s", __FUNCTION__, driver->name); continue; } menu_set_association(driver_menu, driver); menu_add_item(options_menu, driver_menu); if (contrast_avail) { int contrast = driver->get_contrast(driver); /* menu's client is NULL since we're in the server */ slider = menuitem_create_slider("contrast", contrast_handler, "Contrast", NULL, "min", "max", 0, 1000, 25, contrast); menu_add_item(driver_menu, slider); } if (brightness_avail) { int onbrightness = driver->get_brightness(driver, BACKLIGHT_ON); int offbrightness = driver->get_brightness(driver, BACKLIGHT_OFF); slider = menuitem_create_slider("onbrightness", brightness_handler, "On Brightness", NULL, "min", "max", 0, 1000, 25, onbrightness); menu_add_item(driver_menu, slider); slider = menuitem_create_slider("offbrightness", brightness_handler, "Off Brightness", NULL, "min", "max", 0, 1000, 25, offbrightness); menu_add_item(driver_menu, slider); } } } } #ifdef LCDPROC_TESTMENUS void menuscreen_create_testmenu(void) { MenuItem *test_item; Menu *test_menu; char testiso[] = { 'D', 'e', 'm', 'o', '\t', /* #160 */ 160, 161, 162, 163, 164, 165, 166, 167, '\t', 168, 169, 170, 171, 172, 173, 174, 175, '\t', 176, 177, 178, 179, 180, 181, 182, 183, '\t', 184, 185, 186, 187, 188, 189, 190, 191, '\t', /* #192 */ 192, 193, 194, 195, 196, 197, 198, 199, '\t', 200, 201, 202, 203, 204, 205, 206, 207, '\t', 208, 209, 210, 211, 212, 213, 214, 215, '\t', 216, 217, 218, 219, 220, 221, 222, 223, '\t', /* #224 */ 224, 225, 226, 227, 228, 229, 230, 231, '\t', 232, 233, 234, 235, 236, 237, 238, 239, '\t', 240, 241, 242, 243, 244, 245, 246, 247, '\t', 248, 249, 250, 251, 252, 253, 254, 255, '\0' }; test_menu = menu_create("test", NULL, "Test menu", NULL); if (test_menu == NULL) { report(RPT_ERR, "%s: Cannot create test menu", __FUNCTION__); return; } menu_add_item(main_menu, test_menu); /* menu's client is NULL since we're in the server */ test_item = menuitem_create_action("", NULL, "Action", NULL, MENURESULT_NONE); menu_add_item(test_menu, test_item); test_item = menuitem_create_action("", NULL, "Action,closing", NULL, MENURESULT_CLOSE); menu_add_item(test_menu, test_item); test_item = menuitem_create_action("", NULL, "Action,quitting", NULL, MENURESULT_QUIT); menu_add_item(test_menu, test_item); test_item = menuitem_create_checkbox("", NULL, "Checkbox", NULL, false, false); menu_add_item(test_menu, test_item); test_item = menuitem_create_checkbox("", NULL, "Checkbox, gray", NULL, true, false); menu_add_item(test_menu, test_item); test_item = menuitem_create_ring("", NULL, "Ring", NULL, "ABC\tDEF\t01234567890\tOr a very long string that will not fit on any display", 1); menu_add_item(test_menu, test_item); test_item = menuitem_create_slider("", NULL, "Slider", NULL, "mintext", "maxtext", -20, 20, 1, 0); menu_add_item(test_menu, test_item); test_item = menuitem_create_slider("", NULL, "Slider,step=5", NULL, "mintext", "maxtext", -20, 20, 5, 0); menu_add_item(test_menu, test_item); test_item = menuitem_create_numeric("", NULL, "Numeric", NULL, 1, 365, 15); menu_add_item(test_menu, test_item); test_item = menuitem_create_numeric("", NULL, "Numeric,signed", NULL, -20, +20, 15); menu_add_item(test_menu, test_item); test_item = menuitem_create_alpha("", NULL, "Alpha", NULL, 0, 3, 12, true, true, true, ".-+@", "LCDproc-v0.5"); menu_add_item(test_menu, test_item); test_item = menuitem_create_alpha("", NULL, "Alpha, caps only", NULL, 0, 3, 12, true, false, false, "-", "LCDPROC"); menu_add_item(test_menu, test_item); test_item = menuitem_create_ip("", NULL, "IPv4", NULL, false, "192.168.1.245"); menu_add_item(test_menu, test_item); test_item = menuitem_create_ip("", NULL, "IPv6", NULL, true, "1080:0:0:0:8:800:200C:417A"); menu_add_item(test_menu, test_item); test_item = menuitem_create_ring("", NULL, "Charset", NULL, testiso, 0); menu_add_item(test_menu, test_item); } #endif /* LCDPROC_TESTMENUS */ MenuEventFunc(heartbeat_handler) { debug(RPT_DEBUG, "%s(item=[%s], event=%d)", __FUNCTION__, ((item != NULL) ? item->id : "(null)"), event); if ((item != NULL) && (event == MENUEVENT_UPDATE)) { /* Set heartbeat setting */ heartbeat = item->data.checkbox.value; report(RPT_INFO, "Menu: set heartbeat to %d", heartbeat); } return 0; } MenuEventFunc(backlight_handler) { debug(RPT_DEBUG, "%s(item=[%s], event=%d)", __FUNCTION__, ((item != NULL) ? item->id : "(null)"), event); if ((item != NULL) && (event == MENUEVENT_UPDATE)) { /* Set backlight setting */ backlight = item->data.checkbox.value; report(RPT_INFO, "Menu: set backlight to %d", backlight); } return 0; } MenuEventFunc(titlespeed_handler) { debug(RPT_DEBUG, "%s(item=[%s], event=%d)", __FUNCTION__, ((item != NULL) ? item->id : "(null)"), event); if ((item != NULL) && ((event == MENUEVENT_MINUS) || (event == MENUEVENT_PLUS))) { /* set titlespeed setting */ titlespeed = item->data.slider.value; report(RPT_INFO, "Menu: set titlespeed to %d", titlespeed); } return 0; } MenuEventFunc(contrast_handler) { debug(RPT_DEBUG, "%s(item=[%s], event=%d)", __FUNCTION__, ((item != NULL) ? item->id : "(null)"), event); /* * This function can be called by one of several drivers that support * contrast */ if ((item != NULL) && ((event == MENUEVENT_MINUS) || (event == MENUEVENT_PLUS))) { /* Determine the driver by following the menu's association */ Driver *driver = item->parent->data.menu.association; if (driver != NULL) { driver->set_contrast(driver, item->data.slider.value); report(RPT_INFO, "Menu: set contrast of [%.40s] to %d", driver->name, item->data.slider.value); } } return 0; } MenuEventFunc(brightness_handler) { debug(RPT_DEBUG, "%s(item=[%s], event=%d)", __FUNCTION__, ((item != NULL) ? item->id : "(null)"), event); /* * This function can be called by one of several drivers that support * brightness ! */ if ((item != NULL) && ((event == MENUEVENT_MINUS) || (event == MENUEVENT_PLUS))) { /* Determine the driver by following the menu's association */ Driver *driver = item->parent->data.menu.association; if (driver != NULL) { if (strcmp(item->id, "onbrightness") == 0) { driver->set_brightness(driver, BACKLIGHT_ON, item->data.slider.value); } else if (strcmp(item->id, "offbrightness") == 0) { driver->set_brightness(driver, BACKLIGHT_OFF, item->data.slider.value); } } } return 0; } void menuscreen_add_screen(Screen *s) { Menu *m; MenuItem *mi; debug(RPT_DEBUG, "%s(s=[%s])", __FUNCTION__, ((s != NULL) ? s->id : "(null)")); /* screens have not been created or no screen given ... */ if ((screens_menu == NULL) || (s == NULL)) return; /* Create a menu entry for the screen */ m = menu_create(s->id, NULL, ((s->name != NULL) ? s->name : s->id), s->client); if (m == NULL) { report(RPT_ERR, "%s: Cannot create menu", __FUNCTION__); return; } menu_set_association(m, s); menu_add_item(screens_menu, m); /* And add some items for it... */ mi = menuitem_create_action("", NULL, "(don't work yet)", s->client, MENURESULT_NONE); menu_add_item(m, mi); mi = menuitem_create_action("", NULL, "To Front", s->client, MENURESULT_QUIT); menu_add_item(m, mi); mi = menuitem_create_checkbox("", NULL, "Visible", s->client, false, true); menu_add_item(m, mi); mi = menuitem_create_numeric("", NULL, "Duration", s->client, 2, 3600, s->duration); menu_add_item(m, mi); mi = menuitem_create_ring("", NULL, "Priority", s->client, "Hidden\tBackground\tForeground\tAlert\tInput", s->priority); menu_add_item(m, mi); } void menuscreen_remove_screen(Screen *s) { debug(RPT_DEBUG, "%s(s=[%s])", __FUNCTION__, (s != NULL) ? s->id : "(NULL)"); /* allow to remove the menuscreen itself */ if ((s == NULL) || (s == menuscreen)) return; if (screens_menu) { Menu *m = menu_find_item(screens_menu, s->id, false); menu_remove_item(screens_menu, m); menuitem_destroy(m); } } int menuscreen_goto(Menu * menu) { debug(RPT_DEBUG, "%s(m=[%s]): active_menuitem=[%s]", __FUNCTION__, (menu != NULL) ? menu->id : "(NULL)", (active_menuitem != NULL) ? active_menuitem->id : "(NULL)"); menuscreen_switch_item(menu); return 0; } /** sets custom main menu. Use NULL pointer to reset it to the "real" main * menu. */ int menuscreen_set_main(Menu * menu) { debug(RPT_DEBUG, "%s(m=[%s])", __FUNCTION__, (menu != NULL) ? menu->id : "(NULL)"); custom_main_menu = menu; return 0; } Menu * menuscreen_get_main(void) { return custom_main_menu ? custom_main_menu : main_menu; } lcdproc-0.5.9/server/main.h0000644000175100017510000000331413075070515012505 00000000000000/** \file server/main.h */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2001, Joris Robijn */ #ifndef MAIN_H #define MAIN_H #ifdef HAVE_CONFIG_H # include "config.h" #endif /* contains a few things that other parts of the program might want to know about... */ extern char *version; extern char *protocol_version; extern char *build_date; /* You should be able to modify the following freqencies... */ #define PROCESS_FREQ 32 /* And 32 times per second processing of messages and keypresses. */ #define MAX_RENDER_LAG_FRAMES 16 /* Allow the rendering strokes to lag behind this many frames. * More lag will not be corrected, but will cause slow-down. */ extern long timer; /* 32 bits at 8Hz will overflow in 2 ^ 29 = 5e8 seconds = 17 years. * If you get an overflow, please mail us and we will fix this personally * for you ! */ /**** Configuration variables ****/ /* Only configuration items that are settable from the command line should * be mentioned here. See main.c. */ extern unsigned int bind_port; extern char bind_addr[]; /* Do not preinit these strings as they will occupy */ extern char configfile[]; /* a lot of space in the executable. */ extern char user[]; /* The values will be overwritten anyway... */ extern int frame_interval; /* Not a command line option, but could be */ /* The drivers and their driver parameters */ extern char *drivernames[]; extern int num_drivers; /* End of configuration variables */ /* Defines for having 'unset' values*/ #define UNSET_INT -1 #define UNSET_STR "\01" #endif lcdproc-0.5.9/server/widget.h0000644000175100017510000000346412505300405013041 00000000000000/** \file server/widget.h * Public interface to the widget methods. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven */ #ifndef WIDGET_H #define WIDGET_H #define INC_TYPES_ONLY 1 #include "screen.h" #undef INC_TYPES_ONLY /* These correspond to the index into the "types" array...*/ typedef enum WidgetType { WID_NONE = 0, WID_STRING, WID_HBAR, WID_VBAR, WID_ICON, WID_TITLE, WID_SCROLLER, WID_FRAME, WID_NUM } WidgetType; /** Widget structure */ typedef struct Widget { char *id; /**< the widget's name */ WidgetType type; /**< the widget's type */ Screen *screen; /**< What screen is this widget in ? */ int x, y; /**< Position */ int width, height; /**< Visible size */ int left, top, right, bottom; /**< bounding rectangle */ int length; /**< size or direction */ int speed; /**< For scroller... */ char *text; /**< text or binary data */ struct Screen *frame_screen; /**< frame widget get an associated screen */ //LinkedList *kids; /* Frames can contain more widgets...*/ } Widget; #define WID_MAX_DIR 4 /* Create new widget */ Widget *widget_create(char *id, WidgetType type, Screen *screen); /* Destroy a widget */ int widget_destroy(Widget *w); /* Convert a widget typename to a widget type */ WidgetType widget_typename_to_type(char *typename); /* Convert a widget typename to a widget type */ char *widget_type_to_typename(WidgetType t); /* Search subwidgets of a widget */ Widget *widget_search_subs(Widget *w, char *id); /* Convert icon number to icon name */ char *widget_icon_to_iconname(int icon); /* Convert iconname to icon number */ int widget_iconname_to_icon(char *iconname); #endif lcdproc-0.5.9/server/screenlist.h0000644000175100017510000000246413046702113013733 00000000000000/** \file server/screenlist.h */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2003, Joris Robijn */ #ifndef SCREENLIST_H #define SCREENLIST_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "shared/defines.h" #define AUTOROTATE_OFF 0 #define AUTOROTATE_ON 1 extern int autorotate; /**< If enabled, screens will rotate */ int screenlist_init(void); /* Initializes the screenlist. */ int screenlist_shutdown(void); /* Shuts down the screenlist. */ int screenlist_add(Screen *s); /* Adds a screen to the screenlist. */ int screenlist_remove(Screen *s); /* Removes a screen from the screenlist. */ void screenlist_process(void); /* Processes the screenlist. Decides if we need to switch to an other * screen. */ void screenlist_switch(Screen *s); /* Switches to an other screen in the proper way. Informs clients of * the switch. ALWAYS USE THIS FUNCTION TO SWITCH SCREENS. */ Screen *screenlist_current(void); /* Returns the currently active screen. */ int screenlist_goto_next(void); /* Moves on to the next screen. */ int screenlist_goto_prev(void); /* Moves on to the previous screen. */ #endif lcdproc-0.5.9/server/menuscreens.h0000644000175100017510000000267712505300405014112 00000000000000/** \file server/menuscreens.h * Creates all menuscreens, menus and handles the keypresses for the * menuscreens. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2003, Joris Robijn */ #ifndef MENUSCREENS_H #define MENUSCREENS_H #include "menu.h" #include "screen.h" extern Screen *menuscreen; extern Menu *main_menu; int menuscreens_init(void); int menuscreens_shutdown(void); /** This function indicates to the input part whether this key was the * reserved menu key. */ bool is_menu_key(const char *key); /** Meant for other parts of the program to inform the menuscreen that the * item is about to be removed. */ void menuscreen_inform_item_destruction(MenuItem *item); /** Meant for other parts of the program to inform the menuscreen that some * properties of the item have been modified. */ void menuscreen_inform_item_modified(MenuItem *item); /** This handler handles the keypresses for the menu. */ void menuscreen_key_handler(const char *key); /** Adds a menu for the given screen */ void menuscreen_add_screen(Screen *s); /** Removes the menu of the given screen */ void menuscreen_remove_screen(Screen *s); /** switches to menu. */ int menuscreen_goto(Menu *menu); /** sets custom_main_menu. */ int menuscreen_set_main(Menu *menu); #endif lcdproc-0.5.9/server/screenlist.c0000644000175100017510000001365513046702302013732 00000000000000/** \file server/screenlist.c * All actions that can be performed on the list of screens. * This file also manages the rotation of screens. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2003, Joris Robijn */ #include #include #include "shared/LL.h" #include "shared/sockets.h" #include "shared/report.h" #include "client.h" #include "screen.h" #include "screenlist.h" #include "main.h" /* for timer */ /* Local functions */ int compare_priority(void *one, void *two); int autorotate = UNSET_INT; /* If on, INFO and FOREGROUND screens will rotate */ LinkedList *screenlist = NULL; Screen *current_screen = NULL; long int current_screen_start_time = 0; int screenlist_init(void) { report(RPT_DEBUG, "%s()", __FUNCTION__); screenlist = LL_new(); if (!screenlist) { report(RPT_ERR, "%s: Error allocating", __FUNCTION__); return -1; } return 0; } int screenlist_shutdown(void) { report(RPT_DEBUG, "%s()", __FUNCTION__); if (!screenlist) { /* Program shutdown before completed startup */ return -1; } LL_Destroy(screenlist); return 0; } int screenlist_add(Screen *s) { if (!screenlist) return -1; return LL_Push(screenlist, s); } int screenlist_remove(Screen *s) { debug(RPT_DEBUG, "%s(s=[%.40s])", __FUNCTION__, s->id); if (!screenlist) return -1; /* Are we trying to remove the current screen ? */ if (s == current_screen) { screenlist_goto_next(); if (s == current_screen) { /* Hmm, no other screen had same priority */ void *res = LL_Remove(screenlist, s, NEXT); /* And now once more */ screenlist_goto_next(); return (res == NULL) ? -1 : 0; } } return (LL_Remove(screenlist, s, NEXT) == NULL) ? -1 : 0; } void screenlist_process(void) { Screen *s; Screen *f; report(RPT_DEBUG, "%s()", __FUNCTION__); if (!screenlist) return; /* Sort the list according to priority class */ LL_Sort(screenlist, compare_priority); f = LL_GetFirst(screenlist); /**** First we need to check out the current situation. ****/ /* Check whether there is an active screen */ s = screenlist_current(); if (!s) { /* We have no active screen yet. * Try to switch to the first screen in the list... */ s = f; if (!s) { /* There was no screen in the list */ return; } screenlist_switch(s); return; } else { /* There already was an active screen. * Check to see if it has an expiry time. If so, decrease it * and then check to see if it has expired. Remove the screen * if expired. */ if (s->timeout != -1) { --(s->timeout); report(RPT_DEBUG, "Active screen [%.40s] has timeout->%d", s->id, s->timeout); if (s->timeout <= 0) { /* Expired, we can destroy it */ report(RPT_DEBUG, "Removing expired screen [%.40s]", s->id); client_remove_screen(s->client, s); screen_destroy(s); } } } /**** OK, current situation examined. We can now see if we need to switch. */ /* Is there a screen of a higher priority class than the * current one ? */ if (f->priority > s->priority) { /* Yes, switch to that screen, job done */ report(RPT_DEBUG, "%s: High priority screen [%.40s] selected", __FUNCTION__, f->id); screenlist_switch(f); return; } /* Current screen has been visible long enough and is it of 'normal' * priority ? */ if (autorotate && (timer - current_screen_start_time >= s->duration) && s->priority > PRI_BACKGROUND && s->priority <= PRI_FOREGROUND) { /* Ah, rotate! */ screenlist_goto_next(); } } void screenlist_switch(Screen *s) { Client *c; char str[256]; if (!s) return; report(RPT_DEBUG, "%s(s=[%.40s])", __FUNCTION__, s->id); if (s == current_screen) { /* Nothing to be done */ return; } if (current_screen) { c = current_screen->client; if (c) { /* Tell the client we're not listening any more...*/ snprintf(str, sizeof(str), "ignore %s\n", current_screen->id); sock_send_string(c->sock, str); } else { /* It's a server screen, no need to inform it. */ } } c = s->client; if (c) { /* Tell the client we're paying attention...*/ snprintf(str, sizeof(str), "listen %s\n", s->id); sock_send_string(c->sock, str); } else { /* It's a server screen, no need to inform it. */ } report(RPT_INFO, "%s: switched to screen [%.40s]", __FUNCTION__, s->id); current_screen = s; current_screen_start_time = timer; } Screen * screenlist_current(void) { return current_screen; } int screenlist_goto_next(void) { Screen *s; debug(RPT_DEBUG, "%s()", __FUNCTION__); if (!current_screen) return -1; /* Find current screen in screenlist */ for (s = LL_GetFirst(screenlist); s && s != current_screen; s = LL_GetNext(screenlist)) ; /* One step forward */ s = LL_GetNext(screenlist); if (!s || s->priority < current_screen->priority) { /* To far, go back to start of screenlist */ s = LL_GetFirst(screenlist); } screenlist_switch(s); return 0; } int screenlist_goto_prev(void) { Screen *s; debug(RPT_DEBUG, "%s()", __FUNCTION__); if (!current_screen) return -1; /* Find current screen in screenlist */ for (s = LL_GetFirst(screenlist); s && s != current_screen; s = LL_GetNext(screenlist)); /* One step back */ s = LL_GetPrev(screenlist); if (!s) { /* We're at the start of the screenlist. We should find the * last screen with the same priority as the first screen. */ Screen *f = LL_GetFirst(screenlist); Screen *n; s = f; while ((n = LL_GetNext(screenlist)) && n->priority == f->priority) { s = n; } } screenlist_switch(s); return 0; } /* Internal function for sorting. */ int compare_priority(void *one, void *two) { Screen *a, *b; /*debug(RPT_DEBUG, "compare_priority: %8x %8x", one, two);*/ if (!one) return 0; if (!two) return 0; a = (Screen *) one; b = (Screen *) two; /*debug(RPT_DEBUG, "compare_priority: done?");*/ return (b->priority - a->priority); } lcdproc-0.5.9/server/main.c0000644000175100017510000006520113077456513012513 00000000000000/** \file server/main.c * Contains main(), plus signal callback functions and a help screen. * * Program init, command-line handling, and the main loop are * implemented here. Also, minimal data about the program such as * the revision number. * * Some of this stuff should probably be move elsewhere eventually, * such as command-line handling and the main loop. main() is supposed * to be "dumb". */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2001, Joris Robijn * 2001, Rene Wagner * 2002, Mike Patnode * 2002, Guillaume Filion * 2005-2006, Peter Marschall (cleanup) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "getopt.h" #ifdef HAVE_SYS_TIME_H # include #endif /* TODO: fill in what to include otherwise */ #include "shared/report.h" #include "shared/defines.h" #include "drivers.h" #include "sock.h" #include "clients.h" #include "screen.h" #include "screenlist.h" #include "parse.h" #include "render.h" #include "serverscreens.h" #include "menuscreens.h" #include "input.h" #include "shared/configfile.h" #include "drivers.h" #include "main.h" #if !defined(SYSCONFDIR) # define SYSCONFDIR "/etc" #endif #define DEFAULT_BIND_ADDR "127.0.0.1" #define DEFAULT_BIND_PORT LCDPORT #define DEFAULT_CONFIGFILE SYSCONFDIR "/LCDd.conf" #define DEFAULT_USER "nobody" #define DEFAULT_DRIVER "curses" #define DEFAULT_DRIVER_PATH "" /* not needed */ #define MAX_DRIVERS 8 #define DEFAULT_FOREGROUND_MODE 0 #define DEFAULT_ROTATE_SERVER_SCREEN SERVERSCREEN_ON #define DEFAULT_REPORTDEST RPT_DEST_STDERR #define DEFAULT_REPORTLEVEL RPT_WARNING #define DEFAULT_FRAME_INTERVAL 125000 #define DEFAULT_SCREEN_DURATION 32 #define DEFAULT_BACKLIGHT BACKLIGHT_OPEN #define DEFAULT_HEARTBEAT HEARTBEAT_OPEN #define DEFAULT_TITLESPEED TITLESPEED_MAX #define DEFAULT_AUTOROTATE AUTOROTATE_ON /* Socket to bind to... Using loopback is much more secure; it means that this port is accessible only to programs running locally on the same host as LCDd. Using variables for these means that (later) we can select which port and which address to bind to at run time. */ /* Store some standard defines into vars... */ char *version = VERSION; char *protocol_version = PROTOCOL_VERSION; char *api_version = API_VERSION; char *build_date = __DATE__; /**** Configuration variables ****/ /* Some variables are settable on the command line. This are variables that * change the mode of operation. This includes settings that you can use to * enable debugging: driver selection, report settings, bind address etc. * These variables should be in main.h and main.c (below). * * All other settings do not need to be settable from the command line. They * also do not necesarily need to be read in main.c but can better be read in * in the file concerned. */ unsigned int bind_port = UNSET_INT; char bind_addr[64]; /* Do not preinit these strings as they will occupy */ char configfile[256]; /* a lot of space in the executable. */ char user[64]; /* The values will be overwritten anyway... */ int frame_interval = DEFAULT_FRAME_INTERVAL; /* The drivers and their driver parameters */ char *drivernames[MAX_DRIVERS]; int num_drivers = 0; /* End of configuration variables */ /* Local variables */ static int foreground_mode = UNSET_INT; static int report_dest = UNSET_INT; static int report_level = UNSET_INT; static int stored_argc; static char **stored_argv; static volatile short got_reload_signal = 0; /* Local exported variables */ long timer = 0; /**** Local functions ****/ static void clear_settings(void); static int process_command_line(int argc, char **argv); static int process_configfile(char *cfgfile); static void set_default_settings(void); static void install_signal_handlers(int allow_reload); static void child_ok_func(int signal); static pid_t daemonize(void); static int wave_to_parent(pid_t parent_pid); static int init_drivers(void); static int drop_privs(char *user); static void do_reload(void); static void do_mainloop(void); static void exit_program(int val); static void catch_reload_signal(int val); static int interpret_boolean_arg(char *s); static void output_help_screen(void); static void output_GPL_notice(void); #define CHAIN(e,f) { if (e>=0) { e=(f); }} #define CHAIN_END(e,msg) { if (e<0) { report(RPT_CRIT,(msg)); exit(EXIT_FAILURE); }} int main(int argc, char **argv) { int e = 0; pid_t parent_pid = 0; stored_argc = argc; stored_argv = argv; /* * Settings in order of preference: * * 1: Settings specified in command line options... * 2: Settings specified in configuration file... * 3: Default settings * * Because of this, and because one option (-c) specifies where * the configuration file is, things are done in this order: * * 1. Read and set options. * 2. Read configuration file; if option is read in configuration * file and not already set, then set it. * 3. Having read configuration file, if parameter is not set, * set it to the default value. * * It is for this reason that the default values are **NOT** set * in the variable declaration... */ /* Report that server is starting (report will be delayed) */ report(RPT_NOTICE, "LCDd version %s starting", version); report(RPT_INFO, "Built on %s, protocol version %s, API version %s", build_date, protocol_version, api_version); clear_settings(); /* Read command line*/ CHAIN(e, process_command_line(argc, argv)); /* Read config file * If config file was not given on command line use default */ if (strcmp(configfile, UNSET_STR) == 0) strncpy(configfile, DEFAULT_CONFIGFILE, sizeof(configfile)); CHAIN(e, process_configfile(configfile)); /* Set default values*/ set_default_settings(); /* Set reporting settings (will also flush delayed reports) */ set_reporting("LCDd", report_level, report_dest); report(RPT_INFO, "Set report level to %d, output to %s", report_level, ((report_dest == RPT_DEST_SYSLOG) ? "syslog" : "stderr")); CHAIN_END(e, "Critical error while processing settings, abort."); /* Now, go into daemon mode (if we should)... * We wait for the child to report it is running OK. This mechanism * is used because forking after starting the drivers causes the * child to loose the (LPT) port access. */ if (!foreground_mode) { report(RPT_INFO, "Server forking to background"); CHAIN(e, parent_pid = daemonize()); } else { output_GPL_notice(); report(RPT_INFO, "Server running in foreground"); } install_signal_handlers(!foreground_mode); /* Only catch SIGHUP if not in foreground mode */ /* Startup the subparts of the server */ CHAIN(e, sock_init(bind_addr, bind_port)); CHAIN(e, screenlist_init()); CHAIN(e, init_drivers()); CHAIN(e, clients_init()); CHAIN(e, input_init()); CHAIN(e, menuscreens_init()); CHAIN(e, server_screen_init()); CHAIN_END(e, "Critical error while initializing, abort."); if (!foreground_mode) { /* Tell to parent that startup went OK. */ wave_to_parent(parent_pid); } drop_privs(user); /* This can't be done before, because sending a signal to a process of a different user will fail */ do_mainloop(); /* This loop never stops; we'll get out only with a signal...*/ return 0; } static void clear_settings(void) { int i; debug(RPT_DEBUG, "%s()", __FUNCTION__); bind_port = UNSET_INT; strncpy(bind_addr, UNSET_STR, sizeof(bind_addr)); strncpy(configfile, UNSET_STR, sizeof(configfile)); strncpy(user, UNSET_STR, sizeof(user)); foreground_mode = UNSET_INT; rotate_server_screen = UNSET_INT; backlight = UNSET_INT; heartbeat = UNSET_INT; titlespeed = UNSET_INT; default_duration = UNSET_INT; report_dest = UNSET_INT; report_level = UNSET_INT; for (i = 0; i < num_drivers; i++) { free(drivernames[i]); drivernames[i] = NULL; } num_drivers = 0; } /* parses arguments given on command line */ static int process_command_line(int argc, char **argv) { int c, b; int e = 0, help = 0; debug(RPT_DEBUG, "%s(argc=%d, argv=...)", __FUNCTION__, argc); /* Reset getopt */ opterr = 0; /* Prevent some messages to stderr */ /* Analyze options here.. (please try to keep list of options the * same everywhere) */ while ((c = getopt(argc, argv, "hc:d:fa:p:u:w:s:r:i:")) > 0) { switch(c) { case 'h': help = 1; /* Continue to process the other * options */ break; case 'c': strncpy(configfile, optarg, sizeof(configfile)); configfile[sizeof(configfile)-1] = '\0'; /* Terminate string */ break; case 'd': /* Add to a list of drivers to be initialized later...*/ if (num_drivers < MAX_DRIVERS) { drivernames[num_drivers] = strdup(optarg); if (drivernames[num_drivers] != NULL) { num_drivers++; } else { report(RPT_ERR, "alloc error storing driver name: %s", optarg); e = -1; } } else { report(RPT_ERR, "Too many drivers!"); e = -1; } break; case 'f': foreground_mode = 1; break; case 'a': strncpy(bind_addr, optarg, sizeof(bind_addr)); bind_addr[sizeof(bind_addr)-1] = '\0'; /* Terminate string */ break; case 'p': bind_port = atoi(optarg); break; case 'u': strncpy(user, optarg, sizeof(user)); user[sizeof(user)-1] = '\0'; /* Terminate string */ break; case 'w': default_duration = (int) (atof(optarg) * 1e6 / frame_interval); if (default_duration * frame_interval < 2e6) { report(RPT_ERR, "Waittime should be at least 2 (seconds), not %.8s", optarg); e = -1; } break; case 's': b = interpret_boolean_arg(optarg); if (b == -1) { report(RPT_ERR, "Not a boolean value: '%s'", optarg); e = -1; } else { report_dest = (b) ? RPT_DEST_SYSLOG : RPT_DEST_STDERR; } break; case 'r': report_level = atoi(optarg); break; case 'i': b = interpret_boolean_arg(optarg); if (b == -1) { report(RPT_ERR, "Not a boolean value: '%s'", optarg); e = -1; } else { rotate_server_screen = b; } break; case '?': /* For some reason getopt also returns an '?' * when an option argument is mission... */ report(RPT_ERR, "Unknown option: '%c'", optopt); e = -1; break; case ':': report(RPT_ERR, "Missing option argument!"); e = -1; break; } } if (optind < argc) { report(RPT_ERR, "Non-option arguments on the command line !"); e = -1; } if (help) { output_help_screen(); e = -1; } return e; } /* reads and parses configuration file */ static int process_configfile(char *configfile) { debug(RPT_DEBUG, "%s()", __FUNCTION__); /* Read server settings*/ if (config_read_file(configfile) != 0) { report(RPT_CRIT, "Could not read config file: %s", configfile); return -1; } if (bind_port == UNSET_INT) bind_port = config_get_int("Server", "Port", 0, UNSET_INT); if (strcmp(bind_addr, UNSET_STR) == 0) strncpy(bind_addr, config_get_string("Server", "Bind", 0, UNSET_STR), sizeof(bind_addr)); if (strcmp(user, UNSET_STR) == 0) strncpy(user, config_get_string("Server", "User", 0, UNSET_STR), sizeof(user)); if (default_duration == UNSET_INT) { default_duration = (config_get_float("Server", "WaitTime", 0, 0) * 1e6 / frame_interval); if (default_duration == 0) default_duration = UNSET_INT; else if (default_duration * frame_interval < 2e6) { report(RPT_WARNING, "Waittime should be at least 2 (seconds). Set to 2 seconds."); default_duration = 2e6 / frame_interval; } } if (foreground_mode == UNSET_INT) { int fg = config_get_bool("Server", "Foreground", 0, UNSET_INT); if (fg != UNSET_INT) foreground_mode = fg; } if (rotate_server_screen == UNSET_INT) { rotate_server_screen = config_get_tristate("Server", "ServerScreen", 0, "blank", UNSET_INT); } if (backlight == UNSET_INT) { backlight = config_get_tristate("Server", "Backlight", 0, "open", UNSET_INT); } if (heartbeat == UNSET_INT) { heartbeat = config_get_tristate("Server", "Heartbeat", 0, "open", UNSET_INT); } if (autorotate == UNSET_INT) { autorotate = config_get_bool("Server", "AutoRotate", 0, DEFAULT_AUTOROTATE); } if (titlespeed == UNSET_INT) { int speed = config_get_int("Server", "TitleSpeed", 0, DEFAULT_TITLESPEED); /* set titlespeed */ titlespeed = (speed <= TITLESPEED_NO) ? TITLESPEED_NO : min(speed, TITLESPEED_MAX); } frame_interval = config_get_int("Server", "FrameInterval", 0, DEFAULT_FRAME_INTERVAL); if (report_dest == UNSET_INT) { int rs = config_get_bool("Server", "ReportToSyslog", 0, UNSET_INT); if (rs != UNSET_INT) report_dest = (rs) ? RPT_DEST_SYSLOG : RPT_DEST_STDERR; } if (report_level == UNSET_INT) { report_level = config_get_int("Server", "ReportLevel", 0, UNSET_INT); } /* Read drivers */ /* If drivers have been specified on the command line, then do not * use the driver list from the config file. */ if (num_drivers == 0) { /* loop over all the Driver= directives to read the driver names */ while (1) { const char *s = config_get_string("Server", "Driver", num_drivers, NULL); if (s == NULL) break; if (s[0] != '\0') { drivernames[num_drivers] = strdup(s); if (drivernames[num_drivers] == NULL) { report(RPT_ERR, "alloc error storing driver name: %s", s); exit(EXIT_FAILURE); } num_drivers++; } } } return 0; } static void set_default_settings(void) { debug(RPT_DEBUG, "%s()", __FUNCTION__); /* Set defaults into unfilled variables... */ if (bind_port == UNSET_INT) bind_port = DEFAULT_BIND_PORT; if (strcmp(bind_addr, UNSET_STR) == 0) strncpy(bind_addr, DEFAULT_BIND_ADDR, sizeof(bind_addr)); if (strcmp(user, UNSET_STR) == 0) strncpy(user, DEFAULT_USER, sizeof(user)); if (foreground_mode == UNSET_INT) foreground_mode = DEFAULT_FOREGROUND_MODE; if (rotate_server_screen == UNSET_INT) rotate_server_screen = DEFAULT_ROTATE_SERVER_SCREEN; if (default_duration == UNSET_INT) default_duration = DEFAULT_SCREEN_DURATION; if (backlight == UNSET_INT) backlight = DEFAULT_BACKLIGHT; if (heartbeat == UNSET_INT) heartbeat = DEFAULT_HEARTBEAT; if (titlespeed == UNSET_INT) titlespeed = DEFAULT_TITLESPEED; if (report_dest == UNSET_INT) report_dest = DEFAULT_REPORTDEST; if (report_level == UNSET_INT) report_level = DEFAULT_REPORTLEVEL; /* Use default driver */ if (num_drivers == 0) { drivernames[0] = strdup(DEFAULT_DRIVER); if (drivernames[0] == NULL) { report(RPT_ERR, "alloc error storing driver name: %s", DEFAULT_DRIVER); exit(EXIT_FAILURE); } num_drivers = 1; } } static void install_signal_handlers(int allow_reload) { /* Installs signal handlers so that the program does clean exit and * can also receive a reload signal. * sigaction() is favoured over signal() */ struct sigaction sa; debug(RPT_DEBUG, "%s(allow_reload=%d)", __FUNCTION__, allow_reload); sigemptyset(&(sa.sa_mask)); /* Clients can cause SIGPIPE if they quit unexpectedly, and the * default action is to kill the server. Just ignore it. */ sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = exit_program; #ifdef HAVE_SA_RESTART sa.sa_flags = SA_RESTART; #endif sigaction(SIGINT, &sa, NULL); /* Ctrl-C will cause a clean exit...*/ sigaction(SIGTERM, &sa, NULL); /* and "kill"...*/ if (allow_reload) { sa.sa_handler = catch_reload_signal; /* On SIGHUP reread config and restart the drivers ! */ } else { /* Treat this signal just like INT and TERM */ } sigaction(SIGHUP, &sa, NULL); } static void child_ok_func(int signal) { /* We only catch this signal to be sure the child runs OK. */ debug(RPT_INFO, "%s(signal=%d)", __FUNCTION__, signal); /* Exit now ! because of bug? in wait() */ _exit(EXIT_SUCCESS); /* Parent exits normally. */ } static pid_t daemonize(void) { pid_t child; pid_t parent; int child_status; struct sigaction sa; debug(RPT_DEBUG, "%s()", __FUNCTION__); parent = getpid(); debug(RPT_INFO, "parent = %d", parent); /* Install handler at parent for child's signal */ /* sigaction should be more portable than signal, but it does not * work for some reason. */ sa.sa_handler = child_ok_func; sigemptyset(&(sa.sa_mask)); sa.sa_flags = SA_RESTART; sigaction(SIGUSR1, &sa, NULL); /* Do the fork */ switch ((child = fork())) { case -1: report(RPT_ERR, "Could not fork"); return -1; case 0: /* We are the child */ break; default: /* We are the parent */ debug(RPT_INFO, "child = %d", child); wait(&child_status); /* BUG? According to the man page wait() should also return * when a signal comes in that is caught. Instead it * continues to wait. */ if (WIFEXITED(child_status)) { /* Child exited normally, probably because of some * error. */ debug(RPT_INFO, "Child has terminated!"); exit(WEXITSTATUS(child_status)); /* Parent exits with same status as child did... */ } /* Child is still running and has signalled it's OK. * This means the parent can now rest in peace. */ debug(RPT_INFO, "Got OK signal from child."); exit(EXIT_SUCCESS); /* Parent exits normally. */ } /* At this point we are always the child. */ /* Reset signal handler */ sa.sa_handler = SIG_DFL; sigaction(SIGUSR1, &sa, NULL); setsid(); /* Create a new session because otherwise we'll * catch a SIGHUP when the shell is closed. */ return parent; } static int wave_to_parent(pid_t parent_pid) { debug(RPT_DEBUG, "%s(parent_pid=%d)", __FUNCTION__, parent_pid); kill(parent_pid, SIGUSR1); return 0; } static int init_drivers(void) { int i, res; int output_loaded = 0; debug(RPT_DEBUG, "%s()", __FUNCTION__); for (i = 0; i < num_drivers; i++) { res = drivers_load_driver(drivernames[i]); if (res >= 0) { /* Load went OK */ switch(res) { case 0: /* Driver does input only */ break; case 1: /* Driver does output */ output_loaded = 1; break; case 2: /* Driver does output in foreground (don't daemonize) */ foreground_mode = 1; output_loaded = 1; break; } } else { report(RPT_ERR, "Could not load driver %.40s", drivernames[i]); } } /* Do we have a running output driver ?*/ if (output_loaded) { return 0; } else { report(RPT_ERR, "There is no output driver"); return -1; } } static int drop_privs(char *user) { struct passwd *pwent; debug(RPT_DEBUG, "%s(user=\"%.40s\")", __FUNCTION__, user); if (getuid() == 0 || geteuid() == 0) { if ((pwent = getpwnam(user)) == NULL) { report(RPT_ERR, "User %.40s not a valid user!", user); return -1; } else { if (setuid(pwent->pw_uid) < 0) { report(RPT_ERR, "Unable to switch to user %.40s", user); return -1; } } } return 0; } static void do_reload(void) { int e = 0; drivers_unload_all(); /* Close all drivers */ config_clear(); clear_settings(); /* Reread command line*/ CHAIN(e, process_command_line(stored_argc, stored_argv)); /* Reread config file */ if (strcmp(configfile, UNSET_STR)==0) strncpy(configfile, DEFAULT_CONFIGFILE, sizeof(configfile)); CHAIN(e, process_configfile(configfile)); /* Set default values */ CHAIN(e, (set_default_settings(), 0)); /* Set reporting values */ CHAIN(e, set_reporting("LCDd", report_level, report_dest)); CHAIN(e, (report(RPT_INFO, "Set report level to %d, output to %s", report_level, ((report_dest == RPT_DEST_SYSLOG) ? "syslog" : "stderr")), 0)); /* And restart the drivers */ CHAIN(e, init_drivers()); CHAIN_END(e, "Critical error while reloading, abort."); } static void do_mainloop(void) { Screen *s; struct timeval t; struct timeval last_t; int sleeptime; long int process_lag = 0; long int render_lag = 0; long int t_diff; debug(RPT_DEBUG, "%s()", __FUNCTION__); gettimeofday(&t, NULL); /* Get initial time */ while (1) { /* Get current time */ last_t = t; gettimeofday(&t, NULL); t_diff = t.tv_sec - last_t.tv_sec; if ( ((t_diff + 1) > (LONG_MAX / 1e6)) || (t_diff < 0) ) { /* We're going to overflow the calculation - probably been to sleep, fudge the values */ t_diff = 0; process_lag = 1; render_lag = frame_interval; } else { t_diff *= 1e6; t_diff += t.tv_usec - last_t.tv_usec; } process_lag += t_diff; if (process_lag > 0) { /* Time for a processing stroke */ sock_poll_clients(); /* poll clients for input*/ parse_all_client_messages(); /* analyze input from network clients*/ handle_input(); /* handle key input from devices*/ /* We've done the job... */ process_lag = 0 - (1e6/PROCESS_FREQ); /* Note : this does not make a fixed frequency */ } render_lag += t_diff; if (render_lag > 0) { /* Time for a rendering stroke */ timer ++; screenlist_process(); s = screenlist_current(); /* TODO: Move this call to every client connection * and every screen add... */ if (s == server_screen) { update_server_screen(); } render_screen(s, timer); /* We've done the job... */ if (render_lag > frame_interval * MAX_RENDER_LAG_FRAMES) { /* Cause rendering slowdown because too much lag */ render_lag = frame_interval * MAX_RENDER_LAG_FRAMES; } render_lag -= frame_interval; /* Note: this DOES make a fixed frequency (except with slowdown) */ } /* Sleep just as long as needed */ sleeptime = min(0-process_lag, 0-render_lag); if (sleeptime > 0) { usleep(sleeptime); } /* Check if a SIGHUP has been caught */ if (got_reload_signal) { got_reload_signal = 0; do_reload(); } } /* Quit! */ exit_program(0); } static void exit_program(int val) { char buf[64]; debug(RPT_DEBUG, "%s(val=%d)", __FUNCTION__, val); /* TODO: These things shouldn't be so interdependent. The order * things are shut down in shouldn't matter... */ if (val > 0) { strncpy(buf, "Server shutting down on ", sizeof(buf)); switch(val) { case 1: strcat(buf, "SIGHUP"); break; case 2: strcat(buf, "SIGINT"); break; case 15: strcat(buf, "SIGTERM"); break; default: snprintf(buf, sizeof(buf), "Server shutting down on signal %d", val); break; /* Other values should not be seen, but just in case.. */ } report(RPT_NOTICE, buf); /* report it */ } /* Set emergency reporting and flush all messages if not done already. */ if (report_level == UNSET_INT) report_level = DEFAULT_REPORTLEVEL; if (report_dest == UNSET_INT) report_dest = DEFAULT_REPORTDEST; set_reporting("LCDd", report_level, report_dest); goodbye_screen(); /* display goodbye screen on LCD display */ drivers_unload_all(); /* release driver memory and file descriptors */ /* Shutdown things if server start was complete */ clients_shutdown(); /* shutdown clients (must come first) */ menuscreens_shutdown(); screenlist_shutdown(); /* shutdown screens (must come after client_shutdown) */ input_shutdown(); /* shutdown key input part */ sock_shutdown(); /* shutdown the sockets server */ report(RPT_INFO, "Exiting."); _exit(EXIT_SUCCESS); } static void catch_reload_signal(int val) { debug(RPT_DEBUG, "%s(val=%d)", __FUNCTION__, val); got_reload_signal = 1; } static int interpret_boolean_arg(char *s) { /* keep these checks consistent with config_get_boolean() */ if (strcasecmp(s, "0") == 0 || strcasecmp(s, "false") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "off") == 0) { return 0; } if (strcasecmp(s, "1") == 0 || strcasecmp(s, "true") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "on") == 0) { return 1; } /* no legal boolean string given */ return -1; } static void output_GPL_notice(void) { /* This will only be invoked when running in foreground * So, directly output to stderr */ fprintf(stderr, "LCDd %s, LCDproc Protocol %s\n", VERSION, PROTOCOL_VERSION); fprintf(stderr, "Part of the LCDproc suite\n"); fprintf(stderr, "Copyright (C) 1998-2017 William Ferrell, Selene Scriven\n" " and many other contributors\n\n"); fprintf(stderr, "This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU General Public License\n" "as published by the Free Software Foundation; either version 2\n" "of the License, or (at your option) any later version.\n\n"); fprintf(stderr, "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n\n"); fprintf(stderr, "You should have received a copy of the GNU General Public License\n" "along with this program; if not, write to the Free Software Foundation,\n" "Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n"); } static void output_help_screen(void) { /* Help screen is printed to stdout on purpose. No reason to have * this in syslog... */ debug(RPT_DEBUG, "%s()", __FUNCTION__); fprintf(stdout, "LCDd - LCDproc Server Daemon, %s\n\n", version); fprintf(stdout, "Copyright (c) 1998-2017 Selene Scriven, William Ferrell, and misc. contributors.\n"); fprintf(stdout, "This program is released under the terms of the GNU General Public License.\n\n"); fprintf(stdout, "Usage: LCDd []\n"); fprintf(stdout, " where are:\n"); fprintf(stdout, " -h Display this help screen\n"); fprintf(stdout, " -c Use a configuration file other than %s\n", DEFAULT_CONFIGFILE); fprintf(stdout, " -d Add a driver to use (overrides drivers in config file) [%s]\n", DEFAULT_DRIVER); fprintf(stdout, " -f Run in the foreground\n"); fprintf(stdout, " -a Network (IP) address to bind to [%s]\n", DEFAULT_BIND_ADDR); fprintf(stdout, " -p Network port to listen for connections on [%i]\n", DEFAULT_BIND_PORT); fprintf(stdout, " -u User to run as [%s]\n", DEFAULT_USER); fprintf(stdout, " -w Time to pause at each screen (in seconds) [%d]\n", (int) ((DEFAULT_SCREEN_DURATION * frame_interval) / 1e6)); fprintf(stdout, " -s If set, reporting will be done using syslog\n"); fprintf(stdout, " -r Report level [%d]\n", DEFAULT_REPORTLEVEL); fprintf(stdout, " -i Whether to rotate the server info screen\n"); /* Error messages will be flushed to the configured output after this * help message. */ } lcdproc-0.5.9/server/driver.c0000644000175100017510000004331713030601225013043 00000000000000/** \file server/driver.c * This code does all actions on the driver object. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 2001, Joris Robijn */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "main.h" /* for timer */ #include "shared/report.h" #include "shared/configfile.h" #include "widget.h" #include "driver.h" #include "drivers.h" #include "drivers/lcd.h" /* lcd.h is used for the driver API definition */ /** property / method symbols in a Driver structure */ typedef struct driver_symbols { const char *name; /**< symbol name */ short offset; /**< offset in Driver structure */ short required; /**< is the symbol mandatory */ } DriverSymbols; DriverSymbols driver_symbols[] = { { "api_version", offsetof(Driver, api_version), 1 }, { "stay_in_foreground", offsetof(Driver, stay_in_foreground), 1 }, { "supports_multiple", offsetof(Driver, supports_multiple), 1 }, { "symbol_prefix", offsetof(Driver, symbol_prefix), 1 }, { "init", offsetof(Driver, init), 1 }, { "close", offsetof(Driver, close), 1 }, { "width", offsetof(Driver, width), 0 }, { "height", offsetof(Driver, height), 0 }, { "clear", offsetof(Driver, clear), 0 }, { "flush", offsetof(Driver, flush), 0 }, { "string", offsetof(Driver, string), 0 }, { "chr", offsetof(Driver, chr), 0 }, { "vbar", offsetof(Driver, vbar), 0 }, { "hbar", offsetof(Driver, hbar), 0 }, { "num", offsetof(Driver, num), 0 }, { "heartbeat", offsetof(Driver, heartbeat), 0 }, { "icon", offsetof(Driver, icon), 0 }, { "cursor", offsetof(Driver, cursor), 0 }, { "set_char", offsetof(Driver, set_char), 0 }, { "get_free_chars", offsetof(Driver, get_free_chars), 0 }, { "cellwidth", offsetof(Driver, cellwidth), 0 }, { "cellheight", offsetof(Driver, cellheight), 0 }, { "get_contrast", offsetof(Driver, get_contrast), 0 }, { "set_contrast", offsetof(Driver, set_contrast), 0 }, { "get_brightness", offsetof(Driver, get_brightness), 0 }, { "set_brightness", offsetof(Driver, set_brightness), 0 }, { "backlight", offsetof(Driver, backlight), 0 }, { "output", offsetof(Driver, output), 0 }, { "get_key", offsetof(Driver, get_key), 0 }, { "get_info", offsetof(Driver, get_info), 0 }, { NULL, 0, 0 } }; /* Functions for the driver */ static int request_display_width(void); static int request_display_height(void); static int driver_store_private_ptr(Driver *driver, void *private_data); /** Create a driver object. * Allocate memory for the driver object, load it from file and bind its symbols. * \param name Name under which the driver shall be known further on. * \param filename Name of the file containing the drivers object code. * \return Pointer to the freshly created driver; \c NULL on error. */ Driver * driver_load(const char *name, const char *filename) { Driver *driver = NULL; int res; report(RPT_DEBUG, "%s(name=\"%.40s\", filename=\"%.80s\")", __FUNCTION__, name, filename); /* fail on wrong / missing parameters */ if ((name == NULL) || (filename == NULL)) return NULL; /* Allocate memory for new driver struct */ driver = calloc(1, sizeof(Driver)); if (driver == NULL) { report(RPT_ERR, "%s: error allocating driver", __FUNCTION__); return NULL; } /* And store its name and filename */ driver->name = malloc(strlen(name) + 1); if (driver->name == NULL) { report(RPT_ERR, "%s: error allocating driver name", __FUNCTION__); free(driver); return NULL; } strcpy(driver->name, name); driver->filename = malloc(strlen(filename) + 1); if (driver->filename == NULL) { report(RPT_ERR, "%s: error allocating driver filename", __FUNCTION__); free(driver->name); free(driver); return NULL; } strcpy(driver->filename, filename); /* Load and bind the driver module and locate the symbols */ if (driver_bind_module(driver) < 0) { report(RPT_ERR, "Driver [%.40s] binding failed", name); free(driver->name); free(driver->filename); free(driver); return NULL; } /* Check module version */ if (strcmp(*(driver->api_version), API_VERSION) != 0) { report(RPT_ERR, "Driver [%.40s] is of an incompatible version", name); driver_unbind_module(driver); free(driver->name); free(driver->filename); free(driver); return NULL; } /* Call the init function */ debug(RPT_DEBUG, "%s: Calling driver [%.40s] init function", __FUNCTION__, driver->name); res = driver->init(driver); if (res < 0) { report(RPT_ERR, "Driver [%.40s] init failed, return code %d", driver->name, res); /* Driver load failed, driver should not be added to list * Free driver structure again */ driver_unbind_module(driver); free(driver->name); free(driver->filename); free(driver); return NULL; } debug(RPT_NOTICE, "Driver [%.40s] loaded", driver->name); return driver; } /** Unload driver from memory. * \param driver Driver to unload. * \retval <0 Error. * \retval 0 Success. */ int driver_unload(Driver *driver) { debug(RPT_NOTICE, "Closing driver [%.40s]", driver->name); /* close the driver, if its \c close method is [already] defined */ if (driver->close != NULL) driver->close(driver); /* unload the module */ driver_unbind_module(driver); /* free its data */ free(driver->filename); driver->filename = NULL; free(driver->name); driver->name = NULL; free(driver); driver = NULL; debug(RPT_DEBUG, "%s: Driver unloaded", __FUNCTION__); return 0; } /** Dynamically load a module and bind it to the Driver's symbols. * \param driver Pointer to the Driver object. * \retval <0 Error. * \retval 0 Success. */ int driver_bind_module(Driver *driver) { int i; int missing_symbols = 0; debug(RPT_DEBUG, "%s(driver=[%.40s])", __FUNCTION__, driver->name); /* Load the module */ driver->module_handle = dlopen(driver->filename, RTLD_NOW); if (driver->module_handle == NULL) { report(RPT_ERR, "Could not open driver module %.40s: %s", driver->filename, dlerror()); return -1; } /* And locate the symbols */ for (i = 0; driver_symbols[i].name != NULL; i++) { void (**p)(); p = (void(**)()) ((size_t)driver + (driver_symbols[i].offset)); *p = NULL; /* 1) try to retrieve the symbol with the driver's symbol_prefix added */ if (driver->symbol_prefix != NULL) { char *s = malloc(strlen(*(driver->symbol_prefix)) + strlen(driver_symbols[i].name) + 1); strcpy(s, *(driver->symbol_prefix)); strcat(s, driver_symbols[i].name); debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, s); *p = dlsym(driver->module_handle, s); free(s); } /* 2) try to retrieve the symbol without the symbol prefix */ if (*p == NULL) { debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, driver_symbols[i].name); *p = dlsym(driver->module_handle, driver_symbols[i].name); } if (*p != NULL) { debug(RPT_DEBUG, "%s: found symbol at: %p", __FUNCTION__, *p); } else { /* Was the symbol required but not found ? */ if (driver_symbols[i].required) { report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s", driver->name, driver_symbols[i].name); missing_symbols++; } } } /* If errors, leave now while we can :) */ if (missing_symbols > 0) { report(RPT_ERR, "Driver [%.40s] misses %d required symbols", driver->name, missing_symbols); dlclose(driver->module_handle); return -1; } /* Add our exported functions */ /* Config file functions */ driver->config_get_bool = config_get_bool; driver->config_get_int = config_get_int; driver->config_get_float = config_get_float; driver->config_get_string = config_get_string; driver->config_has_section = config_has_section; driver->config_has_key = config_has_key; /* Driver private data */ driver->store_private_ptr = driver_store_private_ptr; /* Display size request */ driver->request_display_width = request_display_width; driver->request_display_height = request_display_height; return 0; } /** Unload a Driver's module. * \param driver Pointer to the driver object. * \retval <0 Error. * \retval 0 Success. */ int driver_unbind_module(Driver *driver) { debug(RPT_DEBUG, "%s(driver=[%.40s])", __FUNCTION__, driver->name); dlclose(driver->module_handle); return 0; } /** Determine if the driver is an output driver. * This is done by checking whether the driver knows dimensions * and supports the methods that write to the screen. * \param driver Pointer to the driver object. * \retval 0 No, it is not an output driver. * \retval 1 Yes, it is an output driver. */ bool driver_does_output(Driver *driver) { return (driver->width != NULL || driver->height != NULL || driver->clear != NULL || driver->string != NULL || driver->chr != NULL) ? 1 : 0; } /** Determine if the driver is an input driver. * This is done by checking whether the driver supports the \c get_key method. * \param driver Pointer to the driver object. * \retval 0 No, it is not an input driver. * \retval 1 Yes, it is an input driver. */ bool driver_does_input(Driver *driver) { return (driver->get_key != NULL) ? 1 : 0; } /** Tell if the driver needs to stay in the foreground. * \param driver Pointer to the driver object. * \retval 0 No, the driver does not need to stay in the foreground. * \retval 1 Yes, the driver needs to stay in the foreground. */ bool driver_stay_in_foreground(Driver *driver) { return *driver->stay_in_foreground; } /** Tell if the driver supports multiple instances. * \param driver Pointer to the driver object. * \retval 0 No, it doesn't. * \retval 1 Yes, it does. */ bool driver_supports_multiple(Driver *driver) { return *driver->supports_multiple; } static int driver_store_private_ptr(Driver *driver, void *private_data) { debug(RPT_DEBUG, "%s(driver=[%.40s], ptr=%p)", __FUNCTION__, driver->name, private_data); driver->private_data = private_data; return 0; } static int request_display_width(void) { if (!display_props) return 0; return display_props->width; } static int request_display_height(void) { if (!display_props) return 0; return display_props->height; } /** Draw a vertical bar bottom-up. * Fallback for the driver's \c vbar method if the driver does not provide one. * \param drv Pointer to driver structure. * \param x Horizontal character position (column) of the starting point. * \param y Vertical character position (row) of the starting point. * \param len Number of characters that the bar is high at 100% * \param promille Current height level of the bar in promille. * \param options Options (currently unused). */ void driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int options) { int pos; debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, options=%d)", __FUNCTION__, drv->name, x, y, len, promille, options); /* if the driver does not support output, do nothing */ if (drv->chr == NULL) return; for (pos = 0; pos < len; pos++) { if (2 * pos < ((long) promille * len / 500 + 1)) { drv->chr(drv, x, y-pos, '|'); } else { ; /* print nothing */ } } } /** Draw a horizontal bar to the right. * Fallback for the driver's \c hbar method if the driver does not provide one. * \param drv Pointer to driver structure. * \param x Horizontal character position (column) of the starting point. * \param y Vertical character position (row) of the starting point. * \param len Number of characters that the bar is long at 100% * \param promille Current length level of the bar in promille. * \param options Options (currently unused). */ void driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int options) { int pos; debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, options=%d)", __FUNCTION__, drv->name, x, y, len, promille, options); /* if the driver does not support output, do nothing */ if (drv->chr == NULL) return; for (pos = 0; pos < len; pos++) { if (2 * pos < ((long) promille * len / 500 + 1)) { drv->chr(drv, x+pos, y, '-'); } else { ; /* print nothing */ } } } /** Write a big number to the screen. * Fallback for the driver's \c num method if the driver does not provide one. * \param drv Pointer to driver structure. * \param x Horizontal character position (column). * \param num Character to write (0 - 10 with 10 representing ':') */ void driver_alt_num(Driver *drv, int x, int num) { /* Ugly code extracted by David GLAUDE from lcdm001.c ;)*/ /* Moved to driver.c by Joris Robijn */ static char num_map[][4][4] = { { /* 0 */ " _ ", "| |", "|_|", " " }, { /* 1 */ " ", " |", " |", " " }, { /* 2 */ " _ ", " _|", "|_ ", " " }, { /* 3 */ " _ ", " _|", " _|", " " }, { /* 4 */ " ", "|_|", " |", " " }, { /* 5 */ " _ ", "|_ ", " _|", " " }, { /* 6 */ " _ ", "|_ ", "|_|", " " }, { /* 7 */ " _ ", " |", " |", " " }, { /* 8 */ " _ ", "|_|", "|_|", " " }, { /* 9 */ " _ ", "|_|", " _|", " " }, { /* colon */ " ", ".", ".", " " } }; /* End of ugly code ;) by Rene Wagner */ /* I like this code ! Joris */ int y, dx; debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, num=%d)", __FUNCTION__, drv->name, x, num); if ((num < 0) || (num > 10)) return; /* if the driver does not support output, do nothing */ if (drv->chr == NULL) return; for (y = 0; y < 4; y++) for (dx = 0; num_map[num][y][dx] != '\0'; dx++) drv->chr(drv, x + dx, y+1, num_map[num][y][dx]); } /** Show the heartbeat. * Fallback for the driver's \c heartbeat method if the driver does not provide one. * \param drv Pointer to driver structure. * \param state Current heartbeat state. */ void driver_alt_heartbeat(Driver *drv, int state) { int icon; debug(RPT_DEBUG, "%s(drv=[%.40s], state=%d)", __FUNCTION__, drv->name, state); if (state == HEARTBEAT_OFF) return; /* Don't display anything */ /* if the driver does not support output, do nothing */ if (drv->width == NULL) return; /* Hmm, is this a good method ? * Or should we use clock() ? Or ftime ? Or gettimeofday ? */ icon = (timer & 5) ? ICON_HEART_FILLED : ICON_HEART_OPEN; if (drv->icon) drv->icon(drv, drv->width(drv), 1, icon); else driver_alt_icon(drv, drv->width(drv), 1, icon); } /** Place an icon on the screen. * Fallback for the driver's \c icon method, in case either the driver does not * provide one or the driver's method indicates the icon needs to be handled * by the server core. * \param drv Pointer to driver structure. * \param x Horizontal character position (column). * \param y Vertical character position (row). * \param icon synbolic value representing the icon. * * \note Icons used for 'play control' actually are composed of two * characters. Drivers must check for bounds on calls to chr()! */ void driver_alt_icon(Driver *drv, int x, int y, int icon) { char ch1 = '?'; char ch2 = '\0'; debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, icon=ICON_%s)", __FUNCTION__, drv->name, x, y, widget_icon_to_iconname(icon)); /* if the driver does not support output, do nothing */ if (drv->chr == NULL) return; switch (icon) { case ICON_BLOCK_FILLED: ch1 = '#'; break; case ICON_HEART_OPEN: ch1 = '-'; break; case ICON_HEART_FILLED: ch1 = '#'; break; case ICON_ARROW_UP: ch1 = '^'; break; case ICON_ARROW_DOWN: ch1 = 'v'; break; case ICON_ARROW_LEFT: ch1 = '<'; break; case ICON_ARROW_RIGHT: ch1 = '>'; break; case ICON_CHECKBOX_OFF: ch1 = 'N'; break; case ICON_CHECKBOX_ON: ch1 = 'Y'; break; case ICON_CHECKBOX_GRAY: ch1 = 'o'; break; case ICON_SELECTOR_AT_LEFT: ch1 = '>'; break; case ICON_SELECTOR_AT_RIGHT: ch1 = '<'; break; case ICON_ELLIPSIS: ch1 = '_'; break; case ICON_STOP: ch1 = '['; ch2 = ']'; break; case ICON_PAUSE: ch1 = '|'; ch2 = '|'; break; case ICON_PLAY: ch1 = '>'; ch2 = ' '; break; case ICON_PLAYR: ch1 = '<'; ch2 = ' '; break; case ICON_FF: ch1 = '>'; ch2 = '>'; break; case ICON_FR: ch1 = '<'; ch2 = '<'; break; case ICON_NEXT: ch1 = '>'; ch2 = '|'; break; case ICON_PREV: ch1 = '|'; ch2 = '<'; break; case ICON_REC: ch1 = '('; ch2 = ')'; break; } drv->chr(drv, x, y, ch1); if (ch2 != '\0') drv->chr(drv, x+1, y, ch2); } /** Set cursor position and state. * Fallback for the driver's \c cursor method if the driver does not provide one. * \param drv Pointer to driver structure. * \param x Horizontal cursor position (column). * \param y Vertical cursor position (row). * \param state New cursor state. */ void driver_alt_cursor(Driver *drv, int x, int y, int state) { /* Same question about timer in this function... */ debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, state=%d)", __FUNCTION__, drv->name, x, y, state); switch (state) { case CURSOR_BLOCK: case CURSOR_DEFAULT_ON: if ((timer & 2) && (drv->chr != NULL)) { if (drv->icon != NULL) { drv->icon(drv, x, y, ICON_BLOCK_FILLED); } else { driver_alt_icon(drv, x, y, ICON_BLOCK_FILLED); } } break; case CURSOR_UNDER: if ((timer & 2) && (drv->chr != NULL)) { drv->chr(drv, x, y, '_'); } break; } } lcdproc-0.5.9/server/clients.h0000644000175100017510000000153012505300405013207 00000000000000/** \file server/clients.h * Manage the list of clients that are connected. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven */ #ifndef CLIENTS_H #define CLIENTS_H #include "client.h" /* Initialize and kill client list...*/ int clients_init(void); int clients_shutdown(void); /* Add/remove clients (return NULL for error) */ Client *clients_add_client(Client *c); Client *clients_remove_client(Client *c, Direction whereto); /* List functions */ Client *clients_getfirst(void); Client *clients_getnext(void); int clients_client_count(void); /* Search for a client with a particular filedescriptor...*/ Client * clients_find_client_by_sock(int sock); #endif lcdproc-0.5.9/server/serverscreens.h0000644000175100017510000000153012505300405014437 00000000000000/** \file server/serverscreens.h * Interface for the serverscreen implementation. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven */ #ifndef SRVSTATS_H #define SRVSTATS_H #include "screen.h" /* server screen rotation states */ #define SERVERSCREEN_OFF 0 /**< Show server screen in rotation. */ #define SERVERSCREEN_ON 1 /**< Show server sreen only when there is no other screen. */ #define SERVERSCREEN_BLANK 2 /**< Don't rotate, and only show a blank screen. */ extern Screen *server_screen; extern int rotate_server_screen; int server_screen_init(void); int server_screen_shutdown(void); int update_server_screen(void); int goodbye_screen(void); #endif lcdproc-0.5.9/server/input.c0000644000175100017510000001446512505300405012713 00000000000000/** \file server/input.c * Handles keypad (and other?) input from the user. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2003, Joris Robijn */ #include #include #include #include "shared/sockets.h" #include "shared/report.h" #include "shared/configfile.h" #include "shared/LL.h" #include "drivers.h" #define INC_TYPES_ONLY 1 #include "client.h" #include "screen.h" #undef INC_TYPES_ONLY #include "screenlist.h" #include "menuscreens.h" #include "input.h" #include "render.h" /* For server_msg* */ LinkedList *keylist; char *toggle_rotate_key; char *prev_screen_key; char *next_screen_key; char *scroll_up_key; char *scroll_down_key; /* Local functions */ int server_input(int key); void input_send_to_client(Client *c, const char *key); void input_internal_key(const char *key); int input_init(void) { debug(RPT_DEBUG, "%s()", __FUNCTION__); keylist = LL_new(); /* Get rotate/scroll keys from config file */ toggle_rotate_key = strdup(config_get_string("server", "ToggleRotateKey", 0, "Enter")); prev_screen_key = strdup(config_get_string("server", "PrevScreenKey", 0, "Left")); next_screen_key = strdup(config_get_string("server", "NextScreenKey", 0, "Right")); scroll_up_key = strdup(config_get_string("server", "ScrollUpKey", 0, "Up")); scroll_down_key = strdup(config_get_string("server", "ScrollDownKey", 0, "Down")); return 0; } int input_shutdown() { if (!keylist) { /* Program shutdown before completed startup */ return -1; } free(keylist); free(toggle_rotate_key); free(prev_screen_key); free(next_screen_key); free(scroll_up_key); free(scroll_down_key); return 0; } int handle_input(void) { const char *key; Screen *current_screen; Client *current_client; Client *target; KeyReservation *kr; debug(RPT_DEBUG, "%s()", __FUNCTION__); current_screen = screenlist_current(); if (current_screen) current_client = current_screen->client; else current_client = NULL; /* Handle all keypresses */ while ((key = drivers_get_key()) != NULL) { /* Find what client wants the key */ kr = input_find_key(key, current_client); if (kr) { /* A hit ! */ report(RPT_DEBUG, "%s: reserved key: \"%.40s\"", __FUNCTION__, key); target = kr->client; } else { report(RPT_DEBUG, "%s: left over key: \"%.40s\"", __FUNCTION__, key); /*target = current_client;*/ target = NULL; /* left-over keys are always for internal client */ } if (target == NULL) { report(RPT_DEBUG, "%s: key is for internal client", __FUNCTION__); input_internal_key(key); } else { /* It's an external client */ report(RPT_DEBUG, "%s: key is for external client on socket %d", __FUNCTION__, target->sock); input_send_to_client(target, key); } } return 0; } void input_send_to_client(Client *c, const char *key) { char *s; size_t size = strlen(key) + sizeof("key %s\n"); // this is large enough debug(RPT_DEBUG, "%s(client=[%d], key=\"%.40s\")", __FUNCTION__, c->sock, key); /* Allocate just as much as we need */ s = calloc(1, size); if (s != NULL) { snprintf(s, size, "key %s\n", key); sock_send_string(c->sock, s); free(s); } else report(RPT_ERR, "%s: malloc failure", __FUNCTION__); } void input_internal_key(const char *key) { if (is_menu_key(key) || screenlist_current() == menuscreen) { menuscreen_key_handler(key); } else { /* Keys are for scrolling or rotating */ if (strcmp(key, toggle_rotate_key) == 0) { autorotate = !autorotate; if (autorotate) { server_msg("Rotate", 4); } else { server_msg("Hold", 4); } } else if (strcmp(key, prev_screen_key) == 0) { screenlist_goto_prev(); server_msg("Prev", 4); } else if (strcmp(key, next_screen_key) == 0) { screenlist_goto_next(); server_msg("Next", 4); } else if (strcmp(key, scroll_up_key) == 0) { } else if (strcmp(key, scroll_down_key) == 0) { } } } int input_reserve_key(const char *key, bool exclusive, Client *client) { KeyReservation *kr; debug(RPT_DEBUG, "%s(key=\"%.40s\", exclusive=%d, client=[%d])", __FUNCTION__, key, exclusive, (client?client->sock:-1)); /* Find out if this key is already reserved in a way that interferes * with the new reservation. */ for (kr = LL_GetFirst(keylist); kr != NULL; kr = LL_GetNext(keylist)) { if (strcmp(kr->key, key) == 0) { if (kr->exclusive || exclusive) { /* Sorry ! */ return -1; } } } /* We can now safely add it ! */ kr = malloc(sizeof(KeyReservation)); kr->key = strdup(key); kr->exclusive = exclusive; kr->client = client; LL_Push(keylist, kr); report(RPT_INFO, "Key \"%.40s\" is now reserved %s by client [%d]", key, (exclusive ? "exclusively" : "shared"), (client ? client->sock : -1)); return 0; } void input_release_key(const char *key, Client *client) { KeyReservation *kr; debug(RPT_DEBUG, "%s(key=\"%.40s\", client=[%d])", __FUNCTION__, key, (client ? client->sock : -1)); for (kr = LL_GetFirst(keylist); kr != NULL; kr = LL_GetNext(keylist)) { if ((kr->client == client) && (strcmp(kr->key, key) == 0)) { report(RPT_INFO, "Key \"%.40s\" reserved %s by client [%d] and is now released", key, (kr->exclusive ? "exclusively" : "shared"), (client ? client->sock : -1)); free(kr->key); free(kr); LL_DeleteNode(keylist, NEXT); return; } } } void input_release_client_keys(Client *client) { KeyReservation *kr; debug(RPT_DEBUG, "%s(client=[%d])", __FUNCTION__, (client ? client->sock : -1)); for (kr = LL_GetFirst(keylist); kr != NULL; kr = LL_GetNext(keylist)) { if (kr->client == client) { report(RPT_INFO, "Key \"%.40s\" reserved %s by client [%d] and is now released", kr->key, (kr->exclusive ? "exclusively" : "shared"), (client ? client->sock : -1)); free(kr->key); free(kr); // jump to node before deleted one to not miss any LL_DeleteNode(keylist, PREV); } } } KeyReservation *input_find_key(const char *key, Client *client) { KeyReservation *kr; debug(RPT_DEBUG, "%s(key=\"%.40s\", client=[%d])", __FUNCTION__, key, (client?client->sock:-1)); for (kr = LL_GetFirst(keylist); kr != NULL; kr = LL_GetNext(keylist)) { if (strcmp(kr->key, key) == 0) { if (kr->exclusive || client == kr->client) { return kr; } } } return NULL; } lcdproc-0.5.9/server/parse.c0000644000175100017510000001266512505300405012666 00000000000000/** \file server/parse.c * Handles input commands from clients, by splitting strings into tokens * and passing arguments to the appropriate handler. * * It works much like a command line. Only the first token is used to * determine what function to call. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2008, Peter Marschall */ #include #include #include #include "shared/LL.h" #include "shared/sockets.h" #include "shared/report.h" #include "clients.h" #include "commands/command_list.h" #include "parse.h" #include "sock.h" #define MAX_ARGUMENTS 40 static inline int is_whitespace(char x) { return ((x == ' ') || (x == '\t') || (x == '\r')); } static inline int is_final(char x) { return ((x == '\n') || (x == '\0')); } static inline int is_opening_quote(char x, char q) { return ((q == '\0') && ((x == '\"') || (x == '{'))); } static inline int is_closing_quote(char x, char q) { return (((q == '{') && (x == '}')) || ((q == '\"') && (x == '\"'))); } static int parse_message(const char *str, Client *c) { typedef enum { ST_INITIAL, ST_WHITESPACE, ST_ARGUMENT, ST_FINAL } State; State state = ST_INITIAL; int error = 0; char quote = '\0'; /* The quote used to open a quote string */ int pos = 0; char *arg_space; int argc = 0; char *argv[MAX_ARGUMENTS]; int argpos = 0; CommandFunc function = NULL; debug(RPT_DEBUG, "%s(str=\"%.120s\", client=[%d])", __FUNCTION__, str, c->sock); /* We will create a list of strings that is shorter or equally long as * the original string str. */ arg_space = malloc(strlen(str)+1); if (arg_space == NULL) { report(RPT_ERR, "%s: Could not allocate memory", __FUNCTION__); sock_send_error(c->sock, "error allocating memory!\n"); } argv[0] = arg_space; while ((state != ST_FINAL) && !error) { char ch = str[pos++]; switch (state) { case ST_INITIAL: case ST_WHITESPACE: if (is_whitespace(ch)) break; if (is_final(ch)) { state = ST_FINAL; break; } /* otherwise fall through */ state = ST_ARGUMENT; case ST_ARGUMENT: if (is_final(ch)) { if (quote) error = 2; if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_FINAL; } else if (ch == '\\') { if (str[pos]) { /* We solve quoted chars here right away */ const char escape_chars[] = "nrt"; const char escape_trans[] = "\n\r\t"; char *p = strchr(escape_chars, str[pos]); /* Is it wise to have the characters \n, \r & \t expanded ? * Can the displays deal with them ? */ if (p != NULL) { /* Insert a replacement for the code */ argv[argc][argpos++] = escape_trans[p - escape_chars]; } else { /* Copy char literally */ argv[argc][argpos++] = str[pos]; } pos++; } else { error = 2; /* alternative: argv[argc][argpos++] = ch; */ if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_FINAL; } } else if (is_opening_quote(ch, quote)) { quote = ch; } else if (is_closing_quote(ch, quote)) { quote = '\0'; if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_WHITESPACE; } else if (is_whitespace(ch) && (quote == '\0')) { if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_WHITESPACE; } else { argv[argc][argpos++] = ch; } break; case ST_FINAL: /* This will never be reached */ break; } } if (argc < MAX_ARGUMENTS) argv[argc] = NULL; else error = 1; if (error) { sock_send_error(c->sock, "Could not parse command\n"); free(arg_space); return 0; } #if 0 /* show what we have parsed */ int i; for (i = 0; i < argc; i++) { printf("%s%c", argv[i], (i == argc-1) ? '\n' : ' '); } #endif /* Now find and call the appropriate function...*/ function = get_command_function(argv[0]); if (function != NULL) { error = function(c, argc, argv); if (error) { sock_printf_error(c->sock, "Function returned error \"%.40s\"\n", argv[0]); report(RPT_WARNING, "Command function returned an error after command from client on socket %d: %.40s", c->sock, str); } } else { sock_printf_error(c->sock, "Invalid command \"%.40s\"\n", argv[0]); report(RPT_WARNING, "Invalid command from client on socket %d: %.40s", c->sock, str); } free(arg_space); return 0; } int parse_all_client_messages(void) { Client *c; debug(RPT_DEBUG, "%s()", __FUNCTION__); for (c = clients_getfirst(); c != NULL; c = clients_getnext()) { char *str; /* And parse all its messages...*/ /*debug(RPT_DEBUG, "parse: Getting messages...");*/ for (str = client_get_message(c); str != NULL; str = client_get_message(c)) { parse_message(str, c); free(str); if (c->state == GONE) { sock_destroy_client_socket(c); break; } } } return 0; } lcdproc-0.5.9/server/input.h0000644000175100017510000000256412505300405012715 00000000000000/** \file server/input.h */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2003, Joris Robijn */ #ifndef INPUT_H #define INPUT_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STDBOOL_H # include #endif #include "shared/defines.h" /* Accepts and uses keypad input while displaying screens... */ int handle_input(void); typedef struct KeyReservation { char *key; bool exclusive; Client *client; /* NULL for internal clients */ } KeyReservation; int input_init(void); /* Init the input handling system */ int input_shutdown(void); /* Shut it down */ int input_reserve_key(const char *key, bool exclusive, Client *client); /* Reserves a key for a client */ /* Return -1 if reservation of key is not possible */ void input_release_key(const char *key, Client *client); /* Releases a key reservation */ void input_release_client_keys(Client *client); /* Releases all key reservations for a given client */ KeyReservation *input_find_key(const char *key, Client *client); /* Finds if a key reservation causes a 'hit'. * If the key was reserved exclusively, the client will be ignored. * If the key was reserved shared, the client must match. */ #endif lcdproc-0.5.9/server/render.c0000644000175100017510000004566213065726500013050 00000000000000/** \file server/render.c * This file contains code that actually generates the full screen data to * send to the LCD. render_screen() takes a screen definition and calls * render_frame() which in turn builds the screen according to the definition. * It may recursively call itself (for nested frames). * * This needs to be greatly expanded and redone for greater flexibility. * For example, it should support multiple screen sizes, more flexible * widgets, and multiple simultaneous screens. * * This will probably take a while to do. :( * * THIS FILE IS MESSY! Anyone care to rewrite it nicely? Please?? :) * * NOTE: (from David Douthitt) Multiple screen sizes? Multiple simultaneous * screens? Horrors of horrors... next thing you know it'll be making coffee... * Better believe it'll take a while to do... * * \todo Review render_string for correctness. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2001, Joris Robijn * 2007, Peter Marschall */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "shared/report.h" #include "shared/LL.h" #include "shared/defines.h" #include "drivers.h" #include "screen.h" #include "screenlist.h" #include "widget.h" #include "render.h" #define BUFSIZE 1024 /* larger than display width => large enough */ int heartbeat = HEARTBEAT_OPEN; static int heartbeat_fallback = HEARTBEAT_ON; /* If no heartbeat setting has been set at all */ int backlight = BACKLIGHT_OPEN; static int backlight_fallback = BACKLIGHT_ON; /* If no backlight setting has been set at all */ int titlespeed = 1; int output_state = 0; char *server_msg_text; int server_msg_expire = 0; static int render_frame(LinkedList *list, int left, int top, int right, int bottom, int fwid, int fhgt, char fscroll, int fspeed, long timer); static int render_string(Widget *w, int left, int top, int right, int bottom, int fy); static int render_hbar(Widget *w, int left, int top, int right, int bottom, int fy); static int render_vbar(Widget *w, int left, int top, int right, int bottom); static int render_title(Widget *w, int left, int top, int right, int bottom, long timer); static int render_scroller(Widget *w, int left, int top, int right, int bottom, long timer); static int render_num(Widget *w, int left, int top, int right, int bottom); /** * Renders a screen. The following actions are taken in order: * * \li Clear the screen. * \li Set the backlight. * \li Set out-of-band data (output). * \li Render the frame contents. * \li Set the cursor. * \li Draw the heartbeat. * \li Show any server message. * \li Flush all output to screen. * * \param s The screen to render. * \param timer A value increased with every call. * \return -1 on error, 0 on success. */ int render_screen(Screen *s, long timer) { int tmp_state = 0; debug(RPT_DEBUG, "%s(screen=[%.40s], timer=%ld) ==== START RENDERING ====", __FUNCTION__, s->id, timer); if (s == NULL) return -1; /* 1. Clear the LCD screen... */ drivers_clear(); /* 2. Set up the backlight */ /*- * 2.1: * First we find out who has set the backlight: * a) the screen, * b) the client, or * c) the server core * with the latter taking precedence over the earlier. If the * backlight is not set on/off then use the fallback (set it ON). */ if (backlight != BACKLIGHT_OPEN) { tmp_state = backlight; } else if ((s->client != NULL) && (s->client->backlight != BACKLIGHT_OPEN)) { tmp_state = s->client->backlight; } else if (s->backlight != BACKLIGHT_OPEN) { tmp_state = s->backlight; } else { tmp_state = backlight_fallback; } /*- * 2.2: * If one of the backlight options (FLASH or BLINK) has been set turn * it on/off based on a timed algorithm. */ /* NOTE: dirty stripping of other options... */ /* Backlight flash: check timer and flip backlight as appropriate */ if (tmp_state & BACKLIGHT_FLASH) { drivers_backlight( ( (tmp_state & BACKLIGHT_ON) ^ ((timer & 7) == 7) ) ? BACKLIGHT_ON : BACKLIGHT_OFF); } /* Backlight blink: check timer and flip backlight as appropriate */ else if (tmp_state & BACKLIGHT_BLINK) { drivers_backlight( ( (tmp_state & BACKLIGHT_ON) ^ ((timer & 14) == 14) ) ? BACKLIGHT_ON : BACKLIGHT_OFF); } else { /* Simple: Only send lowest bit then... */ drivers_backlight(tmp_state & BACKLIGHT_ON); } /* 3. Output ports from LCD - outputs depend on the current screen */ drivers_output(output_state); /* 4. Draw a frame... */ render_frame(s->widgetlist, 0, 0, display_props->width, display_props->height, s->width, s->height, 'v', max(s->duration / s->height, 1), timer); /* 5. Set the cursor */ drivers_cursor(s->cursor_x, s->cursor_y, s->cursor); /* 6. Set the heartbeat */ if (heartbeat != HEARTBEAT_OPEN) { tmp_state = heartbeat; } else if ((s->client != NULL) && (s->client->heartbeat != HEARTBEAT_OPEN)) { tmp_state = s->client->heartbeat; } else if (s->heartbeat != HEARTBEAT_OPEN) { tmp_state = s->heartbeat; } else { tmp_state = heartbeat_fallback; } drivers_heartbeat(tmp_state); /* 7. If there is an server message that is not expired, display it */ if (server_msg_expire > 0) { drivers_string(display_props->width - strlen(server_msg_text) + 1, display_props->height, server_msg_text); server_msg_expire--; if (server_msg_expire == 0) { free(server_msg_text); } } /* 8. Flush display out, frame and all... */ drivers_flush(); debug(RPT_DEBUG, "==== END RENDERING ===="); return 0; } /* The following function is positively ghastly (as was mentioned above!) */ /* Best thing to do is to remove support for frames... but anyway... */ /* */ static int render_frame(LinkedList *list, int left, /* left edge of frame */ int top, /* top edge of frame */ int right, /* right edge of frame */ int bottom, /* bottom edge of frame */ int fwid, /* frame width? */ int fhgt, /* frame height? */ char fscroll, /* direction of scrolling */ int fspeed, /* speed of scrolling... */ long timer) /* current timer tick */ { int fy = 0; /* Scrolling offset for the frame... */ debug(RPT_DEBUG, "%s(list=%p, left=%d, top=%d, " "right=%d, bottom=%d, fwid=%d, fhgt=%d, " "fscroll='%c', fspeed=%d, timer=%ld)", __FUNCTION__, list, left, top, right, bottom, fwid, fhgt, fscroll, fspeed, timer); /* return on no data or illegal height */ if ((list == NULL) || (fhgt <= 0)) return -1; if (fscroll == 'v') { /* vertical scrolling */ // only set offset !=0 when fspeed is != 0 and there is something to scroll if ((fspeed != 0) && (fhgt > bottom - top)) { int fy_max = fhgt - (bottom - top) + 1; fy = (fspeed > 0) ? (timer / fspeed) % fy_max : (-fspeed * timer) % fy_max; fy = max(fy, 0); // safeguard against negative values debug(RPT_DEBUG, "%s: fy=%d", __FUNCTION__, fy); } } else if (fscroll == 'h') { /* horizontal scrolling */ /* TODO: Frames don't scroll horizontally yet! */ } /* reset widget list */ LL_Rewind(list); /* loop over all widgets */ do { Widget *w = (Widget *) LL_Get(list); if (w == NULL) return -1; /* TODO: Make this cleaner and more flexible! */ switch (w->type) { case WID_STRING: render_string(w, left, top - fy, right, bottom, fy); break; case WID_HBAR: render_hbar(w, left, top - fy, right, bottom, fy); break; case WID_VBAR: /* FIXME: Vbars don't work in frames! */ render_vbar(w, left, top, right, bottom); break; case WID_ICON: /* FIXME: Icons don't work in frames! */ drivers_icon(w->x, w->y, w->length); break; case WID_TITLE: /* FIXME: Doesn't work quite right in frames... */ render_title(w, left, top, right, bottom, timer); break; case WID_SCROLLER: /* FIXME: doesn't work in frames... */ render_scroller(w, left, top, right, bottom, timer); break; case WID_FRAME: { /* FIXME: doesn't handle nested frames quite right! * doesn't handle scrolling in nested frames at all... */ int new_left = left + w->left - 1; int new_top = top + w->top - 1; int new_right = min(left + w->right, right); int new_bottom = min(top + w->bottom, bottom); if ((new_left < right) && (new_top < bottom)) /* Render only if it's visible... */ render_frame(w->frame_screen->widgetlist, new_left, new_top, new_right, new_bottom, w->width, w->height, w->length, w->speed, timer); } break; case WID_NUM: /* FIXME: doesn't work in frames... */ /* NOTE: y=10 means COLON (:) */ if ((w->x > 0) && (w->y >= 0) && (w->y <= 10)) { drivers_num(w->x + left, w->y); } break; case WID_NONE: /* FALLTHROUGH */ default: break; } } while (LL_Next(list) == 0); return 0; } static int render_string(Widget *w, int left, int top, int right, int bottom, int fy) { debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, fy=%d)", __FUNCTION__, w, left, top, right, bottom, fy); if ((w != NULL) && (w->text != NULL) && (w->x > 0) && (w->y > 0) && (w->y > fy) && (w->y <= bottom - top)) { /* * FIXME: Could be a bug here? w->x is recalculated (On first * call only? Is it preserved between calls?) and first * character of w->text shows up on the rightmost column for * strings totally off-screen. Is this on purpose? (M. Dolze) */ w->x = min(w->x, right - left); drivers_string(w->x + left, w->y + top, w->text); } return 0; } static int render_hbar(Widget *w, int left, int top, int right, int bottom, int fy) { debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, fy=%d)", __FUNCTION__, w, left, top, right, bottom, fy); if ((w != NULL) && (w->x > 0) && (w->y > 0) && (w->y > fy) && (w->y <= bottom - top)) { if (w->length > 0) { int full_len = display_props->width - w->x - left + 1; int promille = 1000; if ((w->length / display_props->cellwidth) < right - left - w->x + 1) promille = (long) 1000 * w->length / (display_props->cellwidth * full_len); drivers_hbar(w->x + left, w->y + top, full_len, promille, BAR_PATTERN_FILLED); } else if (w->length < 0) { /* TODO: Rearrange stuff to get left-extending * hbars to draw correctly... * .. er, this'll require driver modifications, * so I'll leave it out for now. */ } } return 0; } static int render_vbar(Widget *w, int left, int top, int right, int bottom) { debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d)", __FUNCTION__, w, left, top, right, bottom); if ((w != NULL) && (w->x > 0) && (w->y > 0)) { if (w->length > 0) { int full_len = display_props->height; int promille = (long) 1000 * w->length / (display_props->cellheight * full_len); drivers_vbar(w->x + left, w->y + top, full_len, promille, BAR_PATTERN_FILLED); } else if (w->length < 0) { /* TODO: Rearrange stuff to get down-extending * vbars to draw correctly... * .. er, this'll require driver modifications, * so I'll leave it out for now. */ } } return 0; } static int render_title(Widget *w, int left, int top, int right, int bottom, long timer) { int vis_width = right - left; debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, timer=%ld)", __FUNCTION__, w, left, top, right, bottom, timer); if ((w != NULL) && (w->text != NULL) && (vis_width >= 8)) { char str[BUFSIZE]; int length = strlen(w->text); int width = vis_width - 6; int x; /* calculate delay from titlespeed: <=0 -> 0, [1 - infty] -> [10 - 1] */ int delay = (titlespeed <= TITLESPEED_NO) ? TITLESPEED_NO : max(TITLESPEED_MIN, TITLESPEED_MAX - titlespeed); /* display leading fillers */ drivers_icon(w->x + left, w->y + top, ICON_BLOCK_FILLED); drivers_icon(w->x + left + 1, w->y + top, ICON_BLOCK_FILLED); length = min(length, sizeof(str)-1); if ((length <= width) || (delay == 0)) { /* copy test starting from the beginning */ length = min(length, width); strncpy(str, w->text, length); str[length] = '\0'; /* set x value for trailing fillers */ x = length + 4; } else { /* Scroll the title, if it doesn't fit... */ int offset = timer; int reverse; /* if the delay is "too large" increase cycle length */ if ((delay != 0) && (delay < length / (length - width))) offset /= delay; /* reverse direction every length ticks */ reverse = (offset / length) & 1; /* restrict offset to cycle length */ offset %= length; offset = max(offset, 0); /* if the delay is "low enough" slow down as requested */ if ((delay != 0) && (delay >= length / (length - width))) offset /= delay; /* restrict offset to the max. allowed offset: length - width */ offset = min(offset, length - width); /* scroll backward by mirroring offset at max. offset */ if (reverse) offset = (length - width) - offset; /* copy test starting from offset */ length = min(width, sizeof(str)-1); strncpy(str, w->text + offset, length); str[length] = '\0'; /* set x value for trailing fillers */ x = vis_width - 2; } /* display text */ drivers_string(w->x + 3 + left, w->y + top, str); /* display trailing fillers */ for ( ; x < vis_width; x++) { drivers_icon(w->x + x + left, w->y + top, ICON_BLOCK_FILLED); } } return 0; } static int render_scroller(Widget *w, int left, int top, int right, int bottom, long timer) { char str[BUFSIZE]; int length; int offset, gap; int screen_width; int necessaryTimeUnits = 0; debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, timer=%ld)", __FUNCTION__, w, left, top, right, bottom, timer); if ((w->text == NULL) || (w->right < w->left)) return 0; screen_width = abs(w->right - w->left + 1); screen_width = min(screen_width, sizeof(str)-1); switch (w->length) { /* actually, direction... */ case 'm': // Marquee length = strlen(w->text); if (length <= screen_width) { /* it fits within the box, just render it */ drivers_string(w->left, w->top, w->text); break; } gap = screen_width / 2; length += gap; /* Allow gap between end and beginning */ if (w->speed > 0) { necessaryTimeUnits = length * w->speed; offset = (timer % necessaryTimeUnits) / w->speed; } else if (w->speed < 0) { necessaryTimeUnits = length / (w->speed * -1); offset = (timer % necessaryTimeUnits) * w->speed * -1; } else { offset = 0; } if (offset <= length) { if (gap > offset) { memset(str, ' ', gap - offset); strncpy(&str[gap-offset], w->text, screen_width); } else { int room = screen_width - (length - offset); strncpy(str, &w->text[offset-gap], screen_width); if (room > 0) { memset(&str[length-offset], ' ', min(room, gap)); room -= gap; if (room > 0) strncpy(&str[length-offset+gap], w->text, room); } } str[screen_width] = '\0'; drivers_string(w->left, w->top, str); } break; case 'h': length = strlen(w->text) + 1; if (length <= screen_width) { /* it fits within the box, just render it */ drivers_string(w->left, w->top, w->text); } else { int effLength = length - screen_width; if (w->speed > 0) { necessaryTimeUnits = effLength * w->speed; if (((timer / necessaryTimeUnits) % 2) == 0) { /* wiggle one way */ offset = (timer % (effLength*w->speed)) / w->speed; } else { /* wiggle the other */ offset = (((timer % (effLength * w->speed)) - (effLength * w->speed) + 1) / w->speed) * -1; } } else if (w->speed < 0) { necessaryTimeUnits = effLength / (w->speed * -1); if (((timer / necessaryTimeUnits) % 2) == 0) { offset = (timer % (effLength / (w->speed * -1))) * w->speed * -1; } else { offset = (((timer % (effLength / (w->speed * -1))) * w->speed * -1) - effLength + 1) * -1; } } else { offset = 0; } if (offset <= length) { strncpy(str, &((w->text)[offset]), screen_width); str[screen_width] = '\0'; drivers_string(w->left, w->top, str); /*debug(RPT_DEBUG, "scroller %s : %d", str, length-offset); */ } } break; /* FIXME: Vert scrollers don't always seem to scroll */ /* back up after hitting the bottom. They jump back to */ /* the top instead... (nevermind?) */ case 'v': length = strlen(w->text); if (length <= screen_width) { /* no scrolling required... */ drivers_string(w->left, w->top, w->text); } else { int lines_required = (length / screen_width) + (length % screen_width ? 1 : 0); int available_lines = (w->bottom - w->top + 1); if (lines_required <= available_lines) { /* easy... */ int i; for (i = 0; i < lines_required; i++) { strncpy(str, &((w->text)[i * screen_width]), screen_width); str[screen_width] = '\0'; drivers_string(w->left, w->top + i, str); } } else { int effLines = lines_required - available_lines + 1; int begin = 0; int i = 0; /*debug(RPT_DEBUG, "length: %d sw: %d lines req: %d avail lines: %d effLines: %d ",length,screen_width,lines_required,available_lines,effLines);*/ if (w->speed > 0) { necessaryTimeUnits = effLines * w->speed; if (((timer / necessaryTimeUnits) % 2) == 0) { /*debug(RPT_DEBUG, "up ");*/ begin = (timer % (necessaryTimeUnits)) / w->speed; } else { /*debug(RPT_DEBUG, "down ");*/ begin = (((timer % necessaryTimeUnits) - necessaryTimeUnits + 1) / w->speed) * -1; } } else if (w->speed < 0) { necessaryTimeUnits = effLines / (w->speed * -1); if (((timer / necessaryTimeUnits) % 2) == 0) { begin = (timer % necessaryTimeUnits) * w->speed * -1; } else { begin = (((timer % necessaryTimeUnits) * w->speed * -1) - effLines + 1) * -1; } } else { begin = 0; } /*debug(RPT_DEBUG, "rendering begin: %d timer: %d effLines: %d",begin,timer,effLines); */ for (i = begin; i < begin + available_lines; i++) { strncpy(str, &((w->text)[i * (screen_width)]), screen_width); str[screen_width] = '\0'; /*debug(RPT_DEBUG, "rendering: '%s' of %s", */ /*str,w->text); */ drivers_string(w->left, w->top + (i - begin), str); } } } break; } return 0; } static int render_num(Widget *w, int left, int top, int right, int bottom) { debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d)", __FUNCTION__, w, left, top, right, bottom); /* NOTE: y=10 means COLON (:) */ if ((w != NULL) && (w->x > 0) && (w->y >= 0) && (w->y <= 10)) { drivers_num(w->x + left, w->y); } return 0; } int server_msg(const char *text, int expire) { debug(RPT_DEBUG, "%s(text=\"%.40s\", expire=%d)", __FUNCTION__, text, expire); if (strlen(text) > 15 || expire <= 0) { return -1; } /* Still a message active ? */ if (server_msg_expire > 0) { free(server_msg_text); } /* Store new message */ server_msg_text = malloc(strlen(text) + 3); strcpy(server_msg_text, "| "); strcat(server_msg_text, text); server_msg_expire = expire; return 0; } lcdproc-0.5.9/server/client.h0000644000175100017510000000400012505300405013017 00000000000000/** \file server/client.h * Defines all the client data and actions. * * \note If you only need 'struct Client' to work with, you should use the * following code (which does not create an indirect dependency on * 'struct Screen'): * * \code * #define INC_TYPES_ONLY 1 * #include "client.h" * #undef INC_TYPES_ONLY * \endcode */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn */ #ifndef CLIENT_H_TYPES #define CLIENT_H_TYPES #include "shared/LL.h" #define CLIENT_NAME_SIZE 256 /** Possible states of a client. */ typedef enum _clientstate { NEW, /**< Client did not yet send \c hello. */ ACTIVE, /**< Client sent \c hello, but not yet \c bye. */ GONE /**< Client sent \c bye. */ } ClientState; /** The structure representing a client in the server. */ typedef struct Client { char *name; ClientState state; int sock; int backlight; int heartbeat; LinkedList *messages; /**< Messages that the client sent. */ LinkedList *screenlist; /**< List of client's screens. */ void* menu; /**< Menu hierarchy, if any */ } Client; #endif #ifndef INC_TYPES_ONLY #ifndef CLIENT_H_FNCS #define CLIENT_H_FNCS #define INC_TYPES_ONLY 1 #include "screen.h" #undef INC_TYPES_ONLY /* When a new client connects, set up a new client data struct */ Client *client_create(int sock); /* Destroys the client data */ int client_destroy(Client *c); /* Close the socket */ void client_close_sock(Client *c); /* Add message to the client's queue...*/ int client_add_message(Client *c, char *message); /* Get message from queue */ char *client_get_message(Client *c); /* Find a named screen for the client */ Screen *client_find_screen(Client *c, char *id); int client_add_screen(Client *c, Screen *s); int client_remove_screen(Client *c, Screen *s); int client_screen_count(Client *c); #endif #endif lcdproc-0.5.9/server/render.h0000644000175100017510000000201612505300405013025 00000000000000/** \file server/render.h */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven */ #ifndef RENDER_H #define RENDER_H #define HEARTBEAT_OFF 0 #define HEARTBEAT_ON 1 #define HEARTBEAT_OPEN 2 #define BACKLIGHT_OFF 0 #define BACKLIGHT_ON 1 #define BACKLIGHT_OPEN 2 #define BACKLIGHT_BLINK 0x100 #define BACKLIGHT_FLASH 0x200 #define CURSOR_OFF 0 #define CURSOR_DEFAULT_ON 1 #define CURSOR_BLOCK 4 #define CURSOR_UNDER 5 #define TITLESPEED_NO 0 /* needs to be (TITLESPEED_MIN - 1) */ #define TITLESPEED_MIN 1 #define TITLESPEED_MAX 10 extern int heartbeat; extern int backlight; extern int titlespeed; extern int output_state; /* Render the given screen. */ int render_screen(Screen *s, long timer); /* Display a short message, which must be shorter than 16 chars, in a corner */ int server_msg(const char *text, int expire); #endif lcdproc-0.5.9/server/menu.h0000644000175100017510000000713512505300405012521 00000000000000/** \file server/menu.h * Defines all the menu data and actions. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2004, F5 Networks, Inc. - IP-address input * 2005, Peter Marschall - error checks, ... */ #ifndef MENU_H #define MENU_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STDBOOL_H # include #endif #include "shared/defines.h" #include "shared/LL.h" #include "menuitem.h" /** A Menu is a MenuItem too. * This definition is only for better understanding of this code. */ typedef MenuItem Menu; /** Creates a new menu. */ Menu *menu_create(char *id, MenuEventFunc(*event_func), char *text, Client *client); /** Deletes menu from memory. * Destructors will be called for all subitems. * DO NOT CALL THIS FUNCTION, CALL menuitem_destroy INSTEAD ! */ void menu_destroy(Menu *menu); /** Adds an item to the menu */ void menu_add_item(Menu *menu, MenuItem *item); /** Removes an item from the menu (does not destroy it) */ void menu_remove_item(Menu *menu, MenuItem *item); /** Destroys and removes all items from the menu */ void menu_destroy_all_items(Menu *menu); /** Enumeration function. * Retrieves the first item from the list of items in the menu. */ static inline MenuItem *menu_getfirst_item(Menu *menu) { return (MenuItem*) ((menu != NULL) ? LL_GetFirst(menu->data.menu.contents) : NULL); } /** Enumeration function. * Retrieves the next item from the list of items in the menu. * No other menu calls should be made between menu_first_item() and * this function, to keep the list-cursor where it is. */ static inline MenuItem *menu_getnext_item(Menu *menu) { return (MenuItem*) ((menu != NULL) ? LL_GetNext(menu->data.menu.contents) : NULL); } /** Retrieves the current (non-hidden) item from the list of items in the * menu. */ MenuItem *menu_get_current_item(Menu *menu); /** Finds an item in the menu by the given id. */ MenuItem *menu_find_item(Menu *menu, char *id, bool recursive); /** sets the association member of a Menu. */ void menu_set_association(Menu *menu, void *assoc); /** Resets it to initial state. * DO NOT CALL THIS FUNCTION, CALL menuitem_reset_screen INSTEAD ! */ void menu_reset(Menu *menu); /** Builds the selected menuitem on screen using widgets. * DO NOT CALL THIS FUNCTION, CALL menuitem_rebuild_screen INSTEAD ! */ void menu_build_screen(Menu *menu, Screen *s); /** Updates the widgets of the selected menuitem * DO NOT CALL THIS FUNCTION, CALL menuitem_update_screen INSTEAD ! */ void menu_update_screen(Menu *menu, Screen *s); /** * For predecessor-Check: returns selected subitem of menu if this subitem * has no own screen (action, checkbox, ...) and this subitem has a * predecessor and menu otherwise. * * @return NULL on error. */ MenuItem *menu_get_item_for_predecessor_check(Menu *menu); /** * For successor-Check: returns selected subitem of menu if * this subitem has no own screen (action, checkbox, ...) or menu * otherwise. * * @return NULL on error. */ MenuItem *menu_get_item_for_successor_check(Menu *menu); /** Does something with the given input. * key is only used if token is MENUTOKEN_OTHER. * DO NOT CALL THIS FUNCTION, CALL menuitem_process_input INSTEAD ! */ MenuResult menu_process_input(Menu *menu, MenuToken token, const char *key, unsigned int keymask); /** positions current item pointer on subitem item_id. */ void menu_select_subitem(Menu *menu, char *item_id); #endif lcdproc-0.5.9/server/sock.c0000644000175100017510000003133712505300405012510 00000000000000/** \file server/sock.c * This file contains all the sockets code used by the server. This contains * the code called upon by main() to initialize the listening socket, as well * as code to deal with sending messages to clients, maintaining connections, * accepting new connections, closing dead connections (or connections * associated with dying/exiting clients), etc. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2004, F5 Networks, Inc. - IP-address input * 2005, Peter Marschall - error checks, ... * 2009, Markus Dolze - input ring buffer */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "shared/report.h" #include "shared/sring.h" #include "shared/defines.h" #include "clients.h" #include "sock.h" /****************************************************************************/ static fd_set active_fd_set, read_fd_set; static int listening_fd; /* For efficiency we maintain a list of open sockets. Nodes in this list * are obtained from a pre-allocated pool - this removes heap operations * from the polling loop. A list of open sockets is also required under WINSOCK * as sockets can be arbitrary values instead of low value integers. */ static LinkedList* openSocketList = NULL; static LinkedList* freeClientSocketList = NULL; /* ring buffer for incoming messages */ static sring_buffer *messageRing; /** Mapping between socket and associated client */ typedef struct _ClientSocketMap { int socket; /**< Socket for the client */ Client *client; /**< Pointer to client representation */ } ClientSocketMap; /* The memory referenced from \c openSocketList and \c freeSocketList * is obtained from the freeClientSocketPool array. */ ClientSocketMap *freeClientSocketPool; /* Length of longest transmission allowed at once...*/ #define MAXMSG 8192 /**** Internal function declarations ****************************************/ static int sock_read_from_client(ClientSocketMap *clientSocketMap); static void sock_destroy_socket(void); /** Initialize sockets. * Prepare server socket, and initialize socket management structures. * \param bind_addr Hostname / IP address to bind to. * \param bind_port Port to bind to. * \retval <0 error * \retval 0 success */ int sock_init(char* bind_addr, int bind_port) { int i; debug(RPT_DEBUG, "%s(bind_addr=\"%s\", port=%d)", __FUNCTION__, bind_addr, bind_port); /* Create the socket and set it up to accept connections. */ listening_fd = sock_create_inet_socket(bind_addr, bind_port); if (listening_fd < 0) { report(RPT_ERR, "%s: error creating socket - %s", __FUNCTION__, sock_geterror()); return -1; } /* Create the socket -> Client mapping pool */ /* How large can FD_SETSIZE be? Even if it is ~2000 this only uses a few kilobytes of memory. Let's trade size for speed! */ freeClientSocketPool = (ClientSocketMap *) calloc(FD_SETSIZE, sizeof(ClientSocketMap)); if (freeClientSocketPool == NULL) { report(RPT_ERR, "%s: Error allocating client sockets.", __FUNCTION__); return -1; } freeClientSocketList = LL_new(); if (freeClientSocketList == NULL) { report(RPT_ERR, "%s: error allocating free socket list.", __FUNCTION__); return -1; } for (i = 0; i < FD_SETSIZE; ++i) { LL_AddNode(freeClientSocketList, (void*) &freeClientSocketPool[i]); } /* Create and initialize the open socket list with the server socket */ openSocketList = LL_new(); if (openSocketList == NULL) { report(RPT_ERR, "%s: error allocating open socket list.", __FUNCTION__); return -1; } else { ClientSocketMap *entry; entry = (ClientSocketMap*) LL_Pop(freeClientSocketList); entry->socket = listening_fd; entry->client = NULL; LL_AddNode(openSocketList, (void*) entry); } if ((messageRing = sring_create(MAXMSG)) == NULL) { report(RPT_ERR, "%s: error allocating receive buffer.", __FUNCTION__); return -1; } return 0; } /** Cleanup socket management structures. * \retval <0 error * \retval 0 success */ int sock_shutdown(void) { int retVal = 0; debug(RPT_DEBUG, "%s()", __FUNCTION__); /*ClientSocketMap* clientIt;*/ /* delete all clients */ /* This should be done by calling clients_shutdown */ /* LL_Rewind(openSocketList); for (clientIt = (ClientSocketMap*) LL_Get(openSocketList); clientIt; clientIt = LL_GetNext(openSocketList)) { if (clientIt->client) { */ /* destroying a client also closes its socket */ /* client_destroy(clientIt->client); } } LL_Destroy(openSocketList); */ close(listening_fd); LL_Destroy(freeClientSocketList); free(freeClientSocketPool); sring_destroy(messageRing); return retVal; } /** Create an INET socket, bind to it and listen on it. * \param addr Hostname / IP address to bind to. * \param port Port to bind to. * \retval <0 error * \retval 0 success */ int sock_create_inet_socket(char *addr, unsigned int port) { struct sockaddr_in name; int sock; int sockopt = 1; debug(RPT_DEBUG, "%s(addr=\"%s\", port=%i)", __FUNCTION__, addr, port); /* Create the socket. */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { report(RPT_ERR, "%s: cannot create socket - %s", __FUNCTION__, sock_geterror()); return -1; } /* Set the socket so we can re-use it*/ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, sizeof(sockopt)) < 0) { report(RPT_ERR, "%s: error setting socket option SO_REUSEADDR - %s", __FUNCTION__, sock_geterror()); return -1; } /* Give the socket a name. */ memset(&name, 0, sizeof(name)); name.sin_family = AF_INET; name.sin_port = htons(port); inet_aton(addr, &name.sin_addr); if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { report(RPT_ERR, "%s: cannot bind to port %d at address %s - %s", __FUNCTION__, port, addr, sock_geterror()); return -1; } if (listen(sock, 1) < 0) { report(RPT_ERR, "%s: error in attempting to listen to port " "%d at %s - %s", __FUNCTION__, port, addr, sock_geterror()); return -1; } report(RPT_NOTICE, "Listening for queries on %s:%d", addr, port); /* Initialize the set of active sockets. */ FD_ZERO(&active_fd_set); FD_SET(sock, &active_fd_set); return sock; } /** Service all clients with pending input. * \retval <0 error * \retval 0 success */ int sock_poll_clients(void) { struct timeval t; ClientSocketMap* clientSocket; debug(RPT_DEBUG, "%s()", __FUNCTION__); t.tv_sec = 0; t.tv_usec = 0; /* Block until input arrives on one or more active sockets. */ read_fd_set = active_fd_set; if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0) { report(RPT_ERR, "%s: Select error - %s", __FUNCTION__, sock_geterror()); return -1; } /* Service all the sockets with input pending. */ LL_Rewind(openSocketList); for (clientSocket = (ClientSocketMap *) LL_Get(openSocketList); clientSocket != NULL; clientSocket = LL_GetNext(openSocketList)) { if (FD_ISSET(clientSocket->socket, &read_fd_set)) { if (clientSocket->socket == listening_fd) { /* Connection request on original socket. */ Client *c; int new_sock; struct sockaddr_in clientname; socklen_t size = sizeof(clientname); new_sock = accept(listening_fd, (struct sockaddr *) &clientname, &size); if (new_sock < 0) { report(RPT_ERR, "%s: Accept error - %s", __FUNCTION__, sock_geterror()); return -1; } report(RPT_NOTICE, "Connect from host %s:%hu on socket %i", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_sock); FD_SET(new_sock, &active_fd_set); fcntl(new_sock, F_SETFL, O_NONBLOCK); /* Create new client */ if ((c = client_create(new_sock)) == NULL) { report(RPT_ERR, "%s: Error creating client on socket %i - %s", __FUNCTION__, clientSocket->socket, sock_geterror()); return -1; } else { /* add new_sock */ ClientSocketMap *newClientSocket; newClientSocket = (ClientSocketMap *) LL_Pop(freeClientSocketList); if (newClientSocket != NULL) { newClientSocket->socket = new_sock; newClientSocket->client = c; LL_InsertNode(openSocketList, (void *) newClientSocket); /* advance past the new node - check it on the next pass */ LL_Next(openSocketList); } else { report(RPT_ERR, "%s: Error - free client socket list exhausted - %d clients.", __FUNCTION__, FD_SETSIZE); return -1; } } if (clients_add_client(c) == NULL) { report(RPT_ERR, "%s: Could not add client on socket %i", __FUNCTION__, clientSocket->socket); return -1; } } else { /* Data arriving on an already-connected socket. */ int err = 0; debug(RPT_DEBUG, "%s: reading...", __FUNCTION__); err = sock_read_from_client(clientSocket); debug(RPT_DEBUG, "%s: ...done", __FUNCTION__); if (err < 0) sock_destroy_socket(); } } } return 0; } /** Read from a client's socket and store the messages in the client for further parsing. * \retval <0 error * \retval 0 success */ static int sock_read_from_client(ClientSocketMap *clientSocketMap) { char buffer[MAXMSG]; int nbytes; debug(RPT_DEBUG, "%s()", __FUNCTION__); errno = 0; nbytes = sock_recv(clientSocketMap->socket, buffer, MAXMSG); while (nbytes > 0) { /* Data available */ int fr; char *str; debug(RPT_DEBUG, "%s: received %4d bytes", __FUNCTION__, nbytes); /* Append to ring buffer */ sring_write(messageRing, buffer, nbytes); /* Process all available message in ring buffer */ do { str = sring_read_string(messageRing); if (clientSocketMap->client) { client_add_message(clientSocketMap->client, str); } else { report(RPT_DEBUG, "%s: Can't find client %d", __FUNCTION__, clientSocketMap->socket); } } while (str != NULL); /* Read again, but only as much as space is left */ fr = sring_getMaxWrite(messageRing); if (fr == 0) report(RPT_WARNING, "%s: Message buffer full", __FUNCTION__); nbytes = sock_recv(clientSocketMap->socket, buffer, min(MAXMSG, fr)); } if (sring_getMaxRead(messageRing) > 0) { report(RPT_WARNING, "%s: left over bytes in message buffer", __FUNCTION__); sring_clear(messageRing); } if (nbytes < 0 && errno == EAGAIN) return 0; /* No data is not an error */ return -1; /* EOF */ } /* comparison function to find a ClientsocketMap entry by client */ int byClient(void *csm, void *client) { return (((ClientSocketMap *) csm)->client == (Client *) client) ? 0 : -1; } /** Close an open socket for a given client. * \param client Client whose socket shall be closed. * \retval <0 error * \retval 0 success. */ int sock_destroy_client_socket(Client *client) { ClientSocketMap *entry; LL_Rewind(openSocketList); entry = LL_Find(openSocketList, byClient, client); if (entry != NULL) { sock_destroy_socket(); return 0; } return -1; } /** Close the socket the openSocketList's \c current pointer points to. */ static void sock_destroy_socket(void) { ClientSocketMap *entry = LL_Get(openSocketList); if (entry != NULL) { if (entry->client != NULL) { report(RPT_NOTICE, "Client on socket %i disconnected", entry->socket); client_destroy(entry->client); clients_remove_client(entry->client, PREV); entry->client = NULL; } else { report(RPT_ERR, "%s: Can't find client of socket %i", __FUNCTION__, entry->socket); } /* close socket and remove it from select()'s mask of active sockets */ FD_CLR(entry->socket, &active_fd_set); close(entry->socket); /* re-add socket to the free socket pool */ entry = (ClientSocketMap *) LL_DeleteNode(openSocketList, PREV); LL_Push(freeClientSocketList, (void*) entry); } } /* return 1 if addr is valid IPv4 */ int verify_ipv4(const char *addr) { int result = -1; if (addr != NULL) { struct in_addr a; /* inet_pton returns positive value if it worked */ result = inet_pton(AF_INET, addr, &a); } return (result > 0) ? 1 : 0; } /* return 1 if addr is valid IPv6 */ int verify_ipv6(const char *addr) { int result = 0; if (addr != NULL) { struct in6_addr a; /* inet_pton returns positive value if it worked */ result = inet_pton(AF_INET6, addr, &a); } return (result > 0) ? 1 : 0; } lcdproc-0.5.9/server/menuitem.h0000644000175100017510000002731513076226136013416 00000000000000/** \file server/menuitem.h * Defines all the menuitem data and actions. * * There are a few different menuitems: * - action * - checkbox (on/off and optionally open) * - slider (the user can increase/decrease a value) * - numeric input * - alphanumeric input (in short: alpha) * - menu (a menu is a menuitem itself too) * * The slider, numeric & string input and menu have their own screen, * that comes to front when the items are selected. * One menuitem is in a different file: Menu data is in menu.h. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2004, F5 Networks, Inc. - IP-address input * 2005, Peter Marschall - error checks, ... */ #ifndef MENUITEM_H #define MENUITEM_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STDBOOL_H # include #endif #include "shared/defines.h" #include "shared/LL.h" extern bool menu_permissive_goto; /* Flag from the configuration file */ /********************************************************************* * Data definitions of the menustuff */ /** These values are used in the function tables in menuitem.c ! */ typedef enum MenuItemType { MENUITEM_INVALID = -1, MENUITEM_MENU = 0, MENUITEM_ACTION = 1, MENUITEM_CHECKBOX = 2, MENUITEM_RING = 3, MENUITEM_SLIDER = 4, MENUITEM_NUMERIC = 5, MENUITEM_ALPHA = 6, MENUITEM_IP = 7, NUM_ITEMTYPES = 8 } MenuItemType; typedef enum CheckboxValue { CHECKBOX_OFF = 0, CHECKBOX_ON, CHECKBOX_GRAY } CheckboxValue; /** Recognized input token codes: they need to be bit values */ typedef enum MenuToken { MENUTOKEN_NONE = 0x0000, /**< no key */ MENUTOKEN_MENU = 0x0001, /**< MenuKey */ MENUTOKEN_ENTER = 0x0002, /**< EnterKey */ MENUTOKEN_UP = 0x0004, /**< UpKey */ MENUTOKEN_DOWN = 0x0008, /**< DownKey */ MENUTOKEN_LEFT = 0x0010, /**< LeftKey */ MENUTOKEN_RIGHT = 0x0020, /**< RightKey */ MENUTOKEN_OTHER = 0x1000 /**< any other key */ } MenuToken; /** Return codes from an input handler */ typedef enum MenuResult { MENURESULT_ERROR = -1, /**< Something has gone wrong */ MENURESULT_NONE = 0, /**< Token handled OK, no extra action */ MENURESULT_ENTER, /**< Token handled OK, enter the selected * menuitem now */ MENURESULT_CLOSE, /**< Token handled OK, close the current * menuitem now */ MENURESULT_QUIT, /**< Token handled OK, close ALL menus now */ MENURESULT_PREDECESSOR, /**< Token handled OK, goto registered * predecessor */ MENURESULT_SUCCESSOR /**< Token handled OK, goto registered * successor */ } MenuResult; /** Events caused by a menuitem */ typedef enum MenuEventType { MENUEVENT_INVALID = -1, /**< Special value for error handling */ MENUEVENT_SELECT = 0, /**< Item has been selected * (action chosen) */ MENUEVENT_UPDATE = 1, /**< Item has been modified * (checkbox, numeric, alphanumeric) */ MENUEVENT_PLUS = 2, /**< Item has been modified in positive direction * (slider moved) */ MENUEVENT_MINUS = 3, /**< Item has been modified in negative direction * (slider moved) */ MENUEVENT_ENTER = 4, /**< Menu has been entered */ MENUEVENT_LEAVE = 5, /**< Menu has been left */ NUM_EVENTTYPES = 6 } MenuEventType; #define MenuEventFunc(f) int (f) (struct MenuItem *item, MenuEventType event) /** I've used a union in the struct below. Why? And why not for Widget? * * There are different types of menuitems. There are also types of widgets. * Menuitems have, just like widgets, different datafields per subtype. * The difference is that menuitems have, unlike widgets _many__different_ * attributes. Widgets share many attributes like x, y, text. * The code would become unreadable if we used the 'widget way', or it would * get large if we define datafields that we use for only one type of * menuitem. (Joris) */ typedef struct MenuItem { MenuItemType type; /**< Type as defined above */ char *id; /**< Internal name for client supplied menus */ char *successor_id; /**< next menuitem after hitting "Enter" on * this one. (Special values are "_quit_", * "_close_", "_none_"). */ char *predecessor_id; /**< next menuitem after hitting "Escape" on * this one. (Special values are "_quit_", * "_close_", "_none_"). */ struct MenuItem *parent; /**< Parent of this menuitem */ MenuEventFunc (*event_func); /**< Defines event_func to be an event function */ char *text; /**< Visible name of the item */ void* client; /**< The owner of this menuitem. */ bool is_hidden; /**< If the item currently should not appear in a menu. */ union data { struct menu { int selector_pos; /**< At what menuitem is the selector (0 for first) */ int scroll; /**< How much has the menu been scrolled down */ void *association; /**< To associate an object with this menu */ LinkedList *contents; /**< What's in this menu */ } menu; struct action { /* nothing */ } action; struct checkbox { bool allow_gray; /**< Is CHECKBOX_GRAY allowed ? */ CheckboxValue value; /**< Current value */ } checkbox; struct ring { LinkedList *strings; /**< The selectable strings */ short value; /**< Current index */ } ring; struct slider { char *mintext; /**< Text at minimal value */ char *maxtext; /**< Text at minimal value */ int minvalue; int maxvalue; int stepsize; int value; /**< Current value */ } slider; struct numeric { int maxvalue; int minvalue; //short allowed_decimals; /**< Number of numbers behind dot */ int value; /**< Current value */ char *edit_str; /**< Value while being edited */ short edit_pos; /**< Position while editing */ short edit_offs; /**< Offset while editing */ short error_code; } numeric; struct alpha { char password_char; /**< For passwords */ short minlength; short maxlength; bool allow_caps; /**< Caps allowed ? */ bool allow_noncaps; /**< Non-caps allowed ? */ bool allow_numbers; /**< Numbers allowed ? */ char *allowed_extra; /**< Allowed extra characters */ char *value; /**< Current value */ char *edit_str; /**< Value while being edited */ short edit_pos; /**< Position while editing */ short edit_offs; /**< Offset while editing */ short error_code; } alpha; struct ip { char *value; /**< Current value */ char *edit_str; /**< Value while being edited */ short maxlength; bool v6; /**< true if editing ipv6 addr */ short edit_pos; /**< Position while editing */ short edit_offs; /**< Offset while editing */ short error_code; } ip; } data; } MenuItem; /********************************************************************* * Functions to use the menustuff */ /** translates a predecessor_id into a MenuResult. */ MenuResult menuitem_predecessor2menuresult(char *predecessor_id, MenuResult default_result); /** translates a successor_id into a MenuResult. */ MenuResult menuitem_successor2menuresult(char *successor_id, MenuResult default_result); MenuItem *menuitem_search(char *menu_id, Client *client); /** YOU SHOULD NOT CALL THIS FUNCTION BUT THE TYPE SPECIFIC ONE INSTEAD */ MenuItem *menuitem_create(MenuItemType type, char *id, MenuEventFunc(*event_func), char *text, Client *client); /* For all constructor functions below the following: * * id: internal name of the item. Never visible. String will be * copied. * event_func: the event function that should be called upon actions on this * item. * text: the displayed text. * * All strings will be copied ! * * Return value: the new item, or NULL on error. * * To create a Menu (which is also an ItemType), call menu_create. * */ /** Creates a an action item (a string only). Generated events: * MENUEVENT_SELECT when user selects the item. */ MenuItem *menuitem_create_action(char *id, MenuEventFunc(*event_func), char *text, Client *client, MenuResult menu_result); /** Creates a checkbox. * Generated events: MENUEVENT_UPDATE when user changes value (immediately). */ MenuItem *menuitem_create_checkbox(char *id, MenuEventFunc(*event_func), char *text, Client *client, bool allow_gray, bool value); /** Creates a ring with the given string, separated by tabs. * value is the (initial) index in the strings. * eg: if strings="abc\\tdef" the value=1 means that "def" is selected. * Generated events: MENUEVENT_UPDATE when user changes value (immediately). */ MenuItem *menuitem_create_ring(char *id, MenuEventFunc(*event_func), char *text, Client *client, char *strings, short value); /** Creates a slider with the given min and max values. * If the display is big enough the mintext and maxtext will be placed * at the end positions of the slider. * You can set the step size. Make it 0 to disable the automatic value chaning, * and update the value yourself. * MENUEVENT_PLUS, MENUEVENT_MINUS when slider is moved (immediately). */ MenuItem *menuitem_create_slider(char *id, MenuEventFunc(*event_func), char *text, Client *client, char *mintext, char *maxtext, int minvalue, int maxvalue, int stepsize, int value); /** Creates a numeric value box. * Value can range from minvalue to maxvalue. * MENUEVENT_UPDATE when user finishes the value (no immediate update). */ MenuItem *menuitem_create_numeric(char *id, MenuEventFunc(*event_func), char *text, Client *client, int minvalue, int maxvalue, int value); /** Creates a string value box. * Value should have given minimal and maximal length. You can set whether * caps, non-caps and numbers are allowed. Also you can alow other characters. * If password char is non-zero, you will only see this char, not the actual * input. * MENUEVENT_UPDATE when user finishes the value (no immediate update). */ MenuItem *menuitem_create_alpha(char *id, MenuEventFunc(*event_func), char *text, Client *client, char password_char, short minlength, short maxlength, bool allow_caps, bool allow_noncaps, bool allow_numbers, char *allowed_extra, char *value); /** Creates an ip value box. can be either v4 or v6 * MENUEVENT_UPDATE when user finishes the value (no immediate update). */ MenuItem *menuitem_create_ip(char *id, MenuEventFunc(*event_func), char *text, Client *client, bool v6, char *value); /** Deletes item from memory. * All allocated extra data (like strings) will be freed. */ void menuitem_destroy(MenuItem *item); /** Resets the item to the initial state. * You should call menuitem_update after this to see the effects. * This call is useless on items that have immediate effect, like a slider. * Those items do not keep temporary data. */ void menuitem_reset(MenuItem *item); /** (Re)builds the selected menuitem on screen using widgets. * Should be re-called if menuitem data has been changed. * There are a few (logical) exceptions to this: * - the values * - the menu scroll and menu index */ void menuitem_rebuild_screen(MenuItem *item, Screen *s); /** Updates the widgets of the selected menuitem * Fills all widget attributes with the corrrect values. */ void menuitem_update_screen(MenuItem *item, Screen *s); /** Does something with the given input. * key is only used if token is MENUTOKEN_OTHER. */ MenuResult menuitem_process_input(MenuItem *item, MenuToken token, const char *key, unsigned int keymask); /** returns the Client that owns the MenuItem. item must not be null */ Client *menuitem_get_client(MenuItem *item); /** Converts a tab-separated list to a LinkedList. */ LinkedList *tablist2linkedlist(char *strings); MenuItemType menuitem_typename_to_type(char *name); char *menuitem_type_to_typename(MenuItemType type); MenuEventType menuitem_eventtypename_to_eventtype(char *name); char *menuitem_eventtype_to_eventtypename(MenuEventType type); #endif lcdproc-0.5.9/server/commands/0000755000175100017510000000000013121562645013272 500000000000000lcdproc-0.5.9/server/commands/client_commands.h0000644000175100017510000000130612505300405016507 00000000000000/** \file server/commands/client_commands.h */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn */ #ifndef COMMANDS_CLIENT_H #define COMMANDS_CLIENT_H int hello_func(Client *c, int argc, char **argv); int bye_func(Client *c, int argc, char **argv); int client_set_func(Client *c, int argc, char **argv); int client_add_key_func(Client *c, int argc, char **argv); int client_del_key_func(Client *c, int argc, char **argv); int backlight_func(Client *c, int argc, char **argv); #endif lcdproc-0.5.9/server/commands/server_commands.c0000644000175100017510000001022212505300405016527 00000000000000/** \file server/commands/server_commands.c * Implements handlers for client commands concerning the server settings. * * This contains definitions for all the functions which clients can run. * The functions here are to be called only from parse.c's interpreter. * * The client's available function set is defined here, as is the syntax * for each command. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn */ #include #include #include #include #include #include #include "shared/report.h" #include "shared/sockets.h" #include "client.h" #include "render.h" #include "server_commands.h" #define ALL_OUTPUTS_ON -1 #define ALL_OUTPUTS_OFF 0 /** * Sets the state of the output port (such as on MtxOrb LCDs) * *\verbatim * Usage: output *\endverbatim */ int output_func(Client *c, int argc, char **argv) { if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: output {on|off|}\n"); return 0; } if (0 == strcmp(argv[1], "on")) output_state = ALL_OUTPUTS_ON; else if (0 == strcmp(argv[1], "off")) output_state = ALL_OUTPUTS_OFF; else { long out; char *endptr; /* Note that there is no valid range set for * output_state; thus a value in the 12 digits * is not considered out of range. */ /* set errno to be able to detect errors in strtol() */ errno = 0; out = strtol(argv[1], &endptr, 0); if (errno) { sock_printf_error(c->sock, "number argument: %s\n", strerror(errno)); return 0; } else if ((*argv[1] != '\0') && (*endptr == '\0')) { output_state = out; } else { sock_send_error(c->sock, "invalid parameter...\n"); return 0; } } sock_send_string(c->sock, "success\n"); /* Makes sense to me to set the output immediately; * however, the outputs are currently set in * draw_screen(screen *s, int timer) * Whatever for? */ /* drivers_output(output_state); */ report(RPT_NOTICE, "output states changed"); return 0; } /** * The sleep_func was intended to make the server sleep for some seconds. * This function is currently ignored as making the server sleep actually * stalls it and disrupts other clients. * *\verbatim * Usage: sleep *\endverbatim */ int sleep_func(Client *c, int argc, char **argv) { int secs; long out; char *endptr; #define MAX_SECS 60 #define MIN_SECS 1 if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: sleep \n"); return 0; } /* set errno to be able to detect errors in strtol() */ errno = 0; out = strtol(argv[1], &endptr, 0); /* From the man page for strtol(3) * * In particular, if *nptr is not `\0' but **endptr is * `\0' on return, the entire string is valid. * * In this case, argv[1] is *nptr, and &endptr is **endptr. */ if (errno) { sock_printf_error(c->sock, "number argument: %s\n", strerror(errno)); return 0; } else if ((*argv[1] != '\0') && (*endptr == '\0')) { /* limit seconds to range: MIN_SECS - MAX_SECS */ out = (out > MAX_SECS) ? MAX_SECS : out; out = (out < MIN_SECS) ? MIN_SECS : out; secs = out; } else { sock_send_error(c->sock, "invalid parameter...\n"); return 0; } /* Repeat until no more remains - should normally be zero * on exit the first time...*/ sock_printf(c->sock, "sleeping %d seconds\n", secs); /* whoops.... if this takes place as planned, ALL screens * will "freeze" for the alloted time... * * while ((secs = sleep(secs)) > 0) */ ; sock_send_error(c->sock, "ignored (not fully implemented)\n"); return 0; } /** * Does nothing, returns "noop complete" message. * * This is useful for shell scripts or programs that want to talk * with LCDproc and not get deadlocked. Send a noop after each * command and look for the "noop complete" message. */ int noop_func(Client *c, int argc, char **argv) { if (c->state != ACTIVE) return 1; sock_send_string(c->sock, "noop complete\n"); return 0; } lcdproc-0.5.9/server/commands/server_commands.h0000644000175100017510000000117512505300405016543 00000000000000/** \file server/commands/server_commands.h */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn */ #ifndef COMMANDS_SERVER_H #define COMMANDS_SERVER_H int output_func(Client *c, int argc, char **argv); int test_func_func(Client *c, int argc, char **argv); int noop_func(Client *c, int argc, char **argv); int info_func(Client *c, int argc, char **argv); int sleep_func(Client *c, int argc, char **argv); #endif lcdproc-0.5.9/server/commands/command_list.c0000644000175100017510000000422713121560062016023 00000000000000/** \file server/commands/command_list.c * Implements the dispatcher for handlers dealing with the client commands. * * This contains definitions for all the functions which clients can run. * The functions here are to be called only from parse.c's interpreter. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2003, Joris Robijn */ #include #include #include "command_list.h" #include "server_commands.h" #include "client_commands.h" #include "screen_commands.h" #include "widget_commands.h" #include "menu_commands.h" static client_function commands[] = { { "test_func", test_func_func }, { "hello", hello_func }, { "client_set", client_set_func }, { "client_add_key", client_add_key_func }, { "client_del_key", client_del_key_func }, { "screen_add", screen_add_func }, { "screen_del", screen_del_func }, { "screen_set", screen_set_func }, { "widget_add", widget_add_func }, { "widget_del", widget_del_func }, { "widget_set", widget_set_func }, { "menu_add_item", menu_add_item_func }, { "menu_del_item", menu_del_item_func }, { "menu_set_item", menu_set_item_func }, { "menu_goto", menu_goto_func }, { "menu_set_main", menu_set_main_func }, /* Misc stuff...*/ { "backlight", backlight_func }, { "output", output_func }, { "noop", noop_func }, { "info", info_func }, { "sleep", sleep_func }, { "bye", bye_func }, { NULL, NULL}, }; /** * Looks up a function for a command sent by the client. * \param cmd Command to look up as string. * \return Pointer to the implementing function. */ CommandFunc get_command_function(char *cmd) { int i; if (cmd == NULL) return NULL; for (i = 0; commands[i].keyword != NULL; i++) { if (0 == strcmp(cmd, commands[i].keyword)) return commands[i].function; } return NULL; } lcdproc-0.5.9/server/commands/client_commands.c0000644000175100017510000001415112505300405016504 00000000000000/** \file server/commands/client_commands.c * Implements handlers for general client commands. * * This contains definitions for all the functions which clients can run. * The functions here are to be called only from parse.c's interpreter. * * The client's available function set is defined here, as is the syntax * for each command. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn */ #include #include #include #include #include #include #include "shared/report.h" #include "shared/sockets.h" #include "drivers.h" #include "client.h" #include "render.h" #include "input.h" #include "client_commands.h" /** * Debugging only.. prints out a list of arguments it receives */ int test_func_func(Client *c, int argc, char **argv) { int i; for (i = 0; i < argc; i++) { report(RPT_INFO, "%s: %i -> %s", __FUNCTION__, i, argv[i]); sock_printf(c->sock, "%s: %i -> %s\n", __FUNCTION__, i, argv[i]); } return 0; } /** * The client must say "hello" before doing anything else. * * It sends back a string of info about the server to the client. * *\verbatim * Usage: hello *\endverbatim * * \todo Give \em real info about the server/lcd */ int hello_func(Client *c, int argc, char **argv) { if (argc > 1) { sock_send_error(c->sock, "extra parameters ignored\n"); } debug(RPT_INFO, "Hello!"); sock_printf(c->sock, "connect LCDproc %s protocol %s lcd wid %i hgt %i cellwid %i cellhgt %i\n", VERSION, PROTOCOL_VERSION, display_props->width, display_props->height, display_props->cellwidth, display_props->cellheight); /* make note that client has sent hello */ c->state = ACTIVE; return 0; } /** * The client should say "bye" before disconnecting * * The function does not respond to the client: it simply cuts connection. * *\verbatim * Usage: bye *\endverbatim */ int bye_func(Client *c, int argc, char **argv) { if (c != NULL) { debug(RPT_INFO, "Bye, %s!", (c->name != NULL) ? c->name : "unknown client"); c->state = GONE; //sock_send_error(c->sock, "\"bye\" is currently ignored\n"); } return 0; } /** * Sets info about the client, such as its name * *\verbatim * Usage: client_set -name *\endverbatim */ int client_set_func(Client *c, int argc, char **argv) { int i; if (c->state != ACTIVE) return 1; if (argc != 3) { sock_send_error(c->sock, "Usage: client_set -name \n"); return 0; } i = 1; do { char *p = argv[i]; /* ignore leading '-' in options: we allow both forms */ if (*p == '-') p++; /* Handle the "name" option */ if (strcmp(p, "name") == 0) { i++; if (argv[i] == '\0') { sock_printf_error(c->sock, "internal error: no parameter #%d\n", i); continue; } debug(RPT_DEBUG, "client_set: name=\"%s\"", argv[i]); /* set the name...*/ if (c->name != NULL) free(c->name); if ((c->name = strdup(argv[i])) == NULL) { sock_send_error(c->sock, "error allocating memory!\n"); } else { sock_send_string(c->sock, "success\n"); i++; /* bypass argument (name string)*/ } } else { sock_printf_error(c->sock, "invalid parameter (%s)\n", p); } } while (++i < argc); return 0; } /** * Tells the server the client would like to accept keypresses * of a particular type * *\verbatim * Usage: client_add_key [-exclusively|-shared] {}+ *\endverbatim */ int client_add_key_func(Client *c, int argc, char **argv) { int exclusively = 0; int argnr; if (c->state != ACTIVE) return 1; if (argc < 2) { sock_send_error(c->sock, "Usage: client_add_key [-exclusively|-shared] {}+\n"); return 0; } argnr = 1; if (argv[argnr][0] == '-') { if (strcmp( argv[argnr], "-shared") == 0) { exclusively = 0; } else if(strcmp(argv[argnr], "-exclusively") == 0) { exclusively = 1; } else { sock_printf_error(c->sock, "Invalid option: %s\n", argv[argnr]); } argnr++; } for ( ; argnr < argc; argnr++) { if (input_reserve_key(argv[argnr], exclusively, c) < 0) { sock_printf_error(c->sock, "Could not reserve key \"%s\"\n", argv[argnr]); } } sock_send_string(c->sock, "success\n"); return 0; } /** * Tells the server the client would NOT like to accept keypresses * of a particular type * *\verbatim * Usage: client_del_key {}+ *\endverbatim */ int client_del_key_func(Client *c, int argc, char **argv) { int argnr; if (c->state != ACTIVE) return 1; if (argc < 2) { sock_send_error(c->sock, "Usage: client_del_key {}+\n"); return 0; } for (argnr = 1; argnr < argc; argnr++) { input_release_key(argv[argnr], c); } sock_send_string(c->sock, "success\n"); return 0; } /** * Toggles the backlight, if enabled. * *\verbatim * Usage: backlight {on|off|toggle|blink|flash} *\endverbatim */ int backlight_func(Client *c, int argc, char **argv) { if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: backlight {on|off|toggle|blink|flash}\n"); return 0; } debug(RPT_DEBUG, "backlight(%s)", argv[1]); //backlight = (backlight && 1); /* only preserves ON/OFF bit*/ if (strcmp ("on", argv[1]) == 0) { c->backlight = BACKLIGHT_ON; } else if (strcmp ("off", argv[1]) == 0) { c->backlight = BACKLIGHT_OFF; } else if (strcmp ("toggle", argv[1]) == 0) { if (c->backlight == BACKLIGHT_ON) c->backlight = BACKLIGHT_OFF; else if (c->backlight == BACKLIGHT_OFF) c->backlight = BACKLIGHT_ON; } else if (strcmp ("blink", argv[1]) == 0) { c->backlight |= BACKLIGHT_BLINK; } else if (strcmp ("flash", argv[1]) == 0) { c->backlight |= BACKLIGHT_FLASH; } sock_send_string(c->sock, "success\n"); return 0; } /** * Sends back information about the loaded drivers. * *\verbatim * Usage: info *\endverbatim */ int info_func(Client *c, int argc, char **argv) { if (c->state != ACTIVE) return 1; if (argc > 1) { sock_send_error(c->sock, "Extra arguments ignored...\n"); } sock_printf(c->sock, "%s\n", drivers_get_info()); return 0; } lcdproc-0.5.9/server/commands/command_list.h0000644000175100017510000000156612505300405016031 00000000000000/** \file server/commands/command_list.h * Declares client command dispatcher function. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven */ #ifndef COMMANDS_COMMAND_LIST_H #define COMMANDS_COMMAND_LIST_H #include "client.h" /** * The function list for clients is stored in a table, and the items each * point to a function to call, defined below. */ typedef int (*CommandFunc) (Client *c, int argc, char **argv); /** Defines an entry in the command table */ typedef struct client_function { char *keyword; /**< Command string in the protocol */ CommandFunc function; /**< Pointer to the associated function */ } client_function; CommandFunc get_command_function(char *cmd); #endif lcdproc-0.5.9/server/commands/Makefile.am0000644000175100017510000000057712505300405015244 00000000000000## Process this file with automake to produce Makefile.in noinst_LIBRARIES = libLCDcommands.a libLCDcommands_a_SOURCES = command_list.c command_list.h client_commands.c client_commands.h menu_commands.c menu_commands.h screen_commands.c screen_commands.h server_commands.c server_commands.h widget_commands.c widget_commands.h AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir)/.. ## EOF lcdproc-0.5.9/server/commands/screen_commands.c0000644000175100017510000002375213121560062016516 00000000000000/** \file server/commands/screen_commands.c * Implements handlers for the client commands concerning screens. * * This contains definitions for all the functions which clients can run. * The functions here are to be called only from parse.c's interpreter. * * The client's available function set is defined here, as is the syntax * for each command. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn */ #include #include #include #include #include #include #include "shared/report.h" #include "shared/sockets.h" #include "client.h" #include "screen.h" #include "render.h" #include "screen_commands.h" /** * Tells the server the client has another screen to offer * *\verbatim * Usage: screen_add *\endverbatim */ int screen_add_func(Client *c, int argc, char **argv) { int err = 0; Screen *s; if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: screen_add \n"); return 0; } debug(RPT_DEBUG, "screen_add: Adding screen %s", argv[1]); s = client_find_screen(c, argv[1]); if (s != NULL) { sock_send_error(c->sock, "Screen already exists\n"); return 0; } s = screen_create(argv[1], c); if (s == NULL) { sock_send_error(c->sock, "failed to create screen\n"); return 0; } err = client_add_screen(c, s); if (err == 0) { sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "failed to add screen\n"); } report(RPT_INFO, "Client on socket %d added added screen \"%s\"", c->sock, s->id); return 0; } /** * The client requests that the server forget about a screen * *\verbatim * Usage: screen_del *\endverbatim */ int screen_del_func(Client *c, int argc, char **argv) { int err = 0; Screen *s; if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: screen_del \n"); return 0; } debug(RPT_DEBUG, "screen_del: Deleting screen %s", argv[1]); s = client_find_screen(c, argv[1]); if (s == NULL) { sock_send_error(c->sock, "Unknown screen id\n"); return 0; } err = client_remove_screen(c, s); if (err == 0) { sock_send_string(c->sock, "success\n"); } else if (err < 0) { sock_send_error(c->sock, "failed to remove screen\n"); } else { sock_send_error(c->sock, "Unknown screen id\n"); } report(RPT_INFO, "Client on socket %d removed screen \"%s\"", c->sock, s->id); screen_destroy(s); return 0; } /** * Configures info about a particular screen, such as its * name, priority, or duration * *\verbatim * Usage: screen_set [-name ] [-wid ] [-hgt ] * [-priority ] [-duration ] [-timeout ] * [-heartbeat ] [-backlight ] * [-cursor ] [-cursor_x ] [-cursor_y ] *\endverbatim */ int screen_set_func(Client *c, int argc, char **argv) { int i; int number; char *id; Screen * s; if (c->state != ACTIVE) return 1; if (argc == 1) { sock_send_error(c->sock, "Usage: screen_set [-name ]" " [-wid ] [-hgt ] [-priority ]" " [-duration ] [-timeout ]" " [-heartbeat ] [-backlight ]" " [-cursor ]" " [-cursor_x ] [-cursor_y ]\n"); return 0; } else if (argc == 2) { sock_send_error(c->sock, "What do you want to set?\n"); return 0; } id = argv[1]; s = client_find_screen(c, id); if (s == NULL) { sock_send_error(c->sock, "Unknown screen id\n"); return 0; } /* Handle the rest of the parameters*/ for (i = 2; i < argc; i++) { char *p = argv[i]; /* ignore leading '-' in options: we allow both forms */ if (*p == '-') p++; /* Handle the "name" parameter*/ if (strcmp(p, "name") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: name=\"%s\"", argv[i]); /* set the name...*/ if (s->name != NULL) free(s->name); s->name = strdup(argv[i]); sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-name requires a parameter\n"); } } /* Handle the "priority" parameter*/ else if (strcmp(p, "priority") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: priority=\"%s\"", argv[i]); /* first try to interpret it as a number */ number = atoi(argv[i]); if (number > 0) { if (number <= 64) number = PRI_FOREGROUND; else if (number < 192) number = PRI_INFO; else number = PRI_BACKGROUND; } else { /* Try if it is a priority class */ number = screen_pri_name_to_pri(argv[i]); } if (number >= 0) { s->priority = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "invalid argument at -priority\n"); } } else { sock_send_error(c->sock, "-priority requires a parameter\n"); } } /* Handle the "duration" parameter*/ else if (strcmp(p, "duration") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: duration=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); if (number > 0) s->duration = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-duration requires a parameter\n"); } } /* Handle the "heartbeat" parameter*/ else if (strcmp(p, "heartbeat") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: heartbeat=\"%s\"", argv[i]); /* set the heartbeat type...*/ if (0 == strcmp(argv[i], "on")) s->heartbeat = HEARTBEAT_ON; else if (0 == strcmp(argv[i], "off")) s->heartbeat = HEARTBEAT_OFF; else if (0 == strcmp(argv[i], "open")) s->heartbeat = HEARTBEAT_OPEN; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-heartbeat requires a parameter\n"); } } /* Handle the "wid" parameter*/ else if (strcmp(p, "wid") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: wid=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); if (number > 0) s->width = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-wid requires a parameter\n"); } } /* Handle the "hgt" parameter*/ else if (strcmp(p, "hgt") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: hgt=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); if (number > 0) s->height = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-hgt requires a parameter\n"); } } /* Handle the "timeout" parameter*/ else if (strcmp(p, "timeout") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: timeout=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); /* Add the timeout value (count of TIME_UNITS) * to struct, TIME_UNIT is 1/8th of a second */ if (number > 0) { s->timeout = number; report(RPT_NOTICE, "Timeout set."); } sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-timeout requires a parameter\n"); } } /* Handle the "backlight" parameter*/ else if (strcmp(p, "backlight") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: backlight=\"%s\"", argv[i]); if (strcmp("on", argv[i]) == 0) s->backlight = BACKLIGHT_ON; else if (strcmp("off", argv[i]) == 0) s->backlight = BACKLIGHT_OFF; else if (strcmp("toggle", argv[i]) == 0) { if (s->backlight == BACKLIGHT_ON) s->backlight = BACKLIGHT_OFF; else if (s-backlight == BACKLIGHT_OFF) s->backlight = BACKLIGHT_ON; } else if (strcmp("blink", argv[i]) == 0) s->backlight |= BACKLIGHT_BLINK; else if (strcmp("flash", argv[i]) == 0) s->backlight |= BACKLIGHT_FLASH; else if (strcmp("open", argv[i]) == 0) s->backlight = BACKLIGHT_OPEN; else sock_send_error(c->sock, "unknown backlight mode\n"); sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-backlight requires a parameter\n"); } } /* Handle the "cursor" parameter */ else if (strcmp(p, "cursor") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: cursor=\"%s\"", argv[i]); /* set the heartbeat type...*/ if (0 == strcmp(argv[i], "off")) s->cursor = CURSOR_OFF; if (0 == strcmp(argv[i], "on")) s->cursor = CURSOR_DEFAULT_ON; if (0 == strcmp(argv[i], "under")) s->cursor = CURSOR_UNDER; if (0 == strcmp(argv[i], "block")) s->cursor = CURSOR_BLOCK; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-cursor requires a parameter\n"); } } /* Handle the "cursor_x" parameter */ else if (strcmp(p, "cursor_x") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: cursor_x=\"%s\"", argv[i]); /* set the position...*/ number = atoi(argv[i]); if (number > 0 && number <= s->width) { s->cursor_x = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "Cursor position outside screen\n"); } } else { sock_send_error(c->sock, "-cursor_x requires a parameter\n"); } } /* Handle the "cursor_y" parameter */ else if (strcmp(p, "cursor_y") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: cursor_y=\"%s\"", argv[i]); /* set the position...*/ number = atoi(argv[i]); if (number > 0 && number <= s->height) { s->cursor_y = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "Cursor position outside screen\n"); } } else { sock_send_error(c->sock, "-cursor_y requires a parameter\n"); } } else sock_send_error(c->sock, "invalid parameter\n"); }/* done checking argv*/ return 0; } lcdproc-0.5.9/server/commands/menu_commands.c0000644000175100017510000006710612505300405016202 00000000000000/** \file server/commands/menu_commands.c * Implements handlers for client commands concerning menus. * * This contains definitions for all the functions which clients can run. * The functions here are to be called only from parse.c's interpreter. * * The client's available function set is defined here, as is the syntax * for each command. */ /* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. * Refer to the COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Selene Scriven * 2002, Joris Robijn * 2004, F5 Networks, Inc. - IP-address input * 2005, Peter Marschall - error checks, ... */ #include #include #include #include #include #include #include #include #include "shared/report.h" #include "shared/sockets.h" #include "client.h" #include "menuitem.h" #include "menu.h" #include "menuscreens.h" #include "menu_commands.h" /* Local functions */ MenuEventFunc(menu_commands_handler); int set_predecessor(MenuItem *item, char *itemid, Client *client); int set_successor(MenuItem *item, char *itemid, Client *client); /** small utility for debug output of command line. */ static char *argv2string(int argc, char **argv) { char *rtn = NULL; unsigned int len; unsigned int i; for (i = len = 0; i < argc; i++) len += strlen(argv[i]) + 1; rtn = malloc(len + 1); if (rtn != NULL) { rtn[0] = '\0'; for (i = 0; i < argc; i++) { strcat(rtn, argv[i]); strcat(rtn, " "); } } return rtn; } /** * Adds an item to a menu. * *\verbatim * Usage: menu_add_item [] {