diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..94c5ae3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.o +*.swp +*~ +/Makefile +/config.h +/config.log +/config.status +/tts +/vers.c +/build +/autom4te.cache +/doconf +/bling_import.pl.old +/queue.h diff --git a/Makefile.in b/Makefile.in index 8ee1584..28dfdb6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,13 +1,25 @@ +# TTS - track your time. +# Copyright (c) 2012-2014 Felicity Tarnell. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely. This software is provided 'as-is', without any express or implied +# warranty. + +.SUFFIXES: .c .o .d .h + VPATH = @top_srcdir@ CC = @CC@ -CPPFLAGS = @CPPFLAGS@ +MAKEDEPEND = @CC@ -M +CPPFLAGS = @CPPFLAGS@ -D_XOPEN_SOURCE_EXTENDED CFLAGS = @CFLAGS@ -I@top_srcdir@ -I@top_builddir@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ INSTALL = @INSTALL@ -OBJS = tts.o +OBJS = tts.o wide.o entry.o ui.o functions.o commands.o bindings.o \ + str.o style.o wcslcpy.o prefix = @prefix@ exec_prefix = @exec_prefix@ @@ -23,8 +35,22 @@ install: .c.o: ${CC} ${CPPFLAGS} ${CFLAGS} -c $< +.c.d: + $(MAKEDEPEND) $(CPPFLAGS) $(CFLAGS) $< -o $@ + vers.c: vers.c.sh configure.ac sh @top_srcdir@/vers.c.sh @top_srcdir@/configure.ac clean: - rm -f tts *.o + rm -f tts ${OBJS} $(OBJS:.o=.d) + +depend: $(OBJS:.o=.d) + sed '/^# Do not remove this line -- make depend needs it/,$$ d' \ + Makefile.new + echo '# Do not remove this line -- make depend needs it' >>Makefile.new + cat *.d >> Makefile.new + mv Makefile.new Makefile + +.PHONY: depend clean install libuv + +# Do not remove this line -- make depend needs it diff --git a/README b/README.md similarity index 62% rename from README rename to README.md index 163e90f..2c7760d 100644 --- a/README +++ b/README.md @@ -1,8 +1,21 @@ TTS - Time-tracking software ============================ -TTS is a simple, text-based (curses) time-tracking application. For more -details, see the website at . +TTS is a simple, text-based (curses) time-tracking application. It allows you +to track the time you spend working by client, project, etc. to allow accurate +invoicing of clients or reporting to a corporate time-tracking system. It +uses a simple text format to store data which can easily be parsed to export +data to another system automatically. Entries can be added in bulk or in real +time using a timer, and invoiced and non-billable entries are tracked. +Entries can optionally be rounded up to a minimum billing increment. + +Screenshot +---------- + +![A screenshot of TTS in use](screenshot.png) + +Installation +------------ TTS has been tested on FreeBSD, NetBSD, Solaris, Cygwin and Linux, with the following caveats: @@ -21,7 +34,8 @@ TTS uses autoconf and can be built as follows: After starting with 'tts', type '?' for help. -### Quick start: +Quick start +----------- * Press 'a' to add a new entry, and enter its name. The timer starts running. * Press space to toggle the timer on and off. @@ -34,6 +48,9 @@ After starting with 'tts', type '?' for help. start the interrupt timer. When you're done with the other thing, press 'r' again to assign the interrupt time to a new entry. -### Contact +Contact +------- -Send questions/comments/bugs/patches to . +To report problems or request features, please use the GitHub issue tracker at +. This requires that you have a GitHub +account. diff --git a/aclocal.m4 b/aclocal.m4 index 33a37ac..83aca16 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -108,7 +108,7 @@ # HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the # library supports the X/Open Enhanced Curses definition. In particular, # the wide-character types attr_t, cchar_t and wint_t, the functions -# wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES +# wattr_set() and wget_wch() and the macros WA_BOLD and _XOPEN_CURSES # are checked. The Ncurses library does NOT conform to this definition, # although NcursesW does. # @@ -228,7 +228,7 @@ AC_DEFUN([AX_WITH_CURSES], [ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; int g = getattrs(stdscr); @@ -259,7 +259,7 @@ AC_DEFUN([AX_WITH_CURSES], [ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; int g = getattrs(stdscr); @@ -290,7 +290,7 @@ AC_DEFUN([AX_WITH_CURSES], [ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; int g = getattrs(stdscr); @@ -443,7 +443,7 @@ AC_DEFUN([AX_WITH_CURSES], [ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; initscr(); diff --git a/bindings.c b/bindings.c new file mode 100644 index 0000000..33f61e7 --- /dev/null +++ b/bindings.c @@ -0,0 +1,194 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include + +#include "bindings.h" +#include "wide.h" +#include "ui.h" + +binding_list_t bindings = TTS_TAILQ_HEAD_INITIALIZER(bindings); + +static tkey_t keys[] = { + { KEY_BREAK, L"" }, + { KEY_DOWN, L"" }, + { KEY_UP, L"" }, + { KEY_LEFT, L"" }, + { KEY_RIGHT, L"" }, + { KEY_HOME, L"" }, + { KEY_BACKSPACE, L"" }, + { 0x7F, L"" }, /* DEL */ + { KEY_F(0), L"" }, + { KEY_F(1), L"" }, + { KEY_F(2), L"" }, + { KEY_F(3), L"" }, + { KEY_F(4), L"" }, + { KEY_F(5), L"" }, + { KEY_F(6), L"" }, + { KEY_F(7), L"" }, + { KEY_F(8), L"" }, + { KEY_F(9), L"" }, + { KEY_F(10), L"" }, + { KEY_F(11), L"" }, + { KEY_F(12), L"" }, + { KEY_F(13), L"" }, + { KEY_F(14), L"" }, + { KEY_F(15), L"" }, + { KEY_F(16), L"" }, + { KEY_F(17), L"" }, + { KEY_F(18), L"" }, + { KEY_F(19), L"" }, + { KEY_F(20), L"" }, + { KEY_F(21), L"" }, + { KEY_F(22), L"" }, + { KEY_F(23), L"" }, + { KEY_F(24), L"" }, + { KEY_NPAGE, L"" }, + { KEY_PPAGE, L"" }, + { '\001', L"" }, + { '\002', L"" }, + { '\003', L"" }, + { '\004', L"" }, + { '\005', L"" }, + { '\006', L"" }, + { '\007', L"" }, + { '\010', L"" }, + { '\011', L"" }, + { '\011', L"" }, + { '\012', L"" }, + { '\013', L"" }, + { '\014', L"" }, + { '\015', L"" }, + { '\016', L"" }, + { '\017', L"" }, + { '\020', L"" }, + { '\021', L"" }, + { '\022', L"" }, + { '\023', L"" }, + { '\024', L"" }, + { '\025', L"" }, + { '\026', L"" }, + { '\027', L"" }, + { '\030', L"" }, + { '\031', L"" }, + { ' ', L"" }, + { KEY_ENTER, L"" }, + { KEY_BACKSPACE, L"" }, + { KEY_DC, L"" } +}; + +/* + * Bind .keyname to run the function .funcname. If a binding for .keyname + * already exists, overwrite it. + * + * If .keyname is a single character, e.g. 'a', it is used as a key name + * directly, rather than being looked up in the key table. + */ +void +bind_key(keyname, funcname, is_macro) + const wchar_t *keyname, *funcname; +{ +tkey_t *key = NULL; +function_t *func; +binding_t *binding; +wint_t code; + + /* Find the key and the function */ + if (wcslen(keyname) > 1) { + if ((key = find_key(keyname)) == NULL) { + errbox(L"Unknown key \"%ls\"", keyname); + return; + } + code = key->ky_code; + } else + code = *keyname; + + if (!is_macro) { + if ((func = find_func(funcname)) == NULL) { + errbox(L"Unknown function \"%ls\"", funcname); + return; + } + } + + /* Do we already have a binding for this key? */ + TTS_TAILQ_FOREACH(binding, &bindings, bi_entries) { + if (binding->bi_code == code) { + if (is_macro) { + binding->bi_func = NULL; + binding->bi_macro = wcsdup(funcname); + } else { + free(binding->bi_macro); + binding->bi_func = func; + } + return; + } + } + + /* No, add a new one */ + if ((binding = calloc(1, sizeof(*binding))) == NULL) + return; + + binding->bi_key = key; + binding->bi_code = code; + + if (is_macro) + binding->bi_macro = wcsdup(funcname); + else + binding->bi_func = func; + + TTS_TAILQ_INSERT_TAIL(&bindings, binding, bi_entries); +} + +/* + * Return the tkey_t for the key called .name, or NULL if such a key doesn't + * exist. + */ +tkey_t * +find_key(name) + const wchar_t *name; +{ +size_t i; + + for (i = 0; i < sizeof(keys) / sizeof(*keys); i++) + if (wcscmp(name, keys[i].ky_name) == 0) + return &keys[i]; + return NULL; +} + +void +bind_defaults(void) +{ + bind_key(L"?", L"help", 0); + bind_key(L"a", L"add", 0); + bind_key(L"A", L"add-old", 0); + bind_key(L"d", L"delete", 0); + bind_key(L"u", L"undelete", 0); + bind_key(L"q", L"quit", 0); + bind_key(L"", L"quit", 0); + bind_key(L"i", L"invoice", 0); + bind_key(L"b", L"billable", 0); + bind_key(L"m", L"mark", 0); + bind_key(L"U", L"unmarkall", 0); + bind_key(L"", L"startstop", 0); + bind_key(L"e", L"edit-desc", 0); + bind_key(L"\\", L"edit-time", 0); + bind_key(L"", L"showhide-inv", 0); + bind_key(L"c", L"copy", 0); + bind_key(L"+", L"add-time", 0); + bind_key(L"-", L"sub-time", 0); + bind_key(L"/", L"search", 0); + bind_key(L"$", L"sync", 0); + bind_key(L"", L"prev", 0); + bind_key(L"", L"next", 0); + bind_key(L":", L"execute", 0); + bind_key(L"M", L"merge", 0); + bind_key(L"r", L"interrupt", 0); + bind_key(L"R", L"interrupt", 0); +} diff --git a/bindings.h b/bindings.h new file mode 100644 index 0000000..1d4e916 --- /dev/null +++ b/bindings.h @@ -0,0 +1,40 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_BINDINGS_H +#define TTS_BINDINGS_H + +#include "wide.h" +#include "functions.h" +#include "tailq.h" + +typedef struct tkey { + wint_t ky_code; + const wchar_t *ky_name; +} tkey_t; + +typedef struct binding { + wint_t bi_code; + tkey_t *bi_key; + function_t *bi_func; + wchar_t *bi_macro; + + TTS_TAILQ_ENTRY(binding) bi_entries; +} binding_t; + +typedef TTS_TAILQ_HEAD(bindlist, binding) binding_list_t; +extern binding_list_t bindings; + +void bind_defaults(); +tkey_t *find_key(const wchar_t *name); +void bind_key(const wchar_t *key, const wchar_t *func, int is_macro); + + +#endif /* !TTS_BINDINGS_H */ diff --git a/bling_import.pl b/bling_import.pl index ed644df..f2e0551 100755 --- a/bling_import.pl +++ b/bling_import.pl @@ -20,6 +20,7 @@ use warnings; use strict; +use LWP::Protocol::https; use LWP::UserAgent; use URI::Escape qw/uri_escape/; use POSIX qw/strftime/; @@ -89,7 +90,7 @@ while () { if ($res->is_success) { my $resp = decode_json($res->content); if (defined($resp->{description})) { - print "Failed to Bling [$desc]: " . $resp->description . "\n"; + print "Failed to Bling [$desc]: " . $resp->{description} . "\n"; } else { if ($flags eq "-") { $flags = "i"; diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..4dc1855 --- /dev/null +++ b/commands.c @@ -0,0 +1,157 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include + +#include "commands.h" +#include "style.h" +#include "bindings.h" +#include "variable.h" + +static command_t commands[] = { + { L"bind", c_bind }, + { L"macro", c_macro }, + { L"style", c_style }, + { L"set", c_set }, + { } +}; + +command_t * +find_command(name) + const wchar_t *name; +{ +command_t *c; + for (c = commands; c->cm_name; c++) + if (wcscmp(name, c->cm_name) == 0) + return c; + return NULL; +} + +void +c_style(argc, argv) + size_t argc; + wchar_t **argv; +{ +style_t *sy; +wchar_t *last, *tok; + + if (argc < 3 || argc > 4) { + cmderr(L"Usage: style [background]"); + return; + } + + if (wcscmp(argv[1], L"header") == 0) + sy = &sy_header; + else if (wcscmp(argv[1], L"status") == 0) + sy = &sy_status; + else if (wcscmp(argv[1], L"entry") == 0) + sy = &sy_entry; + else if (wcscmp(argv[1], L"selected") == 0) + sy = &sy_selected; + else if (wcscmp(argv[1], L"running") == 0) + sy = &sy_running; + else if (wcscmp(argv[1], L"date") == 0) + sy = &sy_date; + else { + cmderr(L"Unknown style item."); + return; + } + + style_clear(sy); + for (tok = wcstok(argv[2], L",", &last); tok != NULL; + tok = wcstok(NULL, L",", &last)) { + style_add(sy, tok, argv[3]); + } + + apply_styles(); +} + +void +c_bind(argc, argv) + size_t argc; + wchar_t **argv; +{ + if (argc != 3) { + cmderr(L"Usage: bind "); + return; + } + + bind_key(argv[1], argv[2], 0); +} + +void +c_macro(argc, argv) + size_t argc; + wchar_t **argv; +{ + if (argc != 3) { + cmderr(L"Usage: macro "); + return; + } + + bind_key(argv[1], argv[2], 1); +} + +void +c_set(argc, argv) + size_t argc; + wchar_t **argv; +{ +variable_t *var; +int val; +wchar_t *p = NULL; + + if (argc != 3) { + cmderr(L"Usage: set "); + return; + } + + if ((var = find_variable(argv[1])) == NULL) { + cmderr(L"Unknown variable \"%ls\".", argv[1]); + return; + } + + switch (var->va_type) { + case VTYPE_BOOL: + if (wcscmp(argv[2], L"true") == 0 || + wcscmp(argv[2], L"yes") == 0 || + wcscmp(argv[2], L"on") == 0 || + wcscmp(argv[2], L"1") == 0) { + val = 1; + } else if (wcscmp(argv[2], L"false") == 0 || + wcscmp(argv[2], L"no") == 0 || + wcscmp(argv[2], L"off") == 0 || + wcscmp(argv[2], L"0") == 0) { + val = 0; + } else { + cmderr(L"Invalid value for boolean: \"%ls\".", argv[2]); + return; + } + + *(int *)var->va_addr = val; + break; + + case VTYPE_STRING: + free(*(wchar_t **)var->va_addr); + *(wchar_t **)var->va_addr = wcsdup(argv[2]); + break; + + case VTYPE_INT: + val = wcstol(argv[2], &p, 0); + if (!*argv[2] || *p) { + cmderr(L"Invalid number \"%ls\"", argv[2]); + break; + } + + *(int *)var->va_addr = val; + break; + } +} + diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..5c00c4f --- /dev/null +++ b/commands.h @@ -0,0 +1,33 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_COMMANDS_H +#define TTS_COMMANDS_H + +#include + +#include "wide.h" + +typedef struct command { + const wchar_t *cm_name; + void (*cm_hdl) (size_t, wchar_t **); +} command_t; + +command_t *find_command(const wchar_t *); + +void c_bind (size_t, wchar_t **); +void c_style (size_t, wchar_t **); +void c_set (size_t, wchar_t **); +void c_macro (size_t, wchar_t **); + +void cmderr (const wchar_t *, ...); +void vcmderr (const wchar_t *, va_list); + +#endif /* !TTS_COMMANDS_H */ diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..b79252d --- /dev/null +++ b/config.guess @@ -0,0 +1,1558 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-06-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# 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. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + or1k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in index b2d7e01..9cd0677 100644 --- a/config.h.in +++ b/config.h.in @@ -24,6 +24,9 @@ /* Define to 1 if you have the `IORegisterForSystemPower' function. */ #undef HAVE_IOREGISTERFORSYSTEMPOWER +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H @@ -69,6 +72,12 @@ /* Define to 1 if you have the `use_default_colors' function. */ #undef HAVE_USE_DEFAULT_COLORS +/* Define to 1 if you have the `wcslcat' function. */ +#undef HAVE_WCSLCAT + +/* Define to 1 if you have the `wcslcpy' function. */ +#undef HAVE_WCSLCPY + /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..8b612ab --- /dev/null +++ b/config.sub @@ -0,0 +1,1788 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-04-24' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# 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. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 \ + | or1k | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or1k-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure index 735cc19..3551ac0 100755 --- a/configure +++ b/configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for RT/TTS T.83.4. +# Generated by GNU Autoconf 2.69 for TTS D.84.1. # -# Report bugs to . +# Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -266,11 +266,11 @@ fi $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org and -$0: felicity@loreley.flyingparchment.org.uk about your -$0: system, including any error possibly output before this -$0: message. Then install a modern shell, or manually run -$0: the script under such a shell if you do have one." + $as_echo "$0: Please tell bug-autoconf@gnu.org and ft@le-fay.org +$0: about your system, including any error possibly output +$0: before this message. Then install a modern shell, or +$0: manually run the script under such a shell if you do +$0: have one." fi exit 1 fi @@ -578,11 +578,11 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME='RT/TTS' -PACKAGE_TARNAME='rt-tts' -PACKAGE_VERSION='T.83.4' -PACKAGE_STRING='RT/TTS T.83.4' -PACKAGE_BUGREPORT='felicity@loreley.flyingparchment.org.uk' +PACKAGE_NAME='TTS' +PACKAGE_TARNAME='tts' +PACKAGE_VERSION='D.84.1' +PACKAGE_STRING='TTS D.84.1' +PACKAGE_BUGREPORT='ft@le-fay.org' PACKAGE_URL='' ac_unique_file="tts.c" @@ -638,6 +638,14 @@ CPPFLAGS LDFLAGS CFLAGS CC +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build target_alias host_alias build_alias @@ -1232,7 +1240,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures RT/TTS T.83.4 to adapt to many kinds of systems. +\`configure' configures TTS D.84.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1280,7 +1288,7 @@ Fine tuning of the installation directories: --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/rt-tts] + --docdir=DIR documentation root [DATAROOTDIR/doc/tts] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] @@ -1288,12 +1296,16 @@ Fine tuning of the installation directories: _ACEOF cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of RT/TTS T.83.4:";; + short | recursive ) echo "Configuration of TTS D.84.1:";; esac cat <<\_ACEOF @@ -1317,7 +1329,7 @@ Some influential environment variables: Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. -Report bugs to . +Report bugs to . _ACEOF ac_status=$? fi @@ -1380,7 +1392,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -RT/TTS configure T.83.4 +TTS configure D.84.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1652,9 +1664,9 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## ------------------------------------------------------ ## -## Report this to felicity@loreley.flyingparchment.org.uk ## -## ------------------------------------------------------ ##" +( $as_echo "## ---------------------------- ## +## Report this to ft@le-fay.org ## +## ---------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac @@ -1749,7 +1761,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by RT/TTS $as_me T.83.4, which was +It was created by TTS $as_me D.84.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2101,6 +2113,122 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +case $host_os in + darwin*) + CPPFLAGS="$CPPFLAGS -D_DARWIN_USE_64_BIT_INODE=1" + ;; + linux*) + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" + ;; + netbsd*) + CPPFLAGS="$CPPFLAGS -D_NETBSD_SOURCE" + ;; + solaris*) + CPPFLAGS="-D__EXTENSIONS__ -D_FILE_OFFSET_BITS=64" + ;; +esac + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2890,35 +3018,6 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -3120,7 +3219,7 @@ main () chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; int g = getattrs(stdscr); @@ -3184,7 +3283,7 @@ main () chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; int g = getattrs(stdscr); @@ -3248,7 +3347,7 @@ main () chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; int g = getattrs(stdscr); @@ -3612,7 +3711,7 @@ main () chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; - attr_t d = WA_NORMAL; + attr_t d = WA_BOLD; cchar_t e; wint_t f; initscr(); @@ -3771,14 +3870,20 @@ fi LIBS=$ax_saved_LIBS +if test "x$ax_cv_curses" != xyes; then : + + as_fn_error $? "XSI/SVR4 curses is required to compile TTS" "$LINENO" 5 + +fi oLIBS="$LIBS" LIBS="$LIBS $CURSES_LIB" -for ac_func in use_default_colors +for ac_func in use_default_colors wcslcpy wcslcat do : - ac_fn_c_check_func "$LINENO" "use_default_colors" "ac_cv_func_use_default_colors" -if test "x$ac_cv_func_use_default_colors" = xyes; then : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_USE_DEFAULT_COLORS 1 +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi @@ -4243,7 +4348,7 @@ fi oLDFLAGS="$LDFLAGS" -LDFLAGS="$LDFLAGS -framework CoreFoundation -framework IOKit" +LDFLAGS="$LDFLAGS -framework IOKit" for ac_func in IORegisterForSystemPower do : ac_fn_c_check_func "$LINENO" "IORegisterForSystemPower" "ac_cv_func_IORegisterForSystemPower" @@ -4766,7 +4871,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by RT/TTS $as_me T.83.4, which was +This file was extended by TTS $as_me D.84.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4822,13 +4927,13 @@ $config_files Configuration headers: $config_headers -Report bugs to ." +Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -RT/TTS config.status T.83.4 +TTS config.status D.84.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index d08577f..6d7e993 100644 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,35 @@ AC_PREREQ([2.69]) -AC_INIT([RT/TTS], [T.83.4], [felicity@loreley.flyingparchment.org.uk]) +AC_INIT([TTS], [D.84.1], [ft@le-fay.org]) AC_CONFIG_SRCDIR([tts.c]) AC_CONFIG_HEADERS([config.h]) +AC_CANONICAL_HOST + +case $host_os in + darwin*) + CPPFLAGS="$CPPFLAGS -D_DARWIN_USE_64_BIT_INODE=1" + ;; + linux*) + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" + ;; + netbsd*) + CPPFLAGS="$CPPFLAGS -D_NETBSD_SOURCE" + ;; + solaris*) + CPPFLAGS="-D__EXTENSIONS__ -D_FILE_OFFSET_BITS=64" + ;; +esac + AC_PROG_CC AC_PROG_INSTALL AX_WITH_CURSES +AS_IF([test "x$ax_cv_curses" != xyes], [ + AC_ERROR([XSI/SVR4 curses is required to compile TTS]) +]) oLIBS="$LIBS" LIBS="$LIBS $CURSES_LIB" -AC_CHECK_FUNCS([use_default_colors]) +AC_CHECK_FUNCS([use_default_colors wcslcpy wcslcat]) LIBS="$oLIBS" AC_CHECK_HEADERS([IOKit/pwr_mgt/IOPMLib.h]) @@ -17,7 +37,7 @@ AC_CHECK_HEADERS([IOKit/pwr_mgt/IOPMLib.h]) AC_CHECK_LIB(m, round) oLDFLAGS="$LDFLAGS" -LDFLAGS="$LDFLAGS -framework CoreFoundation -framework IOKit" +LDFLAGS="$LDFLAGS -framework IOKit" AC_CHECK_FUNCS([IORegisterForSystemPower], [], [LDFLAGS="$oLDFLAGS"]) AC_CONFIG_FILES([Makefile]) diff --git a/entry.c b/entry.c new file mode 100644 index 0000000..6226efe --- /dev/null +++ b/entry.c @@ -0,0 +1,124 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include +#include +#include +#include + +#include "entry.h" +#include "wide.h" +#include "tts.h" + +entry_list entries = TTS_TAILQ_HEAD_INITIALIZER(entries); + +entry_t *running; + +entry_t * +entry_new(desc) + const wchar_t *desc; +{ +entry_t *en; + if ((en = calloc(1, sizeof(*en))) == NULL) + return NULL; + + if (auto_nonbillable && wcsstr(desc, auto_nonbillable)) + en->en_flags.efl_nonbillable = 1; + + TTS_TAILQ_INSERT_HEAD(&entries, en, en_entries); + + en->en_desc = wcsdup(desc); + time(&en->en_created); + + return en; +} + +void +entry_start(en) + entry_t *en; +{ + if (running) + entry_stop(running); + time(&en->en_started); + running = en; +} + +void +entry_stop(en) + entry_t *en; +{ + if (running == en) + running = NULL; + en->en_secs += time(NULL) - en->en_started; + en->en_started = 0; +} + +void +entry_free(en) + entry_t *en; +{ + if (en == running) + entry_stop(en); + free(en->en_desc); +} + +void +entry_account(en) + entry_t *en; +{ + if (!en->en_started) + return; + en->en_secs += time(NULL) - en->en_started; + time(&en->en_started); +} + +/* + * Return the amount of time for the day on which the timestamp .when falls. + * If .inv is 0, sum non-invoiced entries; if 1, sum invoiced entries; if + * 2, sum billable entries; if -1, sum all entries. If .incr is non-zero, + * individual entry time will be rounded up to intervals of that many minutes. + */ +time_t +entry_time_for_day(when, inv, incr) + time_t when; +{ +time_t day = time_day(when); +time_t sum = 0; +entry_t *en; +int rnd = incr * 60; + TTS_TAILQ_FOREACH(en, &entries, en_entries) { + time_t n; + + if (entry_day(en) > day) + continue; + if (entry_day(en) < day) + break; + + if (inv == 0 && en->en_flags.efl_invoiced) + continue; + if (inv == 1 && !en->en_flags.efl_invoiced) + continue; + if (inv == 2 && en->en_flags.efl_nonbillable) + continue; + + n = en->en_secs; + if (en->en_started) + n += time(NULL) - en->en_started; + + if (!n) + continue; + + if (rnd) + n = (1 + round((n - 1) / rnd)) * rnd; + sum += n; + } + return sum; +} + diff --git a/entry.h b/entry.h new file mode 100644 index 0000000..651fa4d --- /dev/null +++ b/entry.h @@ -0,0 +1,59 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_ENTRY_H +#define TTS_ENTRY_H + +#include + +#include "tailq.h" +#include "wide.h" + +typedef struct entry { + wchar_t *en_desc; + int en_secs; + time_t en_started; + time_t en_created; + + struct { + int efl_visible:1; + int efl_invoiced:1; + int efl_marked:1; + int efl_deleted:1; + int efl_nonbillable:1; + } en_flags; + TTS_TAILQ_ENTRY(entry) en_entries; +} entry_t; + +typedef TTS_TAILQ_HEAD(entrylist, entry) entry_list; +extern entry_list entries; + +extern entry_t *running; + +entry_t *entry_new (const wchar_t *); +void entry_start (entry_t *); +void entry_stop (entry_t *); +void entry_free (entry_t *); +void entry_account (entry_t *); +time_t entry_time_for_day (time_t, int, int); + +#define time_day(t) (((t) / (60 * 60 * 24)) * (60 * 60 * 24)) +#define entry_day(e) (time_day((e)->en_created)) + +#define time_to_hms(t, h, m, s) do { \ + time_t n = t; \ + h = n / (60 * 60); \ + n %= (60 * 60); \ + m = n / 60; \ + n %= 60; \ + s = n; \ + } while (0) + +#endif /* !TTS_ENTRY_H */ diff --git a/functions.c b/functions.c new file mode 100644 index 0000000..b037878 --- /dev/null +++ b/functions.c @@ -0,0 +1,761 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include + +#include "functions.h" +#include "tts.h" +#include "entry.h" +#include "ui.h" +#include "commands.h" +#include "tts_curses.h" +#include "bindings.h" +#include "str.h" + +function_t funcs[] = { + { L"help", khelp, L"display help screen" }, + { L"add", kadd, L"add a new entry and start the timer" }, + { L"add-old", kaddold, L"add a new entry and specify its duration" }, + { L"delete", kmarkdel, L"delete the current entry" }, + { L"undelete", kundel, L"undelete the current entry" }, + { L"quit", kquit, L"exit TTS" }, + { L"invoice", kinvoiced, L"toggle current entry as invoiced" }, + { L"billable", kbillable, L"toggle current entry as billable" }, + { L"mark", kmark, L"mark the current entry" }, + { L"unmarkall", kunmarkall, L"unmark all entries" }, + { L"startstop", ktoggle, L"start or stop the timer" }, + { L"edit-desc", keddesc, L"edit the current entry's description" }, + { L"edit-time", kedtime, L"edit the current entry's duration" }, + { L"showhide-inv", ktoggleinv, L"show or hide invoiced entries" }, + { L"copy", kcopy, L"copy the current entry's description to a new entry" }, + { L"add-time", kaddtime, L"add time to the current entry" }, + { L"sub-time", kdeltime, L"subtract time from the current entry" }, + { L"search", ksearch, L"search for an entry by name" }, + { L"sync", ksync, L"purge all deleted entries" }, + { L"prev", kup, L"move to the previous entry" }, + { L"next", kdown, L"move to the next entry" }, + { L"execute", kexec, L"execute a configuration command" }, + { L"merge", kmerge, L"merge marked entries into current entry" }, + { L"interrupt", kint, L"split current entry into new entry"}, + { } +}; + +static int +valid_description(d) + const wchar_t *d; +{ + if (!d) + return 0; + + while (iswspace(*d)) + d++; + + if (!*d) + return 0; + + return 1; +} + +void +kquit() +{ +entry_t *en; +int ndel = 0; + + TTS_TAILQ_FOREACH(en, &entries, en_entries) { + if (en->en_flags.efl_deleted) + ndel++; + } + + if (ndel) { + wchar_t s[128]; + swprintf(s, wsizeof(s), L"Purge %d deleted entries?", ndel); + if (yesno(s)) { + ksync(); + } + } + + doexit = 1; +} + +void +kadd() +{ +wchar_t *name; +entry_t *en; + name = prompt(L"Description:", NULL, NULL); + + if (!valid_description(name)) { + free(name); + return; + } + + en = entry_new(name); + entry_start(en); + curent = en; + save(); +} + +void +kaddold() +{ +wchar_t *name; +entry_t *en; + name = prompt(L"Description:", NULL, NULL); + + if (!valid_description(name)) { + free(name); + return; + } + + en = entry_new(name); + curent = en; + kedtime(); + save(); +} + +void +ktoggle() +{ + itime = 0; + + if (!curent) + return; + + if (curent == running) { + entry_stop(curent); + save(); + return; + } + + if (running) + entry_stop(running); + entry_start(curent); + save(); +} + +void +kundel() +{ + if (!curent) + return; + + curent->en_flags.efl_deleted = 0; + if (delete_advance) + cursadvance(); +} + +void +kmarkdel() +{ +entry_t *en; +int nmarked = 0; + + TTS_TAILQ_FOREACH(en, &entries, en_entries) { + if (en->en_flags.efl_marked) { + nmarked++; + en->en_flags.efl_deleted = 1; + } + } + + if (nmarked) + return; + + if (!curent) { + drawstatus(L"No entries to delete."); + return; + } + + curent->en_flags.efl_deleted = 1; + + if (delete_advance) + cursadvance(); +} + +void +ksync() +{ +entry_t *en, *ten; + + TTS_TAILQ_FOREACH_SAFE(en, &entries, en_entries, ten) { + if (!en->en_flags.efl_deleted) + continue; + if (en == curent) + curent = NULL; + TTS_TAILQ_REMOVE(&entries, en, en_entries); + entry_free(en); + } + + if (curent == NULL) + curent = TTS_TAILQ_FIRST(&entries); + save(); +} + +void +kup() +{ +entry_t *prev = curent; + if (!curent) + return; + + do { + if ((prev = TTS_TAILQ_PREV(prev, entrylist, en_entries)) == NULL) + break; + } while (!showinv && prev->en_flags.efl_invoiced); + + if (prev == NULL) { + drawstatus(L"Already at first entry."); + return; + } + + curent = prev; + if (!curent->en_flags.efl_visible) + pagestart--; +} + +void +kdown() +{ +entry_t *next = curent; + if (!curent) + return; + + do { + if ((next = TTS_TAILQ_NEXT(next, en_entries)) == NULL) + break; + } while (!showinv && next->en_flags.efl_invoiced); + + if (next == NULL) { + drawstatus(L"Already at last entry."); + return; + } + + curent = next; + if (!curent->en_flags.efl_visible) + pagestart++; +} + +void +kinvoiced() +{ +entry_t *en; +int anymarked = 0; + + TTS_TAILQ_FOREACH(en, &entries, en_entries) { + if (!en->en_flags.efl_marked) + continue; + anymarked = 1; + en->en_flags.efl_invoiced = !en->en_flags.efl_invoiced; + en->en_flags.efl_marked = 0; + } + + if (anymarked) { + save(); + return; + } + + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + curent->en_flags.efl_invoiced = !curent->en_flags.efl_invoiced; + save(); + + en = curent; + + if (showinv) { + if (TTS_TAILQ_NEXT(curent, en_entries) != NULL) + curent = TTS_TAILQ_NEXT(curent, en_entries); + return; + } + + /* + * Try to find the next uninvoiced request to move the cursor to. + */ + for (;;) { + if ((curent = TTS_TAILQ_NEXT(curent, en_entries)) == NULL) + break; /* end of list */ + if (!curent->en_flags.efl_invoiced) + return; + } + + /* + * We didn't find any, so try searching backwards instead. + */ + for (curent = en;;) { + if ((curent = TTS_TAILQ_PREV(curent, entrylist, en_entries)) == NULL) + break; /* end of list */ + if (!curent->en_flags.efl_invoiced) + return; + } +} + +void +kbillable() +{ +entry_t *en; +int anymarked = 0; + + TTS_TAILQ_FOREACH(en, &entries, en_entries) { + if (!en->en_flags.efl_marked) + continue; + anymarked = 1; + en->en_flags.efl_nonbillable = !en->en_flags.efl_nonbillable; + en->en_flags.efl_marked = 0; + } + + if (anymarked) { + save(); + return; + } + + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + curent->en_flags.efl_nonbillable = !curent->en_flags.efl_nonbillable; + save(); + + if (bill_advance) + cursadvance(); +} + +void +keddesc() +{ +wchar_t *new; + + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + if ((new = prompt(L"Description:", curent->en_desc, NULL)) == NULL) + return; + + free(curent->en_desc); + curent->en_desc = new; + save(); +} + +void +kedtime() +{ +time_t n; + + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + n = curent->en_secs; + if (curent->en_started) + n += time(NULL) - curent->en_started; + + if ((n = prduration(L"Duration:", n)) == (time_t) -1) { + drawstatus(L"Invalid duration."); + return; + } + + curent->en_secs = n; + if (curent->en_started) + time(&curent->en_started); + + save(); +} + +void +ktoggleinv() +{ +entry_t *en = curent; + showinv = !showinv; + drawstatus(L"%ls invoiced entries.", showinv ? L"Showing" : L"Hiding"); + + if (curent && !curent->en_flags.efl_invoiced) + return; + + if (!curent) { + curent = TTS_TAILQ_FIRST(&entries); + return; + } + + /* + * Try to find the next uninvoiced request to move the cursor to. + */ + for (;;) { + if ((curent = TTS_TAILQ_NEXT(curent, en_entries)) == NULL) + break; /* end of list */ + if (!curent->en_flags.efl_invoiced) + return; + } + + /* + * We didn't find any, so try searching backwards instead. + */ + for (curent = en;;) { + if ((curent = TTS_TAILQ_PREV(curent, entrylist, en_entries)) == NULL) + break; /* end of list */ + if (!curent->en_flags.efl_invoiced) + return; + } +} + +void +kcopy() +{ +entry_t *en; + + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + en = entry_new(curent->en_desc); + curent = en; + entry_start(en); + save(); +} + +void +kaddtime() +{ +time_t secs; + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + if ((secs = prduration(L"Time to add:", 0)) == (time_t) -1) { + drawstatus(L"Invalid time format."); + return; + } + + curent->en_secs += secs; + save(); +} + +void +kdeltime() +{ +time_t secs; + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + if ((secs = prduration(L"Time to subtract:", 0)) == (time_t) -1) { + drawstatus(L"Invalid time format."); + return; + } + + entry_account(curent); + + if (curent->en_secs - secs < 0) { + drawstatus(L"Remaining time cannot be less than zero."); + return; + } + + curent->en_secs -= secs; + save(); +} + +void +kmerge() +{ +entry_t *en, *ten; +int nmarked = 0; +wchar_t pr[128]; +wchar_t *ct; +int s = 0; + + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + /* + * Count number of marked entries and the summed time. + */ + TTS_TAILQ_FOREACH(en, &entries, en_entries) { + if (!en->en_flags.efl_marked || en == curent) + continue; + nmarked++; + s += en->en_secs; + if (en->en_started) + s += time(NULL) - en->en_started; + } + + if (nmarked == 0) { + drawstatus(L"No marked entries."); + return; + } + + ct = maketime(s, time_format); + swprintf(pr, wsizeof(pr), L"Merge %d marked entries [%ls] into current entry", + nmarked, ct); + free(ct); + + if (!yesno(pr)) + return; + + TTS_TAILQ_FOREACH_SAFE(en, &entries, en_entries, ten) { + if (!en->en_flags.efl_marked || en == curent) + continue; + if (en->en_started) + entry_stop(en); + curent->en_secs += en->en_secs; + TTS_TAILQ_REMOVE(&entries, en, en_entries); + entry_free(en); + } + save(); +} + +void +khelp() +{ +WINDOW *hwin; +size_t nhelp = 0; +wchar_t **help; +#define HTITLE L" TTS keys " +size_t width = 0; +size_t i; +wint_t c; +binding_t *bi; + + /* Count the number of bindings */ + TTS_TAILQ_FOREACH(bi, &bindings, bi_entries) + nhelp++; + help = calloc(nhelp, sizeof(const wchar_t *)); + + i = 0; + TTS_TAILQ_FOREACH(bi, &bindings, bi_entries) { + wchar_t s[128], t[16]; + + if (bi->bi_key) + swprintf(t, wsizeof(t), L"%ls", bi->bi_key->ky_name); + else + swprintf(t, wsizeof(t), L"%lc", bi->bi_code); + + if (bi->bi_macro) { + wchar_t *esc = escstr(bi->bi_macro); + swprintf(s, wsizeof(s), L"%-10ls execute macro: %ls", + t, esc); + free(esc); + } else + swprintf(s, wsizeof(s), L"%-10ls %ls (%ls)", + t, bi->bi_func->fn_desc, bi->bi_func->fn_name); + + help[i] = wcsdup(s); + i++; + } + + if (nhelp > (LINES - 6)) + nhelp = LINES - 6; + + for (i = 0; i < nhelp; i++) + if (wcslen(help[i]) > width) + width = wcslen(help[i]); + + hwin = newwin(nhelp + 4, width + 4, + (LINES / 2) - ((nhelp + 2) / 2), + (COLS / 2) - ((width + 2) / 2)); + wborder(hwin, 0, 0, 0, 0, 0, 0, 0, 0); + + wattron(hwin, A_REVERSE | A_BOLD); + wmove(hwin, 0, (width / 2) - (wsizeof(HTITLE) - 1)/2); + waddwstr(hwin, HTITLE); + wattroff(hwin, A_REVERSE | A_BOLD); + + for (i = 0; i < nhelp; i++) { + wmove(hwin, i + 2, 2); + waddwstr(hwin, help[i]); + } + + wrefresh(hwin); + + while (wget_wch(hwin, &c) == ERR +#ifdef KEY_RESIZE + || (c == KEY_RESIZE) +#endif + ) + ; + + delwin(hwin); + + for (i = 0; i < nhelp; i++) + free(help[i]); + free(help); +} + +void +kmark() +{ + if (!curent) { + drawstatus(L"No entry selected."); + return; + } + + curent->en_flags.efl_marked = !curent->en_flags.efl_marked; + + if (mark_advance) + cursadvance(); +} + +void +kunmarkall() +{ +entry_t *en; + TTS_TAILQ_FOREACH(en, &entries, en_entries) + en->en_flags.efl_marked = 0; +} + +void +kint() +{ +time_t duration; +entry_t *en; +wchar_t *name; + + if (!itime) { + if (!running) { + drawstatus(L"No running entry."); + return; + } + + itime = time(NULL); + return; + } + + if (!running) { + drawstatus(L"No running entry."); + return; + } + + name = prompt(L"Description ( to abandon interrupt):", NULL, NULL); + + if (!valid_description(name)) { + itime = 0; + free(name); + return; + } + + duration = time(NULL) - itime; + + itime = 0; + running->en_secs += (time(NULL) - running->en_started); + running->en_started = time(NULL); + running->en_secs -= duration; + + en = entry_new(name); + en->en_created = time(NULL) - duration; + en->en_secs = duration; + save(); + + free(name); +} + +void +ksearch() +{ +static wchar_t *lastsearch; +wchar_t *term; +entry_t *start, *cur; + + if (!curent) { + drawstatus(L"No entries."); + return; + } + + if ((term = prompt(L"Search:", NULL, NULL)) == NULL) + return; + + if (!*term) { + free(term); + if (!lastsearch) + return; + + term = lastsearch; + } else { + free(lastsearch); + lastsearch = term; + } + + cur = start = curent; + + for (;;) { + cur = TTS_TAILQ_NEXT(cur, en_entries); + if (cur == NULL) { + drawstatus(L"Search reached last entry, continuing from top."); + cur = TTS_TAILQ_FIRST(&entries); + } + + if (cur == start) { + drawstatus(L"No matches."); + break; + } + + if (wcsstr(cur->en_desc, term)) { + curent = cur; + if (!showinv && cur->en_flags.efl_invoiced) + showinv = 1; + return; + } + + } +} + +void +kexec() +{ +wchar_t *cmd; +wchar_t **args; +command_t *cmds; +size_t nargs; + + if ((cmd = prompt(L":", NULL, NULL)) == NULL || !*cmd) { + free(cmd); + return; + } + + nargs = tokenise(cmd, &args); + free(cmd); + + if (nargs == 0) { + tokfree(&args); + return; + } + + if ((cmds = find_command(args[0])) == NULL) { + drawstatus(L"Unknown command."); + tokfree(&args); + return; + } + + cmds->cm_hdl(nargs, args); + tokfree(&args); +} + +/* + * Return the function_t for the function called .name, or NULL if such a + * function doesn't exist. + */ +function_t * +find_func(name) + const wchar_t *name; +{ +function_t *f; + for (f = funcs; f->fn_name; f++) + if (wcscmp(name, f->fn_name) == 0) + return f; + return NULL; +} + diff --git a/functions.h b/functions.h new file mode 100644 index 0000000..9f1186e --- /dev/null +++ b/functions.h @@ -0,0 +1,51 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_FUNCTIONS_H +#define TTS_FUNCTIONS_H + +#include "wide.h" + +void kadd(void); +void kaddold(void); +void kquit(void); +void kup(void); +void kdown(void); +void ktoggle(void); +void kinvoiced(void); +void kbillable(void); +void keddesc(void); +void kedtime(void); +void ktoggleinv(void); +void kcopy(void); +void kaddtime(void); +void kdeltime(void); +void khelp(void); +void kmark(void); +void kunmarkall(void); +void ksearch(void); +void kmarkdel(void); +void kundel(void); +void ksync(void); +void kexec(void); +void kmerge(void); +void kint(void); + +typedef struct function { + const wchar_t *fn_name; + void (*fn_hdl) (void); + const wchar_t *fn_desc; +} function_t; + +extern function_t funcs[]; + +function_t *find_func(const wchar_t *name); + +#endif /* !TTS_FUNCTIONS_H */ diff --git a/queue.h b/queue.h deleted file mode 100644 index fc3c633..0000000 --- a/queue.h +++ /dev/null @@ -1,611 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * FreeBSD: release/9.0.0/sys/sys/queue.h 221843 2011-05-13 15:49:23Z mdf - */ - -#ifndef TTS_QUEUE_H -#define TTS_QUEUE_H - -/* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - - - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_AFTER + - + - - * _REMOVE_HEAD + - + - - * _REMOVE + + + + - * _SWAP + + + + - * - */ -#ifdef QUEUE_MACRO_DEBUG -/* Store the last 2 places the queue element or head was altered */ -struct qm_trace { - char * lastfile; - int lastline; - char * prevfile; - int prevline; -}; - -#define TRACEBUF struct qm_trace trace; -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) - -#define QMD_TRACE_HEAD(head) do { \ - (head)->trace.prevline = (head)->trace.lastline; \ - (head)->trace.prevfile = (head)->trace.lastfile; \ - (head)->trace.lastline = __LINE__; \ - (head)->trace.lastfile = __FILE__; \ -} while (0) - -#define QMD_TRACE_ELEM(elem) do { \ - (elem)->trace.prevline = (elem)->trace.lastline; \ - (elem)->trace.prevfile = (elem)->trace.lastfile; \ - (elem)->trace.lastline = __LINE__; \ - (elem)->trace.lastfile = __FILE__; \ -} while (0) - -#else -#define QMD_TRACE_ELEM(elem) -#define QMD_TRACE_HEAD(head) -#define QMD_SAVELINK(name, link) -#define TRACEBUF -#define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != NULL; \ - (varp) = &SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ -} while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_AFTER(curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define SLIST_REMOVE_AFTER(elm, field) do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ -} while (0) - -#define SLIST_SWAP(head1, head2, type) do { \ - struct type *swap_first = SLIST_FIRST(head1); \ - SLIST_FIRST(head1) = SLIST_FIRST(head2); \ - SLIST_FIRST(head2) = swap_first; \ -} while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ -} while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_SWAP(head1, head2, type) do { \ - struct type *swap_first = STAILQ_FIRST(head1); \ - struct type **swap_last = (head1)->stqh_last; \ - STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_FIRST(head2) = swap_first; \ - (head2)->stqh_last = swap_last; \ - if (STAILQ_EMPTY(head1)) \ - (head1)->stqh_last = &STAILQ_FIRST(head1); \ - if (STAILQ_EMPTY(head2)) \ - (head2)->stqh_last = &STAILQ_FIRST(head2); \ -} while (0) - - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QMD_LIST_CHECK_NEXT(listelm, field); \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_LIST_CHECK_PREV(listelm, field); \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QMD_LIST_CHECK_HEAD((head), field); \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_PREV(elm, field) ((elm)->field.le_prev ? *(elm)->field.le_prev : NULL) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.le_next); \ - QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ - QMD_LIST_CHECK_NEXT(elm, field); \ - QMD_LIST_CHECK_PREV(elm, field); \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ -} while (0) - -#define LIST_SWAP(head1, head2, type, field) do { \ - struct type *swap_tmp = LIST_FIRST((head1)); \ - LIST_FIRST((head1)) = LIST_FIRST((head2)); \ - LIST_FIRST((head2)) = swap_tmp; \ - if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ - if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ -} while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ -} - -/* - * Tail queue functions. - */ -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ - if (!TAILQ_EMPTY(head) && \ - TAILQ_FIRST((head))->field.tqe_prev != \ - &TAILQ_FIRST((head))) \ - panic("Bad tailq head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ - if (*(head)->tqh_last != NULL) \ - panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ - if (TAILQ_NEXT((elm), field) != NULL && \ - TAILQ_NEXT((elm), field)->field.tqe_prev != \ - &((elm)->field.tqe_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.tqe_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_TAILQ_CHECK_HEAD(head, field) -#define QMD_TAILQ_CHECK_TAIL(head, headname) -#define QMD_TAILQ_CHECK_NEXT(elm, field) -#define QMD_TAILQ_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - QMD_TRACE_HEAD(head1); \ - QMD_TRACE_HEAD(head2); \ - } \ -} while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QMD_TAILQ_CHECK_NEXT(listelm, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else { \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - } \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_TAILQ_CHECK_PREV(listelm, field); \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QMD_TAILQ_CHECK_HEAD(head, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QMD_TAILQ_CHECK_TAIL(head, field); \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ - QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ - QMD_TAILQ_CHECK_NEXT(elm, field); \ - QMD_TAILQ_CHECK_PREV(elm, field); \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - QMD_TRACE_HEAD(head); \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_SWAP(head1, head2, type, field) do { \ - struct type *swap_first = (head1)->tqh_first; \ - struct type **swap_last = (head1)->tqh_last; \ - (head1)->tqh_first = (head2)->tqh_first; \ - (head1)->tqh_last = (head2)->tqh_last; \ - (head2)->tqh_first = swap_first; \ - (head2)->tqh_last = swap_last; \ - if ((swap_first = (head1)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head1)->tqh_first; \ - else \ - (head1)->tqh_last = &(head1)->tqh_first; \ - if ((swap_first = (head2)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head2)->tqh_first; \ - else \ - (head2)->tqh_last = &(head2)->tqh_first; \ -} while (0) - -#endif /* !TTS_QUEUE_H */ diff --git a/screenshot.png b/screenshot.png new file mode 100755 index 0000000..49207ac Binary files /dev/null and b/screenshot.png differ diff --git a/str.c b/str.c new file mode 100644 index 0000000..4c7a42b --- /dev/null +++ b/str.c @@ -0,0 +1,277 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include +#include +#include + +#include "str.h" +#include "tts.h" + +size_t +tokenise(str, res) + const wchar_t *str; + wchar_t ***res; +{ +int ntoks = 0; +const wchar_t *p, *q; +wchar_t *r; + + *res = NULL; + p = str; + + for (;;) { + ptrdiff_t sz; + int qskip = 0; + int isbsl = 0; + + /* Skip leading whitespace */ + while (iswspace(*p)) + p++; + + /* End of string - no more arguments */ + if (!*p) + break; + + q = p; + + if (*q == '"') { + /* Quoted string - scan for end of string */ + p++; + + while (*++q) { + if (!isbsl && (*q == '\\')) { + isbsl = 1; + continue; + } + + if (!isbsl && (*q == '"')) + break; + + isbsl = 0; + } + /* At this point, *q == '"'. If it's NUL instead, then the + * string was not terminated with a closing '"' before the end + * of the line. We could give an error here, but it seems + * more useful to just accept it. + */ + if (*q == '"') + qskip = 1; + } else { + /* Not quoted - just find the next whitespace */ + while (!iswspace(*q) && *q) + q++; + } + + /* Copy the argument (which is sz bytes long) into the result array */ + sz = (q - p); + *res = realloc(*res, sizeof(wchar_t *) * (ntoks + 1)); + (*res)[ntoks] = malloc(sizeof(wchar_t) * (sz + 1)); + wmemcpy((*res)[ntoks], p, sz); + + /* Handle \ escapes */ + for (r = (*res)[ntoks]; r < ((*res)[ntoks] + sz);) { + if (!isbsl) { + if (*r == '\\') { + wmemmove(r, r + 1, sz - (r - (*res)[ntoks])); + sz--; + isbsl = 1; + continue; + } + + r++; + continue; + } + + switch (*r) { + case 't': *r = '\t'; break; + case 'n': *r = '\n'; break; + case 'r': *r = '\r'; break; + case 'v': *r = '\v'; break; + case '\\': *r = '\\'; break; + } + + isbsl = 0; + r++; + } + + (*res)[ntoks][sz] = 0; + ntoks++; + + if (qskip) + q += qskip; + + while (iswspace(*q)) + q++; + + /* + * q is the start of the next token (with leading whitespace); reset + * p to process the next argument. + */ + if (!*q) + break; + p = q; + } + + *res = realloc(*res, sizeof(wchar_t *) * (ntoks + 1)); + (*res)[ntoks] = NULL; + return ntoks; +} + +void +tokfree(vec) + wchar_t ***vec; +{ +wchar_t **p; + for (p = (*vec); *p; p++) + free(*p); + free(*vec); +} + +time_t +parsetime(tm) + const wchar_t *tm; +{ +int h = 0, m = 0, s = 0; +time_t i = 0, r = 0; + +/* The empty string is not a valid duration */ + if (!*tm) + return (time_t) -1; +/* Check for "hh:mm:ss" or "mm:ss" */ + if (swscanf(tm, L"%d:%d:%d", &h, &m, &s) == 3) + return (h * 60 * 60) + (m * 60) + s; + + if (swscanf(tm, L"%d:%d", &m, &s) == 2) + return (m * 60) + s; + +/* + * The string could either be a format like 3h10m, or a simle number like 47 + * (meaning seconds), which is also handled here. This is effectively an + * implementation of atoi with special meaning for 'h', 'm' and 's' characters. + * + * Note that we make no attempt to handle overflow. + */ + for (; *tm; tm++) { + switch (*tm) { + case L'h': + r += i * (60 * 60); + i = 0; + continue; + + case L'm': + r += i * 60; + i = 0; + continue; + + case L's': + r += i; + i = 0; + continue; + + case L' ': + continue; + } + + if (wcschr(L"0123456789", *tm) == NULL) + return (time_t) -1; + + i *= 10; + i += *tm - L'0'; + } + + return r + i; +} + +wchar_t * +maketime(tm, fmt) + time_t tm; +{ +wchar_t res[64] = {}; +wchar_t t[16]; + + if (fmt == TIME_HMS) { + int h, m, s; + time_to_hms(tm, h, m, s); + swprintf(t, wsizeof(t), L"%02d:%02d:%02d", + h, m, s); + return wcsdup(t); + } + + if (fmt == TIME_HM) { + int h, m, s; + time_to_hms(tm, h, m, s); + swprintf(t, wsizeof(t), L"%02d:%02d", h, m); + return wcsdup(t); + } + + if (tm >= (60 * 60)) { + swprintf(t, wsizeof(t), L"%2dh ", tm / (60 * 60)); + wcslcat(res, t, wsizeof(res)); + tm %= (60 * 60); + } + + if (tm >= 60) { + swprintf(t, wsizeof(t), L"%2dm ", tm / 60); + wcslcat(res, t, wsizeof(res)); + tm %= 60; + } + + if (fmt == TIME_AHMS && tm) { + swprintf(t, wsizeof(t), L"%2ds ", tm); + wcslcat(res, t, wsizeof(res)); + } + + res[wcslen(res) - 1] = '\0'; + + return wcsdup(res); +} + +wchar_t * +escstr(s) + const wchar_t *s; +{ +wchar_t *ret, *p; + + if ((ret = calloc(sizeof(wchar_t), wcslen(s) * 2 + 1)) == NULL) + return NULL; + + for (p = ret; *s; s++) { + switch (*s) { + case '\\': + *p++ = L'\\'; + *p++ = L'\\'; + continue; + case '\n': + *p++ = L'\\'; + *p++ = L'n'; + continue; + case '\t': + *p++ = L'\\'; + *p++ = L't'; + continue; + case '\v': + *p++ = L'\\'; + *p++ = L'v'; + continue; + case '\r': + *p++ = L'\\'; + *p++ = L'r'; + continue; + case '"': + *p++ = L'\\'; + *p++ = L'"'; + continue; + } + + *p++ = *s; + } + return ret; +} diff --git a/str.h b/str.h new file mode 100644 index 0000000..9ea533e --- /dev/null +++ b/str.h @@ -0,0 +1,36 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_STR_H +#define TTS_STR_H + +#include + +#include "wide.h" + +#define TIME_HMS 0 /* HH:MM:SS */ +#define TIME_HM 1 /* HH:MM */ +#define TIME_AHMS 2 /* 1h10m37s */ +#define TIME_AHM 3 /* 1h10w */ + +#define TIMEFMT_FOR_EDIT(f) \ + ( (f) == TIME_HMS ? TIME_HMS \ + : (f) == TIME_HM ? TIME_HMS \ + : (f) == TIME_AHMS ? TIME_AHMS \ + : (f) == TIME_AHM ? TIME_AHMS \ + : 0) + +size_t tokenise (const wchar_t *, wchar_t ***result); +void tokfree (wchar_t ***); +time_t parsetime (const wchar_t *); +wchar_t *maketime (time_t, int format); +wchar_t *escstr (const wchar_t *); + +#endif /* !TTS_STR_H */ diff --git a/style.c b/style.c new file mode 100644 index 0000000..9479876 --- /dev/null +++ b/style.c @@ -0,0 +1,146 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include "style.h" +#include "ui.h" +#include "wide.h" + +short default_fg, default_bg; + +style_t sy_header = { 1, 0 }, + sy_status = { 2, 0 }, + sy_entry = { 3, 0 }, + sy_running = { 4, 0 }, + sy_selected = { 5, 0 }, + sy_date = { 6, 0 }; + +static attrname_t attrnames[] = { + { L"normal", 0 }, + { L"bold", WA_BOLD }, + { L"reverse", WA_REVERSE }, + { L"blink", WA_BLINK }, + { L"dim", WA_DIM }, + { L"underline", WA_UNDERLINE }, + { L"standout", WA_STANDOUT } +}; + +static colour_t colours[] = { + { L"black", COLOR_BLACK }, + { L"red", COLOR_RED }, + { L"green", COLOR_GREEN }, + { L"yellow", COLOR_YELLOW }, + { L"blue", COLOR_BLUE }, + { L"magenta", COLOR_MAGENTA }, + { L"cyan", COLOR_CYAN }, + { L"white", COLOR_WHITE } +}; + +int +attr_find(name, result) + const wchar_t *name; + attr_t *result; +{ +size_t i; + for (i = 0; i < sizeof(attrnames) / sizeof(*attrnames); i++) { + if (wcscmp(attrnames[i].an_name, name) == 0) { + *result = attrnames[i].an_value; + return 0; + } + } + + return -1; +} + +int +colour_find(name, result) + const wchar_t *name; + short *result; +{ +size_t i; + for (i = 0; i < sizeof(colours) / sizeof(*colours); i++) { + if (wcscmp(colours[i].co_name, name) == 0) { + *result = colours[i].co_value; + return 0; + } + } + + return -1; +} + +void +style_clear(sy) + style_t *sy; +{ + init_pair(sy->sy_pair, default_fg, default_bg); + sy->sy_attrs = 0; +} + +int +style_set(sy, fg, bg) + style_t *sy; + const wchar_t *fg, *bg; +{ + sy->sy_attrs = 0; + init_pair(sy->sy_pair, default_fg, default_bg); + return style_add(sy, fg, bg); +} + +int +style_add(sy, fg, bg) + style_t *sy; + const wchar_t *fg, *bg; +{ +attr_t at; +short colfg, colbg = default_bg; + + if (colour_find(fg, &colfg) == 0) { + if (bg && (colour_find(bg, &colbg) == -1)) + return -1; + + init_pair(sy->sy_pair, colfg, colbg); + return 0; + } + + if (attr_find(fg, &at) == -1) + return -1; + sy->sy_attrs |= at; + return 0; +} + +void +apply_styles() +{ + wbkgd(statwin, style_bg(sy_status)); + wattr_on(statwin, style_fg(sy_status), NULL); + drawstatus(L""); + + wbkgd(titwin, style_bg(sy_header)); + wattr_on(titwin, style_fg(sy_header), NULL); + drawheader(); +} + +void +style_defaults(void) +{ + init_pair(1, default_fg, default_bg); + init_pair(2, default_fg, default_bg); + init_pair(3, default_fg, default_bg); + init_pair(4, default_fg, default_bg); + init_pair(5, default_fg, default_bg); + init_pair(6, default_fg, default_bg); + + style_set(&sy_header, L"reverse", NULL); + style_set(&sy_status, L"normal", NULL); + style_set(&sy_entry, L"normal", NULL); + style_set(&sy_selected, L"normal", NULL); + style_set(&sy_running, L"bold", NULL); + style_set(&sy_date, L"underline", NULL); + apply_styles(); +} diff --git a/style.h b/style.h new file mode 100644 index 0000000..2954895 --- /dev/null +++ b/style.h @@ -0,0 +1,54 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_STYLE_H +#define TTS_STYLE_H + +#include "tts_curses.h" +#include "wide.h" + +typedef struct style { + short sy_pair; + attr_t sy_attrs; +} style_t; + +#define style_fg(s) (COLOR_PAIR((s).sy_pair) | (s).sy_attrs) +#define style_bg(s) ((wint_t) ' ' | COLOR_PAIR((s).sy_pair) | ((s).sy_attrs & ~WA_UNDERLINE)) + +typedef struct attrname { + const wchar_t *an_name; + attr_t an_value; +} attrname_t; + +typedef struct colour { + const wchar_t *co_name; + short co_value; +} colour_t; + +extern style_t sy_header, + sy_status, + sy_entry, + sy_running, + sy_selected, + sy_date; + +extern short default_fg, default_bg; + +int attr_find (const wchar_t *name, attr_t *result); +int colour_find (const wchar_t *name, short *result); + +void style_clear (style_t *); +int style_set (style_t *, const wchar_t *fg, const wchar_t *bg); +int style_add (style_t *, const wchar_t *fg, const wchar_t *bg); + +void style_defaults (void); +void apply_styles (void); + +#endif /* !TTS_STYLE_H */ diff --git a/tailq.h b/tailq.h new file mode 100644 index 0000000..940f155 --- /dev/null +++ b/tailq.h @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * FreeBSD: release/9.0.0/sys/sys/queue.h 221843 2011-05-13 15:49:23Z mdf + */ + +#ifndef TTS_TAILQ_H +#define TTS_TAILQ_H + +/* + * Tail queue declarations. + */ +#define TTS_TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TTS_TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TTS_TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +#define TTS_TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TTS_TAILQ_INIT((head2)); \ + } \ +} while (0) + +#define TTS_TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TTS_TAILQ_FIRST(head) ((head)->tqh_first) + +#define TTS_TAILQ_FOREACH(var, head, field) \ + for ((var) = TTS_TAILQ_FIRST((head)); \ + (var); \ + (var) = TTS_TAILQ_NEXT((var), field)) + +#define TTS_TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TTS_TAILQ_FIRST((head)); \ + (var) && ((tvar) = TTS_TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TTS_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TTS_TAILQ_LAST((head), headname); \ + (var); \ + (var) = TTS_TAILQ_PREV((var), headname, field)) + +#define TTS_TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)\ + for ((var) = TTS_TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TTS_TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TTS_TAILQ_INIT(head) do { \ + TTS_TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TTS_TAILQ_FIRST((head)); \ +} while (0) + +#define TTS_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TTS_TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TTS_TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TTS_TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TTS_TAILQ_NEXT((elm), field); \ + } \ + TTS_TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TTS_TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TTS_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TTS_TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TTS_TAILQ_NEXT((elm), field); \ +} while (0) + +#define TTS_TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TTS_TAILQ_NEXT((elm), field) = TTS_TAILQ_FIRST((head))) != NULL) \ + TTS_TAILQ_FIRST((head))->field.tqe_prev = \ + &TTS_TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TTS_TAILQ_NEXT((elm), field); \ + TTS_TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TTS_TAILQ_FIRST((head)); \ +} while (0) + +#define TTS_TAILQ_INSERT_TAIL(head, elm, field) do { \ + TTS_TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TTS_TAILQ_NEXT((elm), field); \ +} while (0) + +#define TTS_TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TTS_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TTS_TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TTS_TAILQ_REMOVE(head, elm, field) do { \ + if ((TTS_TAILQ_NEXT((elm), field)) != NULL) \ + TTS_TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + } \ + *(elm)->field.tqe_prev = TTS_TAILQ_NEXT((elm), field); \ +} while (0) + +#define TTS_TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + + +#endif /* !TTS_TAILQ_H */ diff --git a/tts.c b/tts.c index 53eb15b..1a2b9ad 100644 --- a/tts.c +++ b/tts.c @@ -8,16 +8,8 @@ * warranty. */ -#define __EXTENSIONS__ -/* - * Older versions of glibc don't supporte _XOPEN_SOURCE==700 and require - * this for wcsdup() prototype. - */ -#define _GNU_SOURCE -#define _XOPEN_SOURCE 700 -#define _XOPEN_SOURCE_EXTENDED - #include +#include #include #include @@ -45,494 +37,134 @@ # include # include # include +# include + +# include # include # include -# include +# include #endif -#if defined HAVE_NCURSESW_CURSES_H -# include -#elif defined HAVE_NCURSESW_H -# include -#elif defined HAVE_NCURSES_CURSES_H -# include -#elif defined HAVE_NCURSES_H -# include -#elif defined HAVE_CURSES_H -# include -#else -# error "SVR4 or XSI compatible curses header file required" -#endif +#include "tailq.h" +#include "tts.h" +#include "entry.h" +#include "wide.h" +#include "tts_curses.h" +#include "ui.h" +#include "functions.h" +#include "commands.h" +#include "bindings.h" +#include "str.h" +#include "style.h" +#include "variable.h" -#include "queue.h" +volatile sig_atomic_t doexit; -#ifdef HAVE_CURSES_ENHANCED -# define WPFX(x) wcs##x -# define WIDE(x) L##x -# define ISX(x) isw##x -# define WCHAR wchar_t -# define FMT_L "l" -# define SNPRINTF swprintf -# define VSNPRINTF vswprintf -# define SSCANF swscanf -# define MEMCPY wmemcpy -# define MEMMOVE wmemmove -# define MBSTOWCS mbstowcs -# define WCSTOMBS wcstombs -# define FPRINTF fwprintf -# define STRTOK wcstok +time_t laststatus; -# define GETCH get_wch -# define WGETCH wget_wch -# define ADDSTR addwstr -# define WADDSTR waddwstr -# define INT wint_t -#else -# define WPFX(x) str##x -# define WIDE(x) x -# define ISX(x) is##x -# define WCHAR char -# define FMT_L -# define SNPRINTF snprintf -# define VSNPRINTF vsnprintf -# define SSCANF sscanf -# define MEMCPY memcpy -# define MEMMOVE memmove -# define MBSTOWCS strncpy -# define WCSTOMBS strncpy -# define FPRINTF fprintf -# define STRTOK strtok_r - -# define ADDSTR addstr -# define WADDSTR waddstr -# define INT int - -static int -tss_wgetch(win, d) - WINDOW *win; - int *d; -{ -int c; - if ((c = wgetch(win)) == ERR) - return ERR; - *d = c; - return OK; -} -# define WGETCH tss_wgetch -# define GETCH(c) tss_wgetch(stdscr,c) -#endif - -#define STRLEN WPFX(len) -#define STRCMP WPFX(cmp) -#define STRNCMP WPFX(ncmp) -#define STRCPY WPFX(cpy) -#define STRNCPY WPFX(ncpy) -#define STRSTR WPFX(str) -#define STRFTIME WPFX(ftime) -#define STRDUP WPFX(dup) -#define STRTOL WPFX(tol) - -#define ISSPACE ISX(space) - -#define WSIZEOF(s) (sizeof(s) / sizeof(WCHAR)) - -extern char const *tts_version; - -static volatile sig_atomic_t doexit; - -static WINDOW *titwin, *statwin, *listwin; - -static int in_curses; - -static void drawstatus(const WCHAR *msg, ...); -static void vdrawstatus(const WCHAR *msg, va_list); -static void drawheader(void); -static void drawentries(void); - -static time_t laststatus; - -typedef struct entry { - WCHAR *en_desc; - int en_secs; - time_t en_started; - time_t en_created; - - struct { - int efl_visible:1; - int efl_invoiced:1; - int efl_marked:1; - int efl_deleted:1; - int efl_nonbillable:1; - } en_flags; - TAILQ_ENTRY(entry) en_entries; -} entry_t; - -static TAILQ_HEAD(entrylist, entry) entries = TAILQ_HEAD_INITIALIZER(entries); - -static entry_t *running; - -static entry_t *entry_new(const WCHAR *); -static void entry_start(entry_t *); -static void entry_stop(entry_t *); -static void entry_free(entry_t *); -static void entry_account(entry_t *); -static time_t entry_time_for_day(time_t, int, int); - -#define time_day(t) (((t) / (60 * 60 * 24)) * (60 * 60 * 24)) -#define entry_day(e) (time_day((e)->en_created)) - -#define time_to_hms(t, h, m, s) do { \ - time_t n = t; \ - h = n / (60 * 60); \ - n %= (60 * 60); \ - m = n / 60; \ - n %= 60; \ - s = n; \ - } while (0) - -#define NHIST 50 -typedef struct histent { - WCHAR *he_text; - TAILQ_ENTRY(histent) he_entries; -} histent_t; -typedef TAILQ_HEAD(hentlist, histent) hentlist_t; - -typedef struct history { - int hi_nents; - hentlist_t hi_ents; -} history_t; - -static history_t *hist_new(void); -static void hist_add(history_t *, WCHAR const *); - -static history_t *searchhist, *prompthist; - -static WCHAR *prompt(WCHAR const *, WCHAR const *, history_t *); -static int prduration(WCHAR *prompt, int *h, int *m, int *s); -static int yesno(WCHAR const *); -static void errbox(WCHAR const *, ...); -static void verrbox(WCHAR const *, va_list); +history_t *searchhist; +history_t *prompthist; #define STATFILE ".rttts" #define RCFILE ".ttsrc" -static int load(void); -static int save(void); +int load(void); +int save(void); static time_t lastsave; static char statfile[PATH_MAX + 1]; static int load_file(const char *); -static void cursadvance(void); +int pagestart; +entry_t *curent; -static void kadd(void); -static void kaddold(void); -static void kquit(void); -static void kup(void); -static void kdown(void); -static void ktoggle(void); -static void kinvoiced(void); -static void kbillable(void); -static void keddesc(void); -static void kedtime(void); -static void ktoggleinv(void); -static void kcopy(void); -static void kaddtime(void); -static void kdeltime(void); -static void khelp(void); -static void kmark(void); -static void kunmarkall(void); -static void ksearch(void); -static void kmarkdel(void); -static void kundel(void); -static void ksync(void); -static void kexec(void); -static void kmerge(void); -static void kint(void); +int showinv = 0; -typedef struct function { - const WCHAR *fn_name; - void (*fn_hdl) (void); - const WCHAR *fn_desc; -} function_t; +static wchar_t *macro_text, *macro_pos; -static function_t funcs[] = { - { WIDE("help"), khelp, WIDE("display help screen") }, - { WIDE("add"), kadd, WIDE("add a new entry and start the timer") }, - { WIDE("add-old"), kaddold, WIDE("add a new entry and specify its duration") }, - { WIDE("delete"), kmarkdel, WIDE("delete the current entry") }, - { WIDE("undelete"), kundel, WIDE("undelete the current entry") }, - { WIDE("quit"), kquit, WIDE("exit TTS") }, - { WIDE("invoice"), kinvoiced, WIDE("toggle current entry as invoiced") }, - { WIDE("billable"), kbillable, WIDE("toggle current entry as billable") }, - { WIDE("mark"), kmark, WIDE("mark the current entry") }, - { WIDE("unmarkall"), kunmarkall, WIDE("unmark all entries") }, - { WIDE("startstop"), ktoggle, WIDE("start or stop the timer") }, - { WIDE("edit-desc"), keddesc, WIDE("edit the current entry's description") }, - { WIDE("edit-time"), kedtime, WIDE("edit the current entry's duration") }, - { WIDE("showhide-inv"), ktoggleinv, WIDE("show or hide invoiced entries") }, - { WIDE("copy"), kcopy, WIDE("copy the current entry's description to a new entry") }, - { WIDE("add-time"), kaddtime, WIDE("add time to the current entry") }, - { WIDE("sub-time"), kdeltime, WIDE("subtract time from the current entry") }, - { WIDE("search"), ksearch, WIDE("search for an entry by name") }, - { WIDE("sync"), ksync, WIDE("purge all deleted entries") }, - { WIDE("prev"), kup, WIDE("move to the previous entry") }, - { WIDE("next"), kdown, WIDE("move to the next entry") }, - { WIDE("execute"), kexec, WIDE("execute a configuration command") }, - { WIDE("merge"), kmerge, WIDE("merge marked entries into current entry") }, - { WIDE("interrupt"), kint, WIDE("split current entry into new entry")}, +time_t itime = 0; + +int show_billable = 0; +int delete_advance = 1; +int mark_advance = 1; +int bill_advance = 0; +int bill_increment = 0; +wchar_t *auto_nonbillable; +int time_format; + +variable_t variables[] = { + { L"delete_advance", VTYPE_BOOL, &delete_advance }, + { L"mark_advance", VTYPE_BOOL, &mark_advance }, + { L"billable_advance", VTYPE_BOOL, &bill_advance }, + { L"show_billable", VTYPE_BOOL, &show_billable }, + { L"auto_non_billable", VTYPE_STRING, &auto_nonbillable }, + { L"bill_increment", VTYPE_INT, &bill_increment }, + { L"time_format", VTYPE_INT, &time_format }, + { } }; -typedef struct tkey { - INT ky_code; - const WCHAR *ky_name; -} tkey_t; - -static tkey_t keys[] = { - { KEY_BREAK, WIDE("") }, - { KEY_DOWN, WIDE("") }, - { KEY_UP, WIDE("") }, - { KEY_LEFT, WIDE("") }, - { KEY_RIGHT, WIDE("") }, - { KEY_HOME, WIDE("") }, - { KEY_BACKSPACE, WIDE("") }, - { 0x7F, WIDE("") }, /* DEL */ - { KEY_F(0), WIDE("") }, - { KEY_F(1), WIDE("") }, - { KEY_F(2), WIDE("") }, - { KEY_F(3), WIDE("") }, - { KEY_F(4), WIDE("") }, - { KEY_F(5), WIDE("") }, - { KEY_F(6), WIDE("") }, - { KEY_F(7), WIDE("") }, - { KEY_F(8), WIDE("") }, - { KEY_F(9), WIDE("") }, - { KEY_F(10), WIDE("") }, - { KEY_F(11), WIDE("") }, - { KEY_F(12), WIDE("") }, - { KEY_F(13), WIDE("") }, - { KEY_F(14), WIDE("") }, - { KEY_F(15), WIDE("") }, - { KEY_F(16), WIDE("") }, - { KEY_F(17), WIDE("") }, - { KEY_F(18), WIDE("") }, - { KEY_F(19), WIDE("") }, - { KEY_F(20), WIDE("") }, - { KEY_F(21), WIDE("") }, - { KEY_F(22), WIDE("") }, - { KEY_F(23), WIDE("") }, - { KEY_F(24), WIDE("") }, - { KEY_NPAGE, WIDE("") }, - { KEY_PPAGE, WIDE("") }, - { '\001', WIDE("") }, - { '\002', WIDE("") }, - { '\003', WIDE("") }, - { '\004', WIDE("") }, - { '\005', WIDE("") }, - { '\006', WIDE("") }, - { '\007', WIDE("") }, - { '\010', WIDE("") }, - { '\011', WIDE("") }, - { '\011', WIDE("") }, - { '\012', WIDE("") }, - { '\013', WIDE("") }, - { '\014', WIDE("") }, - { '\015', WIDE("") }, - { '\016', WIDE("") }, - { '\017', WIDE("") }, - { '\020', WIDE("") }, - { '\021', WIDE("") }, - { '\022', WIDE("") }, - { '\023', WIDE("") }, - { '\024', WIDE("") }, - { '\025', WIDE("") }, - { '\026', WIDE("") }, - { '\027', WIDE("") }, - { '\030', WIDE("") }, - { '\031', WIDE("") }, - { ' ', WIDE("") }, - { KEY_ENTER, WIDE("") }, - { KEY_BACKSPACE, WIDE("") }, - { KEY_DC, WIDE("") } -}; - -typedef struct binding { - INT bi_code; - tkey_t *bi_key; - function_t *bi_func; - TAILQ_ENTRY(binding) bi_entries; -} binding_t; - -typedef struct command { - const WCHAR *cm_name; - void (*cm_hdl) (size_t, WCHAR **); -} command_t; - -static command_t *find_command(const WCHAR *); -static void c_bind(size_t, WCHAR **); -static void c_style(size_t, WCHAR **); -static void c_set(size_t, WCHAR **); - -static command_t commands[] = { - { WIDE("bind"), c_bind }, - { WIDE("style"), c_style }, - { WIDE("set"), c_set }, -}; - -static void cmderr(const WCHAR *, ...); -static void vcmderr(const WCHAR *, va_list); - -static size_t tokenise(const WCHAR *, WCHAR ***result); -static void tokfree(WCHAR ***); - -static TAILQ_HEAD(bindlist, binding) bindings = TAILQ_HEAD_INITIALIZER(bindings); - -static tkey_t *find_key(const WCHAR *name); -static function_t *find_func(const WCHAR *name); -static void bind_key(const WCHAR *key, const WCHAR *func); - -static int pagestart; -static entry_t *curent; - -static int showinv = 0; - -typedef struct style { - short sy_pair; - attr_t sy_attrs; -} style_t; - -#define style_fg(s) (COLOR_PAIR((s).sy_pair) | (s).sy_attrs) -#define style_bg(s) ((INT) ' ' | COLOR_PAIR((s).sy_pair) | ((s).sy_attrs & ~WA_UNDERLINE)) - -typedef struct attrname { - const WCHAR *an_name; - attr_t an_value; -} attrname_t; - -static attrname_t attrnames[] = { - { WIDE("normal"), WA_NORMAL }, - { WIDE("bold"), WA_BOLD }, - { WIDE("reverse"), WA_REVERSE }, - { WIDE("blink"), WA_BLINK }, - { WIDE("dim"), WA_DIM }, - { WIDE("underline"), WA_UNDERLINE }, - { WIDE("standout"), WA_STANDOUT } -}; - -typedef struct colour { - const WCHAR *co_name; - short co_value; -} colour_t; - -static colour_t colours[] = { - { WIDE("black"), COLOR_BLACK }, - { WIDE("red"), COLOR_RED }, - { WIDE("green"), COLOR_GREEN }, - { WIDE("yellow"), COLOR_YELLOW }, - { WIDE("blue"), COLOR_BLUE }, - { WIDE("magenta"), COLOR_MAGENTA }, - { WIDE("cyan"), COLOR_CYAN }, - { WIDE("white"), COLOR_WHITE } -}; - -static int attr_find(const WCHAR *name, attr_t *result); -static int colour_find(const WCHAR *name, short *result); - -static void style_clear(style_t *); -static int style_set(style_t *, const WCHAR *fg, const WCHAR *bg); -static int style_add(style_t *, const WCHAR *fg, const WCHAR *bg); - -static short default_fg, default_bg; - -static void apply_styles(void); - -static style_t - sy_header = { 1, 0 }, - sy_status = { 2, 0 }, - sy_entry = { 3, 0 }, - sy_running = { 4, 0 }, - sy_selected = { 5, 0 }, - sy_date = { 6, 0 }; - -static time_t itime = 0; - -static int show_billable = 0; -static int delete_advance = 1; -static int mark_advance = 1; -static int bill_advance = 0; -static int bill_increment = 0; -static WCHAR *auto_nonbillable; - -#define VTYPE_INT 1 -#define VTYPE_BOOL 2 -#define VTYPE_STRING 3 - -typedef struct variable { - WCHAR const *va_name; - int va_type; - void *va_addr; -} variable_t; - -static variable_t variables[] = { - { WIDE("delete_advance"), VTYPE_BOOL, &delete_advance }, - { WIDE("mark_advance"), VTYPE_BOOL, &mark_advance }, - { WIDE("billable_advance"), VTYPE_BOOL, &bill_advance }, - { WIDE("show_billable"), VTYPE_BOOL, &show_billable }, - { WIDE("auto_non_billable"), VTYPE_STRING, &auto_nonbillable }, - { WIDE("bill_increment"), VTYPE_INT, &bill_increment } -}; - -static variable_t *find_variable(const WCHAR *name); - #ifdef USE_DARWIN_POWER -static pthread_t power_thread; -static io_connect_t root_port; -static volatile sig_atomic_t donesleep; -static time_t sleeptime; +static IONotificationPortRef port_ref; +static io_object_t notifier; +static mach_port_t ioport; +static io_connect_t root_port; -static void *power_thread_run(void *); -static void power_event(void *, io_service_t, natural_t, void *); -static void prompt_sleep(void); +static void power_setup (struct kevent *); +static void power_handle (struct kevent *); +static void power_event (void *, io_service_t, natural_t, void *); +static void prompt_sleep (time_t); static void -sigsleep(sig) +power_setup(ev) + struct kevent *ev; { -/* Delivered from the power thread as SIGUSR1 */ - donesleep = 1; -} +mach_port_t pset; +int ret; -/* - * Darwin power notifications are delivered from IOKit via Mach ports, which - * is incompatible with TTS's curses-based main loop. We therefore spawn a - * separate thread to listen for these events, and when we receive one, we - * translate it into a signal (SIGUSR1) which is delivered to the main thread - * to handle. The signal will interrupt getch(). - */ -static void * -power_thread_run(arg) - void *arg; -{ -sigset_t ss; -IONotificationPortRef port_ref; -io_object_t notifier; - -/* Block SIGUSR1 so it's always delivered to the main thread, not us */ - sigemptyset(&ss); - sigaddset(&ss, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &ss, NULL); + if ((ret = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_PORT_SET, + &pset)) != KERN_SUCCESS) { + fprintf(stderr, "mach_port_allocate: %s [%x]\n", + mach_error_string(ret), ret); + exit(1); + } /* Register a handler for sleep and wake events */ root_port = IORegisterForSystemPower(NULL, &port_ref, power_event, ¬ifier); - CFRunLoopAddSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(port_ref), - kCFRunLoopCommonModes); - CFRunLoopRun(); + ioport = IONotificationPortGetMachPort(port_ref); + EV_SET(ev, pset, EVFILT_MACHPORT, EV_ADD, 0, 0, 0); - /*NOTREACHED*/ - return NULL; + if ((ret = mach_port_insert_member(mach_task_self(), ioport, + pset)) != KERN_SUCCESS) { + fprintf(stderr, "mach_port_insert_member: %s [%x]\n", + mach_error_string(ret), ret); + exit(1); + } +} + +static void +power_handle(ev) + struct kevent *ev; +{ +mach_msg_return_t ret; +void *msg = alloca(ev->data); + +/* Receive the message */ + memset(msg, 0, ev->data); + ret = mach_msg(msg, MACH_RCV_MSG, 0, ev->data, ioport, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + if (ret != MACH_MSG_SUCCESS) { + fprintf(stderr, "mach_msg: %s [%x]\n", + mach_error_string(ret), ret); + exit(1); + } + +/* Give the message to IOKit to handle */ + IODispatchCalloutFromMessage(NULL, msg, port_ref); } static void @@ -542,7 +174,6 @@ power_event(ref, service, msgtype, arg) natural_t msgtype; { static time_t sleep_started; -time_t diff; switch (msgtype) { case kIOMessageSystemWillSleep: @@ -553,12 +184,9 @@ time_t diff; case kIOMessageSystemHasPoweredOn: /* System has finished wake-up; calculate the sleep time and - * notify the main thread. + * prompt the user. */ - time(&diff); - diff -= sleep_started; - sleeptime += diff; - raise(SIGUSR1); + prompt_sleep(time(NULL) - sleep_started); break; } } @@ -576,17 +204,35 @@ main(argc, argv) { struct passwd *pw; char rcfile[PATH_MAX + 1]; +#ifdef USE_DARWIN_POWER +int kq; +struct kevent evs[2], rev; +# define STDIN_EV 0 +# define IOKIT_EV 1 +#endif setlocale(LC_ALL, ""); +#ifdef USE_DARWIN_POWER + if ((kq = kqueue()) == -1) { + perror("kqueue"); + return 1; + } + + memset(evs, 0, sizeof(evs)); + + EV_SET(&evs[STDIN_EV], STDIN_FILENO, EVFILT_READ, EV_ADD, 0, 0, 0); + power_setup(&evs[IOKIT_EV]); + + if (kevent(kq, evs, 2, NULL, 0, NULL) == -1) { + perror("kevent"); + return 1; + } +#endif + signal(SIGTERM, sigexit); signal(SIGINT, sigexit); -#ifdef USE_DARWIN_POWER - signal(SIGUSR1, sigsleep); - pthread_create(&power_thread, NULL, power_thread_run, NULL); -#endif - searchhist = hist_new(); prompthist = hist_new(); @@ -598,88 +244,15 @@ char rcfile[PATH_MAX + 1]; snprintf(statfile, sizeof(statfile), "%s/%s", pw->pw_dir, STATFILE); snprintf(rcfile, sizeof(rcfile), "%s/%s", pw->pw_dir, RCFILE); - initscr(); - in_curses = 1; - start_color(); -#ifdef HAVE_USE_DEFAULT_COLORS - use_default_colors(); -#endif - cbreak(); - noecho(); - nonl(); - halfdelay(5); - - pair_content(0, &default_fg, &default_bg); - - refresh(); - - intrflush(stdscr, TRUE); - keypad(stdscr, TRUE); - leaveok(stdscr, TRUE); - - titwin = newwin(1, 0, 0, 0); - intrflush(titwin, FALSE); - keypad(titwin, TRUE); - leaveok(titwin, TRUE); - - statwin = newwin(1, 0, LINES - 1, 0); - intrflush(statwin, FALSE); - keypad(statwin, TRUE); - leaveok(statwin, TRUE); - - listwin = newwin(LINES - 2, 0, 1, 0); - intrflush(listwin, FALSE); - keypad(listwin, TRUE); - leaveok(listwin, TRUE); - - init_pair(1, default_fg, default_bg); - init_pair(2, default_fg, default_bg); - init_pair(3, default_fg, default_bg); - init_pair(4, default_fg, default_bg); - init_pair(5, default_fg, default_bg); - init_pair(6, default_fg, default_bg); - - style_set(&sy_header, WIDE("reverse"), NULL); - style_set(&sy_status, WIDE("normal"), NULL); - style_set(&sy_entry, WIDE("normal"), NULL); - style_set(&sy_selected, WIDE("normal"), NULL); - style_set(&sy_running, WIDE("bold"), NULL); - style_set(&sy_date, WIDE("underline"), NULL); - apply_styles(); + ui_init(); + style_defaults(); if (load_file(rcfile) == -1) { endwin(); return 1; } - curs_set(0); - - bind_key(WIDE("?"), WIDE("help")); - bind_key(WIDE("a"), WIDE("add")); - bind_key(WIDE("A"), WIDE("add-old")); - bind_key(WIDE("d"), WIDE("delete")); - bind_key(WIDE("u"), WIDE("undelete")); - bind_key(WIDE("q"), WIDE("quit")); - bind_key(WIDE(""), WIDE("quit")); - bind_key(WIDE("i"), WIDE("invoice")); - bind_key(WIDE("b"), WIDE("billable")); - bind_key(WIDE("m"), WIDE("mark")); - bind_key(WIDE("U"), WIDE("unmarkall")); - bind_key(WIDE(""), WIDE("startstop")); - bind_key(WIDE("e"), WIDE("edit-desc")); - bind_key(WIDE("\\"), WIDE("edit-time")); - bind_key(WIDE(""), WIDE("showhide-inv")); - bind_key(WIDE("c"), WIDE("copy")); - bind_key(WIDE("+"), WIDE("add-time")); - bind_key(WIDE("-"), WIDE("sub-time")); - bind_key(WIDE("/"), WIDE("search")); - bind_key(WIDE("$"), WIDE("sync")); - bind_key(WIDE(""), WIDE("prev")); - bind_key(WIDE(""), WIDE("next")); - bind_key(WIDE(":"), WIDE("execute")); - bind_key(WIDE("M"), WIDE("merge")); - bind_key(WIDE("r"), WIDE("interrupt")); - bind_key(WIDE("R"), WIDE("interrupt")); + bind_defaults(); /* * Make sure we can save (even if it's an empty file or nothing has @@ -689,61 +262,98 @@ char rcfile[PATH_MAX + 1]; save(); drawheader(); - drawstatus(WIDE("")); + drawstatus(L""); - if (!TAILQ_EMPTY(&entries)) { - curent = TAILQ_FIRST(&entries); + if (!TTS_TAILQ_EMPTY(&entries)) { + curent = TTS_TAILQ_FIRST(&entries); while (!showinv && curent->en_flags.efl_invoiced) - if ((curent = TAILQ_NEXT(curent, en_entries)) == NULL) + if ((curent = TTS_TAILQ_NEXT(curent, en_entries)) == NULL) break; } for (;;) { - INT c; + wint_t c; binding_t *bi; +#ifdef USE_DARWIN_POWER + struct timespec timeout; + int nev; +#else + fd_set in_set; + struct timeval timeout; +#endif if (doexit) break; -#ifdef USE_DARWIN_POWER - if (donesleep) - prompt_sleep(); -#endif - drawheader(); drawentries(); wrefresh(listwin); - if (GETCH(&c) == ERR) { +#ifdef USE_DARWIN_POWER + timeout.tv_sec = 0; + timeout.tv_nsec = 500000000; + + if ((nev = kevent(kq, NULL, 0, &rev, 1, &timeout)) == -1) { if (doexit) break; -#ifdef USE_DARWIN_POWER - if (donesleep) - prompt_sleep(); -#endif - if (time(NULL) - laststatus >= 2) - drawstatus(WIDE("")); - if (time(NULL) - lastsave > 60) - save(); - continue; - } - -#ifdef KEY_RESIZE - if (c == KEY_RESIZE) - continue; -#endif - - drawstatus(WIDE("")); - - TAILQ_FOREACH(bi, &bindings, bi_entries) { - if (bi->bi_code != c) + if (errno == EINTR) continue; - bi->bi_func->fn_hdl(); - goto next; + perror("kevent"); + return 1; } - drawstatus(WIDE("Unknown command.")); - next: ; + if (nev == 1 && (rev.filter == EVFILT_MACHPORT)) { + power_handle(&rev); + continue; + } +#else + /* Wait for input to be ready. */ + FD_ZERO(&in_set); + FD_SET(STDIN_FILENO, &in_set); + + timeout.tv_sec = 0; + timeout.tv_usec = 500000; + + if (select(STDIN_FILENO + 1, &in_set, NULL, NULL, &timeout) == -1) { + if (doexit) + break; + if (errno == EINTR) + continue; + } +#endif + + while (input_char(stdscr, &c) != ERR) { +#ifdef KEY_RESIZE + if (c == KEY_RESIZE) + continue; +#endif + + drawstatus(L""); + + TTS_TAILQ_FOREACH(bi, &bindings, bi_entries) { + if (bi->bi_code != c) + continue; + + if (!macro_text && bi->bi_macro) + input_macro(bi->bi_macro); + else if (bi->bi_func) + bi->bi_func->fn_hdl(); + + goto next; + } + + drawstatus(L"Unknown command."); + next: ; + } + + if (doexit) + break; + + if (time(NULL) - laststatus >= 2) + drawstatus(L""); + + if (time(NULL) - lastsave > 60) + save(); } save(); @@ -751,1389 +361,55 @@ char rcfile[PATH_MAX + 1]; return 0; } -void -kquit() -{ -entry_t *en; -int ndel = 0; - - TAILQ_FOREACH(en, &entries, en_entries) { - if (en->en_flags.efl_deleted) - ndel++; - } - - if (ndel) { - WCHAR s[128]; - SNPRINTF(s, WSIZEOF(s), WIDE("Purge %d deleted entries?"), ndel); - if (yesno(s)) { - ksync(); - } - } - - doexit = 1; -} - -void -kadd() -{ -WCHAR *name; -entry_t *en; - name = prompt(WIDE("Description:"), NULL, NULL); - if (!name || !*name) { - free(name); - return; - } - en = entry_new(name); - entry_start(en); - curent = en; - save(); -} - -void -kaddold() -{ -WCHAR *name; -entry_t *en; - name = prompt(WIDE("Description:"), NULL, NULL); - - if (!name || !*name) { - free(name); - return; - } - - en = entry_new(name); - curent = en; - kedtime(); - save(); -} - -void -ktoggle() -{ - itime = 0; - - if (!curent) - return; - - if (curent == running) { - entry_stop(curent); - save(); - return; - } - - if (running) - entry_stop(running); - entry_start(curent); - save(); -} - -void -kundel() -{ - if (!curent) - return; - - curent->en_flags.efl_deleted = 0; - if (delete_advance) - cursadvance(); -} - -void -kmarkdel() -{ -entry_t *en; -int nmarked = 0; - - TAILQ_FOREACH(en, &entries, en_entries) { - if (en->en_flags.efl_marked) { - nmarked++; - en->en_flags.efl_deleted = 1; - } - } - - if (nmarked) - return; - - if (!curent) { - drawstatus(WIDE("No entries to delete.")); - return; - } - - curent->en_flags.efl_deleted = 1; - - if (delete_advance) - cursadvance(); -} - -/* - * Move the cursor to the next entry after an operation like mark or deleted. - * If there are no suitable entries after this one, move it backwards instead. - */ -void -cursadvance() -{ -entry_t *en; - - if (!curent) { - curent = TAILQ_FIRST(&entries); - return; - } - - /* - * Try to find the next suitable entry to move the cursor to. - */ - for (en = TAILQ_NEXT(curent, en_entries); en; en = TAILQ_NEXT(en, en_entries)) { - if (!showinv && en->en_flags.efl_invoiced) - continue; - curent = en; - if (!curent->en_flags.efl_visible) - pagestart++; - return; - } - - /* - * No entries; if the current entry is visible, stay here, otherwise - * try moving backwards instead. - */ - if (showinv || !curent->en_flags.efl_invoiced) - return; - - for (en = TAILQ_PREV(curent, entrylist, en_entries); en; - en = TAILQ_PREV(en, entrylist, en_entries)) { - if (!showinv && en->en_flags.efl_invoiced) - continue; - curent = en; - if (!curent->en_flags.efl_visible) - pagestart--; - return; - } - - /* - * Couldn't find any entries at all? - */ - curent = NULL; -} - -void -ksync() -{ -entry_t *en, *ten; - - TAILQ_FOREACH_SAFE(en, &entries, en_entries, ten) { - if (!en->en_flags.efl_deleted) - continue; - if (en == curent) - curent = NULL; - TAILQ_REMOVE(&entries, en, en_entries); - entry_free(en); - } - - if (curent == NULL) - curent = TAILQ_FIRST(&entries); - save(); -} - -void -kup() -{ -entry_t *prev = curent; - if (!curent) - return; - - do { - if ((prev = TAILQ_PREV(prev, entrylist, en_entries)) == NULL) - break; - } while (!showinv && prev->en_flags.efl_invoiced); - - if (prev == NULL) { - drawstatus(WIDE("Already at first entry.")); - return; - } - - curent = prev; - if (!curent->en_flags.efl_visible) - pagestart--; -} - -void -kdown() -{ -entry_t *next = curent; - if (!curent) - return; - - do { - if ((next = TAILQ_NEXT(next, en_entries)) == NULL) - break; - } while (!showinv && next->en_flags.efl_invoiced); - - if (next == NULL) { - drawstatus(WIDE("Already at last entry.")); - return; - } - - curent = next; - if (!curent->en_flags.efl_visible) - pagestart++; -} - -void -kinvoiced() -{ -entry_t *en; -int anymarked = 0; - - TAILQ_FOREACH(en, &entries, en_entries) { - if (!en->en_flags.efl_marked) - continue; - anymarked = 1; - en->en_flags.efl_invoiced = !en->en_flags.efl_invoiced; - en->en_flags.efl_marked = 0; - } - - if (anymarked) { - save(); - return; - } - - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - curent->en_flags.efl_invoiced = !curent->en_flags.efl_invoiced; - save(); - - en = curent; - - if (showinv) { - if (TAILQ_NEXT(curent, en_entries) != NULL) - curent = TAILQ_NEXT(curent, en_entries); - return; - } - - /* - * Try to find the next uninvoiced request to move the cursor to. - */ - for (;;) { - if ((curent = TAILQ_NEXT(curent, en_entries)) == NULL) - break; /* end of list */ - if (!curent->en_flags.efl_invoiced) - return; - } - - /* - * We didn't find any, so try searching backwards instead. - */ - for (curent = en;;) { - if ((curent = TAILQ_PREV(curent, entrylist, en_entries)) == NULL) - break; /* end of list */ - if (!curent->en_flags.efl_invoiced) - return; - } -} - -void -kbillable() -{ -entry_t *en; -int anymarked = 0; - - TAILQ_FOREACH(en, &entries, en_entries) { - if (!en->en_flags.efl_marked) - continue; - anymarked = 1; - en->en_flags.efl_nonbillable = !en->en_flags.efl_nonbillable; - en->en_flags.efl_marked = 0; - } - - if (anymarked) { - save(); - return; - } - - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - curent->en_flags.efl_nonbillable = !curent->en_flags.efl_nonbillable; - save(); - - if (bill_advance) - cursadvance(); -} - -void -keddesc() -{ -WCHAR *new; - - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - if ((new = prompt(WIDE("Description:"), curent->en_desc, NULL)) == NULL) - return; - - free(curent->en_desc); - curent->en_desc = new; - save(); -} - -void -kedtime() -{ -WCHAR *new, old[64]; -time_t n; -int h, m, s; - - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - n = curent->en_secs; - if (curent->en_started) - n += time(NULL) - curent->en_started; - h = n / (60 * 60); - n %= (60 * 60); - m = n / 60; - n %= 60; - s = n; - - SNPRINTF(old, WSIZEOF(old), WIDE("%02d:%02d:%02d"), h, m, s); - if ((new = prompt(WIDE("Duration [HH:MM:SS]:"), old, NULL)) == NULL) - return; - - if (!SSCANF(new, WIDE("%d:%d:%d"), &h, &m, &s)) { - free(new); - drawstatus(WIDE("Invalid duration.")); - } - - curent->en_secs = (h * 60 * 60) + (m * 60) + s; - if (curent->en_started) - time(&curent->en_started); - - save(); -} - -void -ktoggleinv() -{ -entry_t *en = curent; - showinv = !showinv; - drawstatus(WIDE("%"FMT_L"s invoiced entries."), - showinv ? L"Showing" : L"Hiding"); - - if (curent && !curent->en_flags.efl_invoiced) - return; - - if (!curent) { - curent = TAILQ_FIRST(&entries); - return; - } - - /* - * Try to find the next uninvoiced request to move the cursor to. - */ - for (;;) { - if ((curent = TAILQ_NEXT(curent, en_entries)) == NULL) - break; /* end of list */ - if (!curent->en_flags.efl_invoiced) - return; - } - - /* - * We didn't find any, so try searching backwards instead. - */ - for (curent = en;;) { - if ((curent = TAILQ_PREV(curent, entrylist, en_entries)) == NULL) - break; /* end of list */ - if (!curent->en_flags.efl_invoiced) - return; - } -} - -void -kcopy() -{ -entry_t *en; - - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - en = entry_new(curent->en_desc); - curent = en; - entry_start(en); - save(); -} - -void -kaddtime() -{ -WCHAR *tstr; -int h = 0, m = 0, s = 0, secs; - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - if ((tstr = prompt(WIDE("Time to add ([[HH:]MM:]SS):"), NULL, NULL)) == NULL) - return; - - if (!*tstr) { - drawstatus(WIDE("")); - free(tstr); - return; - } - - if (SSCANF(tstr, WIDE("%d:%d:%d"), &h, &m, &s) != 3) { - h = 0; - if (SSCANF(tstr, WIDE("%d:%d"), &m, &s) != 2) { - m = 0; - if (SSCANF(tstr, WIDE("%d"), &s) != 1) { - free(tstr); - drawstatus(WIDE("Invalid time format.")); - return; - } - } - } - - free(tstr); - - if (m >= 60) { - drawstatus(WIDE("Minutes cannot be more than 59.")); - return; - } - - if (s >= 60) { - drawstatus(WIDE("Seconds cannot be more than 59.")); - return; - } - - secs = s + m*60 + h*60*60; - curent->en_secs += secs; - save(); -} - -void -kdeltime() -{ -WCHAR *tstr; -int h = 0, m = 0, s = 0, secs; - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - if ((tstr = prompt(WIDE("Time to subtract, ([[HH:]MM:]SS):"), NULL, NULL)) == NULL) - return; - - if (!*tstr) { - drawstatus(WIDE("")); - free(tstr); - return; - } - - if (SSCANF(tstr, WIDE("%d:%d:%d"), &h, &m, &s) != 3) { - h = 0; - if (SSCANF(tstr, WIDE("%d:%d"), &m, &s) != 2) { - m = 0; - if (SSCANF(tstr, WIDE("%d"), &s) != 1) { - free(tstr); - drawstatus(WIDE("Invalid time format.")); - return; - } - } - } - - free(tstr); - if (m >= 60) { - drawstatus(WIDE("Minutes cannot be more than 59.")); - return; - } - - if (s >= 60) { - drawstatus(WIDE("Seconds cannot be more than 59.")); - return; - } - - entry_account(curent); - - secs = s + m*60 + h*60*60; - if (curent->en_secs - secs < 0) { - drawstatus(WIDE("Remaining time cannot be less than zero.")); - return; - } - - curent->en_secs -= secs; - save(); -} - -void -kmerge() -{ -entry_t *en, *ten; -int nmarked = 0; -WCHAR pr[128]; -int h, m, s = 0; - - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - /* - * Count number of marked entries and the summed time. - */ - TAILQ_FOREACH(en, &entries, en_entries) { - if (!en->en_flags.efl_marked || en == curent) - continue; - nmarked++; - s += en->en_secs; - if (en->en_started) - s += time(NULL) - en->en_started; - } - - if (nmarked == 0) { - drawstatus(WIDE("No marked entries.")); - return; - } - - h = s / (60 * 60); - s %= (60 * 60); - m = s / 60; - s %= 60; - - SNPRINTF(pr, WSIZEOF(pr), WIDE("Merge %d marked entries [%02d:%02d:%02d] into current entry?"), - nmarked, h, m, s); - if (!yesno(pr)) - return; - - TAILQ_FOREACH_SAFE(en, &entries, en_entries, ten) { - if (!en->en_flags.efl_marked || en == curent) - continue; - curent->en_secs += en->en_secs; - if (en->en_started) { - entry_stop(en); - curent->en_secs += time(NULL) - en->en_started; - } - TAILQ_REMOVE(&entries, en, en_entries); - entry_free(en); - } - save(); -} - -void -khelp() -{ -WINDOW *hwin; -size_t nhelp = 0; -WCHAR **help; -#define HTITLE WIDE(" TTS keys ") -size_t width = 0; -size_t i; -INT c; -binding_t *bi; - /* Count the number of bindings */ - TAILQ_FOREACH(bi, &bindings, bi_entries) - nhelp++; - help = calloc(nhelp, sizeof(const WCHAR *)); - - i = 0; - TAILQ_FOREACH(bi, &bindings, bi_entries) { - WCHAR s[128]; - if (bi->bi_key) - SNPRINTF(s, WSIZEOF(s), WIDE("%-10"FMT_L"s %"FMT_L"s (%"FMT_L"s)"), - bi->bi_key->ky_name, bi->bi_func->fn_desc, - bi->bi_func->fn_name); - else - SNPRINTF(s, WSIZEOF(s), WIDE("%"FMT_L"c %"FMT_L"s (%"FMT_L"s)"), - bi->bi_code, bi->bi_func->fn_desc, bi->bi_func->fn_name); - help[i] = STRDUP(s); - i++; - } - - if (nhelp > (LINES - 6)) - nhelp = LINES - 6; - - for (i = 0; i < nhelp; i++) - if (STRLEN(help[i]) > width) - width = STRLEN(help[i]); - - hwin = newwin(nhelp + 4, width + 4, - (LINES / 2) - ((nhelp + 2) / 2), - (COLS / 2) - ((width + 2) / 2)); - wborder(hwin, 0, 0, 0, 0, 0, 0, 0, 0); - - wattron(hwin, A_REVERSE | A_BOLD); - wmove(hwin, 0, (width / 2) - (WSIZEOF(HTITLE) - 1)/2); - WADDSTR(hwin, HTITLE); - wattroff(hwin, A_REVERSE | A_BOLD); - - for (i = 0; i < nhelp; i++) { - wmove(hwin, i + 2, 2); - WADDSTR(hwin, help[i]); - } - - wrefresh(hwin); - - while (WGETCH(hwin, &c) == ERR -#ifdef KEY_RESIZE - || (c == KEY_RESIZE) -#endif - ) - ; - - delwin(hwin); - - for (i = 0; i < nhelp; i++) - free(help[i]); - free(help); -} - -void -kmark() -{ - if (!curent) { - drawstatus(WIDE("No entry selected.")); - return; - } - - curent->en_flags.efl_marked = !curent->en_flags.efl_marked; - - if (mark_advance) - cursadvance(); -} - -void -kunmarkall() -{ -entry_t *en; - TAILQ_FOREACH(en, &entries, en_entries) - en->en_flags.efl_marked = 0; -} - -void -kint() -{ -time_t duration; -entry_t *en; -WCHAR *name; - - if (!itime) { - if (!running) { - drawstatus(WIDE("No running entry.")); - return; - } - - itime = time(NULL); - return; - } - - if (!running) { - drawstatus(WIDE("No running entry.")); - return; - } - - name = prompt(WIDE("Description:"), NULL, NULL); - - if (!name || !*name) { - itime = 0; - free(name); - return; - } - - if (itime) { - duration = time(NULL) - itime; - } else { - int h, m, s; - if (prduration(WIDE("Duration [HH:MM:SS]:"), &h, &m, &s) == -1) - return; - - duration = (h * 60 * 60) + (m * 60) + s; - } - - itime = 0; - running->en_secs += (time(NULL) - running->en_started); - running->en_started = time(NULL); - running->en_secs -= duration; - - en = entry_new(name); - en->en_created = time(NULL) - duration; - en->en_secs = duration; - save(); - - free(name); -} - -void -ksearch() -{ -static WCHAR *lastsearch; -WCHAR *term; -entry_t *start, *cur; - - if (!curent) { - drawstatus(WIDE("No entries.")); - return; - } - - if ((term = prompt(WIDE("Search:"), NULL, NULL)) == NULL) - return; - - if (!*term) { - free(term); - if (!lastsearch) - return; - - term = lastsearch; - } else { - free(lastsearch); - lastsearch = term; - } - - cur = start = curent; - - for (;;) { - cur = TAILQ_NEXT(cur, en_entries); - if (cur == NULL) { - drawstatus(WIDE("Search reached last entry, continuing from top.")); - cur = TAILQ_FIRST(&entries); - } - - if (cur == start) { - drawstatus(WIDE("No matches.")); - break; - } - - if (STRSTR(cur->en_desc, term)) { - curent = cur; - if (!showinv && cur->en_flags.efl_invoiced) - showinv = 1; - return; - } - - } -} - -void -kexec() -{ -WCHAR *cmd; -WCHAR **args; -command_t *cmds; -size_t nargs; - - if ((cmd = prompt(WIDE(":"), NULL, NULL)) == NULL || !*cmd) { - free(cmd); - return; - } - - nargs = tokenise(cmd, &args); - free(cmd); - - if (nargs == 0) { - tokfree(&args); - return; - } - - if ((cmds = find_command(args[0])) == NULL) { - drawstatus(WIDE("Unknown command.")); - tokfree(&args); - return; - } - - cmds->cm_hdl(nargs, args); - tokfree(&args); -} - -void -drawheader() -{ -WCHAR title[64]; - - SNPRINTF(title, WSIZEOF(title), WIDE("TTS %s - Type '?' for help"), - tts_version); - wmove(titwin, 0, 0); - WADDSTR(titwin, title); - - if (itime > 0) { - WCHAR str[128]; - int h, m, s; - time_t passed = time(NULL) - itime; - - time_to_hms(passed, h, m, s); - SNPRINTF(str, WSIZEOF(str), WIDE(" *** MARK INTERRUPT: %02d:%02d:%02d ***"), - h, m, s); - - wattron(titwin, A_BOLD); - WADDSTR(titwin, str); - wattroff(titwin, A_BOLD); - } - wclrtoeol(titwin); - wrefresh(titwin); -} - -void -vdrawstatus(msg, ap) - const WCHAR *msg; - va_list ap; -{ -WCHAR s[1024]; - VSNPRINTF(s, WSIZEOF(s), msg, ap); - - wmove(statwin, 0, 0); - WADDSTR(statwin, s); - wclrtoeol(statwin); - wrefresh(statwin); - time(&laststatus); -} - -void -drawstatus(const WCHAR *msg, ...) -{ -va_list ap; - va_start(ap, msg); - vdrawstatus(msg, ap); - va_end(ap); -} - -int -yesno(msg) - const WCHAR *msg; -{ -WINDOW *pwin; -INT c; - - pwin = newwin(1, COLS, LINES - 2, 0); - keypad(pwin, TRUE); - wattron(pwin, A_BOLD); - wmove(pwin, 0, 0); - WADDSTR(pwin, msg); - WADDSTR(pwin, WIDE(" [y/N]? ")); - wattroff(pwin, A_BOLD); - - while (WGETCH(pwin, &c) == ERR -#ifdef KEY_RESIZE - || (c == KEY_RESIZE) -#endif - ) - ; - - return (c == 'Y' || c == 'y') ? 1 : 0; -} - -WCHAR * -prompt(msg, def, hist) - const WCHAR *msg, *def; - history_t *hist; -{ -WINDOW *pwin; -WCHAR input[256]; -size_t pos = 0; -histent_t *histpos = NULL; - - if (hist == NULL) - hist = prompthist; - - memset(input, 0, sizeof(input)); - if (def) { - STRNCPY(input, def, WSIZEOF(input) - 1); - pos = STRLEN(input); - } - - pwin = newwin(1, COLS, LINES - 2, 0); - keypad(pwin, TRUE); - - wattr_on(pwin, style_fg(sy_status), NULL); - wbkgd(pwin, style_bg(sy_status)); - - wattron(pwin, A_BOLD); - wmove(pwin, 0, 0); - WADDSTR(pwin, msg); - wattroff(pwin, A_BOLD); - - curs_set(1); - - for (;;) { - INT c; - wmove(pwin, 0, STRLEN(msg) + 1); - WADDSTR(pwin, input); - wclrtoeol(pwin); - wmove(pwin, 0, STRLEN(msg) + 1 + pos); - wrefresh(pwin); - - if (WGETCH(pwin, &c) == ERR) - continue; - - switch (c) { - case '\n': - case '\r': - goto end; - - case KEY_BACKSPACE: - case 0x7F: - case 0x08: - if (pos) { - if (pos == STRLEN(input)) - input[--pos] = 0; - else { - int i = STRLEN(input); - pos--; - MEMCPY(input + pos, input + pos + 1, STRLEN(input) - pos); - input[i] = 0; - } - } - break; - - case KEY_DC: - if (pos < STRLEN(input)) { - int i = STRLEN(input); - MEMCPY(input + pos, input + pos + 1, STRLEN(input) - pos); - input[i] = 0; - } - break; - - case KEY_LEFT: - if (pos) - pos--; - break; - - case KEY_RIGHT: - if (pos < STRLEN(input)) - pos++; - break; - - case KEY_HOME: - case 0x01: /* ^A */ - pos = 0; - break; - - case KEY_END: - case 0x05: /* ^E */ - pos = STRLEN(input); - break; - - case 0x07: /* ^G */ - case 0x1B: /* ESC */ - curs_set(0); - delwin(pwin); - return NULL; - - case 0x15: /* ^U */ - input[0] = 0; - pos = 0; - break; - -#ifdef KEY_RESIZE - case KEY_RESIZE: - break; -#endif - - case KEY_UP: - if (histpos == NULL) { - if ((histpos = TAILQ_LAST(&hist->hi_ents, hentlist)) == NULL) { - beep(); - break; - } - } else { - if (TAILQ_PREV(histpos, hentlist, he_entries) == NULL) { - beep(); - break; - } else - histpos = TAILQ_PREV(histpos, hentlist, he_entries); - } - - - STRNCPY(input, histpos->he_text, WSIZEOF(input) - 1); - pos = STRLEN(input); - break; - - case KEY_DOWN: - if (histpos == NULL) { - beep(); - break; - } - - if (TAILQ_NEXT(histpos, he_entries) == NULL) { - beep(); - break; - } else - histpos = TAILQ_NEXT(histpos, he_entries); - - - STRNCPY(input, histpos->he_text, WSIZEOF(input) - 1); - pos = STRLEN(input); - break; - - default: - if (pos != STRLEN(input)) { - MEMMOVE(input + pos + 1, input + pos, STRLEN(input) - pos); - input[pos++] = c; - } else { - input[pos++] = c; - input[pos] = 0; - } - - break; - } - } -end: ; - - curs_set(0); - delwin(pwin); - wtouchln(statwin, 1, 1, 1); - hist_add(hist, input); - return STRDUP(input); -} - -void -drawentries() -{ -int i, nlines; -int cline = 0; -time_t lastday = 0; -entry_t *en; -chtype oldbg; - - getmaxyx(listwin, nlines, i); - - TAILQ_FOREACH(en, &entries, en_entries) - en->en_flags.efl_visible = 0; - - en = TAILQ_FIRST(&entries); - for (i = 0; i < pagestart; i++) - if ((en = TAILQ_NEXT(en, en_entries)) == NULL) - return; - - for (; en; en = TAILQ_NEXT(en, en_entries)) { - time_t n; - int h, s, m; - WCHAR flags[10], stime[16], *p; - attr_t attrs = WA_NORMAL; - - if (!showinv && en->en_flags.efl_invoiced) - continue; - - oldbg = getbkgd(listwin); - - if (lastday != entry_day(en)) { - struct tm *lt; - WCHAR lbl[128]; - time_t itime = entry_time_for_day(entry_day(en), 1, 0), - ntime = entry_time_for_day(entry_day(en), 0, 0), - btime = entry_time_for_day(entry_day(en), 2, bill_increment); - int hi, mi, si, - hn, mn, sn, - hb, mb, sb, - ht, mt, st; - WCHAR hdrtext[256]; - - time_to_hms(itime, hi, mi, si); - time_to_hms(ntime, hn, mn, sn); - time_to_hms(btime, hb, mb, sb); - time_to_hms(itime + ntime, ht, mt, st); - - oldbg = getbkgd(listwin); - wbkgdset(listwin, style_bg(sy_entry)); - wattr_on(listwin, style_fg(sy_entry), NULL); - - wmove(listwin, cline, 0); - wclrtoeol(listwin); - - wbkgdset(listwin, oldbg); - wattr_off(listwin, style_fg(sy_entry), NULL); - - if (++cline >= nlines) - break; - - lastday = entry_day(en); - lt = localtime(&lastday); - - STRFTIME(lbl, WSIZEOF(lbl), WIDE("%A, %d %B %Y"), lt); - if (show_billable) - SNPRINTF(hdrtext, WSIZEOF(hdrtext), - WIDE("%-30"FMT_L"s [I:%02d:%02d:%02d / " - "N:%02d:%02d:%02d / T:%02d:%02d:%02d / " - "B:%02d:%02d:%02d]"), - lbl, hi, mi, si, hn, mn, sn, ht, mt, st, - hb, mb, sb); - else - SNPRINTF(hdrtext, WSIZEOF(hdrtext), - WIDE("%-30"FMT_L"s [I:%02d:%02d:%02d / " - "N:%02d:%02d:%02d / T:%02d:%02d:%02d]"), - lbl, hi, mi, si, hn, mn, sn, ht, mt, st); - - wattr_on(listwin, style_fg(sy_date), NULL); - wbkgdset(listwin, style_bg(sy_date)); - wmove(listwin, cline, 0); - WADDSTR(listwin, hdrtext); - wclrtoeol(listwin); - wattr_off(listwin, style_fg(sy_date), NULL); - wbkgdset(listwin, oldbg); - - if (++cline >= nlines) { - wbkgdset(listwin, oldbg); - wattr_off(listwin, style_fg(sy_date), NULL); - break; - } - - oldbg = getbkgd(listwin); - wbkgdset(listwin, style_bg(sy_entry)); - wattr_on(listwin, style_fg(sy_entry), NULL); - - wmove(listwin, cline, 0); - wclrtoeol(listwin); - - wbkgdset(listwin, oldbg); - wattr_off(listwin, style_fg(sy_entry), NULL); - - if (++cline >= nlines) - break; - } - - en->en_flags.efl_visible = 1; - wmove(listwin, cline, 0); - - attrs = style_fg(sy_entry); - - if (en->en_started && en == curent) - attrs = style_fg(sy_selected) | - (style_fg(sy_running) & ( - WA_STANDOUT | WA_UNDERLINE | - WA_REVERSE | WA_BLINK | WA_DIM | - WA_BOLD)); - else if (en->en_started) - attrs = style_fg(sy_running); - else if (en == curent) - attrs = style_fg(sy_selected); - - wbkgdset(listwin, ' ' | (attrs & ~WA_UNDERLINE)); - wattr_on(listwin, attrs, NULL); - - if (en == curent) { - WADDSTR(listwin, WIDE(" -> ")); - } else - WADDSTR(listwin, WIDE(" ")); - - n = en->en_secs; - if (en->en_started) - n += time(NULL) - en->en_started; - h = n / (60 * 60); - n %= (60 * 60); - m = n / 60; - n %= 60; - s = n; - - SNPRINTF(stime, WSIZEOF(stime), WIDE("%02d:%02d:%02d%c "), - h, m, s, (itime && (en == running)) ? '*' : ' '); - WADDSTR(listwin, stime); - - memset(flags, 0, sizeof(flags)); - p = flags; - - if (en->en_flags.efl_marked) - *p++ = 'M'; - else - *p++ = ' '; - - if (en->en_flags.efl_invoiced) - *p++ = 'I'; - else - *p++ = ' '; - - if (!en->en_flags.efl_nonbillable) - *p++ = 'B'; - else - *p++ = ' '; - - if (en->en_flags.efl_deleted) - *p++ = 'D'; - else - *p++ = ' '; - - if (*flags) { - WCHAR s[10]; - SNPRINTF(s, WSIZEOF(s), WIDE("%-5"FMT_L"s "), flags); - WADDSTR(listwin, s); - } else - WADDSTR(listwin, WIDE(" ")); - - WADDSTR(listwin, en->en_desc); - wclrtoeol(listwin); - wbkgdset(listwin, oldbg); - wattr_off(listwin, attrs, NULL); - - if (++cline >= nlines) - return; - } - - oldbg = getbkgd(listwin); - wattr_on(listwin, style_fg(sy_entry), NULL); - wbkgdset(listwin, style_bg(sy_entry)); - for (; cline < nlines; cline++) { - wmove(listwin, cline, 0); - wclrtoeol(listwin); - } - wattr_off(listwin, style_fg(sy_entry), NULL); - wbkgdset(listwin, oldbg); -} - -entry_t * -entry_new(desc) - const WCHAR *desc; -{ -entry_t *en; - if ((en = calloc(1, sizeof(*en))) == NULL) - return NULL; - - if (auto_nonbillable && STRSTR(desc, auto_nonbillable)) - en->en_flags.efl_nonbillable = 1; - - TAILQ_INSERT_HEAD(&entries, en, en_entries); - - en->en_desc = STRDUP(desc); - time(&en->en_created); - - return en; -} - -void -entry_start(en) - entry_t *en; -{ - if (running) - entry_stop(running); - time(&en->en_started); - running = en; -} - -void -entry_stop(en) - entry_t *en; -{ - if (running == en) - running = NULL; - en->en_secs += time(NULL) - en->en_started; - en->en_started = 0; -} - -void -entry_free(en) - entry_t *en; -{ - if (en == running) - entry_stop(en); - free(en->en_desc); -} - -void -entry_account(en) - entry_t *en; -{ - if (!en->en_started) - return; - en->en_secs += time(NULL) - en->en_started; - time(&en->en_started); -} - -/* - * Return the amount of time for the day on which the timestamp .when falls. - * If .inv is 0, sum non-invoiced entries; if 1, sum invoiced entries; if - * 2, sum billable entries; if -1, sum all entries. If .incr is non-zero, - * individual entry time will be rounded up to intervals of that many minutes. - */ -time_t -entry_time_for_day(when, inv, incr) - time_t when; -{ -time_t day = time_day(when); -time_t sum = 0; -entry_t *en; -int rnd = incr * 60; - TAILQ_FOREACH(en, &entries, en_entries) { - time_t n; - - if (entry_day(en) > day) - continue; - if (entry_day(en) < day) - break; - - if (inv == 0 && en->en_flags.efl_invoiced) - continue; - if (inv == 1 && !en->en_flags.efl_invoiced) - continue; - if (inv == 2 && en->en_flags.efl_nonbillable) - continue; - - n = en->en_secs; - if (en->en_started) - n += time(NULL) - en->en_started; - - if (!n) - continue; - - if (rnd) - n = (1 + round((n - 1) / rnd)) * rnd; - sum += n; - } - return sum; -} - int load() { FILE *f; char input[4096]; -WCHAR line[4096]; +wchar_t line[4096]; entry_t *en; - TAILQ_FOREACH(en, &entries, en_entries) + TTS_TAILQ_FOREACH(en, &entries, en_entries) entry_free(en); if ((f = fopen(statfile, "r")) == NULL) { if (errno == ENOENT) return 0; - errbox(WIDE("Can't read %s: %s"), statfile, strerror(errno)); + errbox(L"Can't read %s: %s", statfile, strerror(errno)); exit(1); } if (fgets(input, sizeof(input), f) == NULL) { - errbox(WIDE("Can't read %s: %s"), statfile, strerror(errno)); + errbox(L"Can't read %s: %s", statfile, strerror(errno)); fclose(f); exit(1); } - MBSTOWCS(line, input, WSIZEOF(line)); + mbstowcs(line, input, wsizeof(line)); - if (STRCMP(line, WIDE("#%RT/TTS V1\n"))) { - errbox(WIDE("Can't read %s: invalid magic signature"), statfile); + if (wcscmp(line, L"#%RT/TTS V1\n")) { + errbox(L"Can't read %s: invalid magic signature", statfile); fclose(f); exit(1); } while (fgets(input, sizeof(input), f)) { unsigned long cre, secs; - WCHAR flags[10], desc[4096], *p; + wchar_t flags[10], desc[4096], *p; entry_t *en; int i; - MBSTOWCS(line, input, WSIZEOF(line)); + mbstowcs(line, input, wsizeof(line)); - if (SSCANF(line, WIDE("#%%showinv %d\n"), &i) == 1) { + if (swscanf(line, L"#%%showinv %d\n", &i) == 1) { showinv = i ? 1 : 0; continue; } - if (SSCANF(line, WIDE("%lu %lu %9"FMT_L"[in-] %4095"FMT_L"[^\n]\n"), + if (swscanf(line, L"%lu %lu %9l[in-] %4095l[^\n]\n", &cre, &secs, flags, desc) != 4) { - errbox(WIDE("Can't read %s: invalid entry format"), statfile); + errbox(L"Can't read %s: invalid entry format", statfile); fclose(f); exit(1); } @@ -2155,7 +431,7 @@ entry_t *en; break; default: - errbox(WIDE("Can't read %s: invalid flag"), statfile); + errbox(L"Can't read %s: invalid flag", statfile); fclose(f); exit(1); } @@ -2163,7 +439,7 @@ entry_t *en; } if (ferror(f)) { - errbox(WIDE("Can't read %s: %s"), statfile, strerror(errno)); + errbox(L"Can't read %s: %s", statfile, strerror(errno)); fclose(f); exit(1); } @@ -2183,40 +459,40 @@ entry_t *en; snprintf(p, sizeof(p), "%s_", statfile); if ((fd = open(p, O_WRONLY | O_CREAT, 0600)) == -1) { - errbox(WIDE("%s_: %s"), statfile, strerror(errno)); + errbox(L"%s_: %s", statfile, strerror(errno)); endwin(); exit(1); } if ((f = fdopen(fd, "w")) == NULL) { - errbox(WIDE("%s: %s"), p, strerror(errno)); + errbox(L"%s: %s", p, strerror(errno)); endwin(); exit(1); } - if (FPRINTF(f, WIDE("#%%RT/TTS V1\n")) == -1) { + if (fwprintf(f, L"#%%RT/TTS V1\n") == -1) { fclose(f); unlink(p); - errbox(WIDE("%s: write error (header): %s"), p, strerror(errno)); + errbox(L"%s: write error (header): %s", p, strerror(errno)); endwin(); exit(1); } - if (FPRINTF(f, WIDE("#%%showinv %d\n"), showinv) == -1) { + if (fwprintf(f, L"#%%showinv %d\n", showinv) == -1) { fclose(f); unlink(p); - errbox(WIDE("%s: write error (showinv): %s"), p, strerror(errno)); + errbox(L"%s: write error (showinv): %s", p, strerror(errno)); endwin(); exit(1); } - TAILQ_FOREACH_REVERSE(en, &entries, entrylist, en_entries) { + TTS_TAILQ_FOREACH_REVERSE(en, &entries, entrylist, en_entries) { char flags[10], *fp = flags, wdesc[4096] = {}; time_t n; - WCSTOMBS(wdesc, en->en_desc, sizeof(wdesc)); + wcstombs(wdesc, en->en_desc, sizeof(wdesc)); memset(flags, 0, sizeof(flags)); if (en->en_flags.efl_invoiced) @@ -2228,11 +504,11 @@ entry_t *en; if (en->en_started) n += time(NULL) - en->en_started; - if (FPRINTF(f, WIDE("%lu %lu %s %s\n"), + if (fwprintf(f, L"%lu %lu %s %s\n", (unsigned long) en->en_created, (unsigned long) n, *flags ? flags : "-", wdesc) == -1) { - errbox(WIDE("%s: write error (entry): %s"), p, strerror(errno)); + errbox(L"%s: write error (entry): %s", p, strerror(errno)); fclose(f); unlink(p); endwin(); @@ -2242,14 +518,14 @@ entry_t *en; if (fclose(f) == EOF) { unlink(p); - errbox(WIDE("%s: write error (closing): %s"), p, strerror(errno)); + errbox(L"%s: write error (closing): %s", p, strerror(errno)); endwin(); exit(1); } if (rename(p, statfile) == -1) { unlink(p); - errbox(WIDE("%s: rename: %s"), statfile, strerror(errno)); + errbox(L"%s: rename: %s", statfile, strerror(errno)); endwin(); exit(1); } @@ -2258,72 +534,20 @@ entry_t *en; return 0; } -void -errbox(const WCHAR *msg, ...) -{ -va_list ap; - va_start(ap, msg); - verrbox(msg, ap); - va_end(ap); -} - -void -verrbox(msg, ap) - const WCHAR *msg; - va_list ap; -{ -WCHAR text[4096]; -WINDOW *ewin; - -#define ETITLE WIDE(" Error ") -#define ECONT WIDE(" ") -int width; -INT c; - - VSNPRINTF(text, WSIZEOF(text), msg, ap); - width = STRLEN(text); - - ewin = newwin(6, width + 4, - (LINES / 2) - ((1 + 2)/ 2), - (COLS / 2) - ((width + 2) / 2)); - leaveok(ewin, TRUE); - wborder(ewin, 0, 0, 0, 0, 0, 0, 0, 0); - - wattron(ewin, A_REVERSE | A_BOLD); - wmove(ewin, 0, (width / 2) - (WSIZEOF(ETITLE) - 1)/2); - WADDSTR(ewin, ETITLE); - wattroff(ewin, A_REVERSE | A_BOLD); - - wmove(ewin, 2, 2); - WADDSTR(ewin, text); - wattron(ewin, A_REVERSE | A_BOLD); - wmove(ewin, 4, (width / 2) - ((WSIZEOF(ECONT) - 1) / 2)); - WADDSTR(ewin, ECONT); - wattroff(ewin, A_REVERSE | A_BOLD); - - for (;;) { - if (WGETCH(ewin, &c) == ERR) - continue; - if (c == '\r') - break; - } - - delwin(ewin); -} - history_t * hist_new() { history_t *hi; if ((hi = calloc(1, sizeof(*hi))) == NULL) return NULL; - TAILQ_INIT(&hi->hi_ents); + TTS_TAILQ_INIT(&hi->hi_ents); return hi; } -void hist_add(hi, text) +void +hist_add(hi, text) history_t *hi; - const WCHAR *text; + const wchar_t *text; { histent_t *hent; @@ -2333,404 +557,35 @@ histent_t *hent; if ((hent = calloc(1, sizeof(*hent))) == NULL) return; - if ((hent->he_text = STRDUP(text)) == NULL) { + if ((hent->he_text = wcsdup(text)) == NULL) { free(hent); return; } - TAILQ_INSERT_TAIL(&hi->hi_ents, hent, he_entries); + TTS_TAILQ_INSERT_TAIL(&hi->hi_ents, hent, he_entries); if (hi->hi_nents == 50) - TAILQ_REMOVE(&hi->hi_ents, TAILQ_FIRST(&hi->hi_ents), he_entries); + TTS_TAILQ_REMOVE(&hi->hi_ents, TTS_TAILQ_FIRST(&hi->hi_ents), he_entries); else ++hi->hi_nents; } -/* - * Return the tkey_t for the key called .name, or NULL if such a key doesn't - * exist. - */ -tkey_t * -find_key(name) - const WCHAR *name; -{ -size_t i; - - for (i = 0; i < sizeof(keys) / sizeof(*keys); i++) - if (STRCMP(name, keys[i].ky_name) == 0) - return &keys[i]; - return NULL; -} - -/* - * Return the function_t for the function called .name, or NULL if such a - * function doesn't exist. - */ -function_t * -find_func(name) - const WCHAR *name; -{ -size_t i; - for (i = 0; i < sizeof(funcs) / sizeof(*funcs); i++) - if (STRCMP(name, funcs[i].fn_name) == 0) - return &funcs[i]; - return NULL; -} - -/* - * Bind .keyname to run the function .funcname. If a binding for .keyname - * already exists, overwrite it. - * - * If .keyname is a single character, e.g. 'a', it is used as a key name - * directly, rather than being looked up in the key table. - */ -void -bind_key(keyname, funcname) - const WCHAR *keyname, *funcname; -{ -tkey_t *key = NULL; -function_t *func; -binding_t *binding; -INT code; - - /* Find the key and the function */ - if (STRLEN(keyname) > 1) { - if ((key = find_key(keyname)) == NULL) { - errbox(WIDE("Unknown key \"%"FMT_L"s\""), keyname); - return; - } - code = key->ky_code; - } else - code = *keyname; - - if ((func = find_func(funcname)) == NULL) { - errbox(WIDE("Unknown function \"%"FMT_L"s\""), funcname); - return; - } - - /* Do we already have a binding for this key? */ - TAILQ_FOREACH(binding, &bindings, bi_entries) { - if (binding->bi_code == code) { - binding->bi_func = func; - return; - } - } - - /* No, add a new one */ - if ((binding = calloc(1, sizeof(*binding))) == NULL) - return; - - binding->bi_key = key; - binding->bi_func = func; - binding->bi_code = code; - TAILQ_INSERT_TAIL(&bindings, binding, bi_entries); -} - -size_t -tokenise(str, res) - const WCHAR *str; - WCHAR ***res; -{ -int ntoks = 0; -const WCHAR *p, *q; - - *res = NULL; - p = str; - - for (;;) { - ptrdiff_t sz; - int qskip = 0; - - /* Skip leading whitespace */ - while (ISSPACE(*p)) - p++; - - /* End of string - no more arguments */ - if (!*p) - break; - - q = p; - - if (*q == '"') { - /* Quoted string - scan for end of string */ - int isbsl = 0; - p++; - - while (*++q) { - /* Handle escaping with backslash; currently works but the \ isn't - * removed from the string. - */ - if (*q == '\\') { - isbsl = 1; - continue; - } - - if (!isbsl && (*q == '"')) - break; - - isbsl = 0; - } - /* At this point, *q == '"'. If it's NUL instead, then the - * string was not terminated with a closing '"' before the end - * of the line. We could give an error here, but it seems - * more useful to just accept it. - */ - if (*q == '"') - qskip = 1; - } else { - /* Not quoted - just find the next whitespace */ - while (!ISSPACE(*q) && *q) - q++; - } - - /* Copy the argument (which is sz bytes long) into the result array */ - sz = (q - p); - *res = realloc(*res, sizeof(WCHAR *) * (ntoks + 1)); - (*res)[ntoks] = malloc(sizeof(WCHAR) * sz + 1); - MEMCPY((*res)[ntoks], p, sz); - (*res)[ntoks][sz] = 0; - ntoks++; - - if (qskip) - q += qskip; - - while (ISSPACE(*q)) - q++; - - /* - * q is the start of the next token (with leading whitespace); reset - * p to process the next argument. - */ - if (!*q) - break; - p = q; - } - - *res = realloc(*res, sizeof(WCHAR *) * (ntoks + 1)); - (*res)[ntoks] = NULL; - return ntoks; -} - -void -tokfree(vec) - WCHAR ***vec; -{ -WCHAR **p; - for (p = (*vec); *p; p++) - free(*p); - free(*vec); -} - -command_t * -find_command(name) - const WCHAR *name; -{ -size_t i; - for (i = 0; i < sizeof(commands) / sizeof(*commands); i++) - if (STRCMP(name, commands[i].cm_name) == 0) - return &commands[i]; - return NULL; -} - -void -c_style(argc, argv) - size_t argc; - WCHAR **argv; -{ -style_t *sy; -WCHAR *last, *tok; - - if (argc < 3 || argc > 4) { - cmderr(WIDE("Usage: style [background]")); - return; - } - - if (STRCMP(argv[1], WIDE("header")) == 0) - sy = &sy_header; - else if (STRCMP(argv[1], WIDE("status")) == 0) - sy = &sy_status; - else if (STRCMP(argv[1], WIDE("entry")) == 0) - sy = &sy_entry; - else if (STRCMP(argv[1], WIDE("selected")) == 0) - sy = &sy_selected; - else if (STRCMP(argv[1], WIDE("running")) == 0) - sy = &sy_running; - else if (STRCMP(argv[1], WIDE("date")) == 0) - sy = &sy_date; - else { - cmderr(WIDE("Unknown style item.")); - return; - } - - style_clear(sy); - for (tok = STRTOK(argv[2], WIDE(","), &last); tok != NULL; - tok = STRTOK(NULL, WIDE(","), &last)) { - style_add(sy, tok, argv[3]); - } - - apply_styles(); -} - -void -c_bind(argc, argv) - size_t argc; - WCHAR **argv; -{ - if (argc != 3) { - cmderr(WIDE("Usage: bind ")); - return; - } - - bind_key(argv[1], argv[2]); -} - variable_t * find_variable(name) - WCHAR const *name; + wchar_t const *name; { -size_t i; - for (i = 0; i < sizeof(variables) / sizeof(*variables); i++) - if (STRCMP(name, variables[i].va_name) == 0) - return &variables[i]; +variable_t *v; + for (v = variables; v->va_name; v++) + if (wcscmp(name, v->va_name) == 0) + return v; return NULL; } -void -c_set(argc, argv) - size_t argc; - WCHAR **argv; -{ -variable_t *var; -int val; - - if (argc != 3) { - cmderr(WIDE("Usage: set ")); - return; - } - - if ((var = find_variable(argv[1])) == NULL) { - cmderr(WIDE("Unknown variable \"%"FMT_L"s\"."), argv[1]); - return; - } - - switch (var->va_type) { - case VTYPE_BOOL: - if (STRCMP(argv[2], WIDE("true")) == 0 || - STRCMP(argv[2], WIDE("yes")) == 0 || - STRCMP(argv[2], WIDE("on")) == 0 || - STRCMP(argv[2], WIDE("1")) == 0) { - val = 1; - } else if (STRCMP(argv[2], WIDE("false")) == 0 || - STRCMP(argv[2], WIDE("no")) == 0 || - STRCMP(argv[2], WIDE("off")) == 0 || - STRCMP(argv[2], WIDE("0")) == 0) { - val = 0; - } else { - cmderr(WIDE("Invalid value for boolean: \"%"FMT_L"s\"."), argv[2]); - return; - } - - *(int *)var->va_addr = val; - break; - - case VTYPE_STRING: - *(WCHAR **)var->va_addr = STRDUP(argv[2]); - break; - - case VTYPE_INT: - *(int *)var->va_addr = STRTOL(argv[2], NULL, 0); - break; - } -} - -int -attr_find(name, result) - const WCHAR *name; - attr_t *result; -{ -size_t i; - for (i = 0; i < sizeof(attrnames) / sizeof(*attrnames); i++) { - if (STRCMP(attrnames[i].an_name, name) == 0) { - *result = attrnames[i].an_value; - return 0; - } - } - - return -1; -} - -int -colour_find(name, result) - const WCHAR *name; - short *result; -{ -size_t i; - for (i = 0; i < sizeof(colours) / sizeof(*colours); i++) { - if (STRCMP(colours[i].co_name, name) == 0) { - *result = colours[i].co_value; - return 0; - } - } - - return -1; -} -void -style_clear(sy) - style_t *sy; -{ - init_pair(sy->sy_pair, default_fg, default_bg); - sy->sy_attrs = WA_NORMAL; -} - -int -style_set(sy, fg, bg) - style_t *sy; - const WCHAR *fg, *bg; -{ - sy->sy_attrs = WA_NORMAL; - init_pair(sy->sy_pair, default_fg, default_bg); - return style_add(sy, fg, bg); -} - -int -style_add(sy, fg, bg) - style_t *sy; - const WCHAR *fg, *bg; -{ -attr_t at; -short colfg, colbg = default_bg; - - if (colour_find(fg, &colfg) == 0) { - if (bg && (colour_find(bg, &colbg) == -1)) - return -1; - - init_pair(sy->sy_pair, colfg, colbg); - return 0; - } - - if (attr_find(fg, &at) == -1) - return -1; - sy->sy_attrs |= at; - return 0; -} - -void -apply_styles() -{ - wbkgd(statwin, style_bg(sy_status)); - wattr_on(statwin, style_fg(sy_status), NULL); - drawstatus(WIDE("")); - - wbkgd(titwin, style_bg(sy_header)); - wattr_on(titwin, style_fg(sy_header), NULL); - drawheader(); -} - static char *curfile; static int lineno, nerr; void -cmderr(const WCHAR *msg, ...) +cmderr(const wchar_t *msg, ...) { va_list ap; @@ -2741,16 +596,16 @@ va_list ap; void vcmderr(msg, ap) - const WCHAR *msg; + const wchar_t *msg; va_list ap; { nerr++; if (curfile) { - WCHAR s[1024]; + wchar_t s[1024]; char t[1024]; - VSNPRINTF(s, WSIZEOF(t), msg, ap); - WCSTOMBS(t, s, sizeof(t)); + vswprintf(s, wsizeof(t), msg, ap); + wcstombs(t, s, sizeof(t)); if (in_curses) { endwin(); @@ -2759,8 +614,10 @@ vcmderr(msg, ap) fprintf(stderr, "\"%s\", line %d: %s\n", curfile, lineno, t); - } else + } else { + input_macro(NULL); vdrawstatus(msg, ap); + } } /* @@ -2790,13 +647,13 @@ char input[1024]; while (fgets(input, sizeof(input), s)) { size_t nargs; - WCHAR **args; + wchar_t **args; command_t *cmds; - WCHAR line[1024]; + wchar_t line[1024]; ++lineno; - MBSTOWCS(line, input, WSIZEOF(line)); + mbstowcs(line, input, wsizeof(line)); if (line[0] == '#') continue; @@ -2808,7 +665,7 @@ char input[1024]; } if ((cmds = find_command(args[0])) == NULL) { - cmderr(WIDE("Unknown command \"%"FMT_L"s\"."), args[0]); + cmderr(L"Unknown command \"%ls\".", args[0]); nerr++; tokfree(&args); continue; @@ -2828,66 +685,19 @@ char input[1024]; return 0; } -int -prduration(pr, hh, mm, ss) - WCHAR *pr; - int *hh, *mm, *ss; -{ -WCHAR *tstr; -int h, m, s; - if ((tstr = prompt(pr, WIDE("00:00:00"), NULL)) == NULL) - return -1; - - if (!*tstr) { - drawstatus(WIDE("No duration entered")); - free(tstr); - return -1; - } - - if (SSCANF(tstr, WIDE("%d:%d:%d"), &h, &m, &s) != 3) { - h = 0; - if (SSCANF(tstr, WIDE("%d:%d"), &m, &s) != 2) { - m = 0; - if (SSCANF(tstr, WIDE("%d"), &s) != 1) { - free(tstr); - drawstatus(WIDE("Invalid time format.")); - return -1; - } - } - } - - free(tstr); - - if (m >= 60) { - drawstatus(WIDE("Minutes cannot be more than 59.")); - return -1; - } - - if (s >= 60) { - drawstatus(WIDE("Seconds cannot be more than 59.")); - return -1; - } - - *hh = h; - *mm = m; - *ss = s; - return 0; -} - #ifdef USE_DARWIN_POWER static void -prompt_sleep() +prompt_sleep(sleeptime) + time_t sleeptime; { /* * We woke from sleep. If there's a running entry, prompt the user to * subtract the time spent sleeping, in case they forgot to turn off * the timer. */ -WCHAR pr[128]; +wchar_t pr[128]; int h, m, s = 0; - donesleep = 0; - /* Only prompt if an entry is running */ if (!running) return; @@ -2900,20 +710,79 @@ int h, m, s = 0; m = s / 60; s %= 60; - SNPRINTF(pr, WSIZEOF(pr), - WIDE("Remove %02d:%02d:%02d time asleep from running entry?"), + swprintf(pr, wsizeof(pr), + L"Remove %02d:%02d:%02d time asleep from running entry?", h, m, s); - if (!yesno(pr)) { - sleeptime = 0; + if (!yesno(pr)) return; - } /* * This is a bit of a fudge, but it has the desired effect. Alternatively * we could merge en_started into en_secs, then subtract that. */ running->en_started += sleeptime; - sleeptime = 0; } #endif /* USE_DARWIN_POWER */ + +void +input_macro(s) + wchar_t *s; +{ + free(macro_text); + macro_text = macro_pos = NULL; + + if (!s) + return; + + macro_text = macro_pos = wcsdup(s); +} + +int +input_char(win, c) + WINDOW *win; + wint_t *c; +{ +wchar_t *pr, *s, *r; + if (!macro_pos) + return wget_wch(win, c); + + if (!*macro_pos) { + input_macro(NULL); + return wget_wch(win, c); + } + + if (macro_pos[0] != '$' || macro_pos[1] != '[') { + *c = *macro_pos++; + return 0; + } + +/* Handle $[prompt string] escapes */ + pr = calloc(sizeof(wchar_t), wcslen(macro_pos) - 1); + for (r = pr, s = macro_pos + 2; ; s++) { + if (*s == '\0') { + cmderr(L"Unterminated $[ prompt in macro"); + input_macro(NULL); + return wget_wch(win, c); + } + + if (*s == ']') + break; + + *r++ = *s; + } + + s++; + + macro_pos = NULL; + r = prompt(pr, NULL, NULL); + free(pr); + + pr = calloc(sizeof(wchar_t), wcslen(r) + wcslen(s) + 1); + wcscpy(pr, r); + wcscat(pr, s); + free(macro_text); + macro_text = macro_pos = pr; + *c = *macro_pos++; + return 0; +} diff --git a/tts.h b/tts.h new file mode 100644 index 0000000..21db178 --- /dev/null +++ b/tts.h @@ -0,0 +1,78 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_H +#define TTS_H + +#include + +#include "wide.h" +#include "tailq.h" +#include "entry.h" + +extern char const *tts_version; +extern time_t laststatus; + +/* + * Configuration options. + */ + +extern int show_billable; +extern int delete_advance; +extern int mark_advance; +extern int bill_advance; +extern int bill_increment; +extern wchar_t *auto_nonbillable; + +/* + * Global state. + */ + +extern entry_t *curent; +extern volatile sig_atomic_t doexit; +extern int pagestart; +extern time_t itime; + +int load(void); +int save(void); + +/* + * Command history. + */ + +#define NHIST 50 +typedef struct histent { + wchar_t *he_text; + TTS_TAILQ_ENTRY(histent) he_entries; +} histent_t; +typedef TTS_TAILQ_HEAD(hentlist, histent) hentlist_t; + +typedef struct history { + int hi_nents; + hentlist_t hi_ents; +} history_t; + +history_t *hist_new(void); +void hist_add(history_t *, wchar_t const *); + +extern history_t *searchhist; +extern history_t *prompthist; + +#ifndef HAVE_WCSLCPY +size_t wcslcat(wchar_t *s1, const wchar_t *s2, size_t n); +#endif + +#ifndef HAVE_WCSLCAT +size_t wcslcpy(wchar_t *s1, const wchar_t *s2, size_t n); +#endif + +extern int time_format; + +#endif /* !TTS_H */ diff --git a/tts_curses.h b/tts_curses.h new file mode 100644 index 0000000..79f4e20 --- /dev/null +++ b/tts_curses.h @@ -0,0 +1,30 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_CURSES_H +#define TTS_CURSES_H + +#include "config.h" + +#if defined HAVE_NCURSESW_CURSES_H +# include +#elif defined HAVE_NCURSESW_H +# include +#elif defined HAVE_NCURSES_CURSES_H +# include +#elif defined HAVE_NCURSES_H +# include +#elif defined HAVE_CURSES_H +# include +#else +# error "SVR4 or XSI compatible curses header file required" +#endif + +#endif /* !TTS_CURSES_H */ diff --git a/ttsrc.sample b/ttsrc.sample index 43791fd..da11815 100644 --- a/ttsrc.sample +++ b/ttsrc.sample @@ -11,6 +11,15 @@ #set mark_advance 1 #set delete_advance 1 +# Select the time format used in the display; value can be from 0 to 3. +# +# 0: 10:03:37 (default) +# 1: 10:03 +# 2: 10h 3m 37s +# 3: 10h 3m +# +#set time_format 0 + #### Billing options # # If set, show billable time in each daily summary. @@ -33,7 +42,7 @@ #set bill_advance 0 -#### Bindings +#### Bindings and macros # # Use the 'bind' command to (re)define keybindings. Type '?' while TTS is # running for a full list of key bindings. @@ -45,6 +54,17 @@ bind j next bind k prev +# Macros work in a similar way to bindings, except the second argument is a +# string which will be executed as if it was typed. For example, the +# following macro would add a new entry called "test", and set its timer to +# 30 minutes. +#macro t "atest\n+30m\n" + +# Macros can also prompt for input from the user using $[Prompt string]; the +# $[...] will be replaced with the user's input. For example, this macro will +# prompt for the name of a new entry, then set its duration to 30m: +#macro t "a$[Description:]\n+30m\n" + #### Styling # # You can style UI elements with the 'style' command. Its syntax is: @@ -101,8 +121,8 @@ bind k prev # style header yellow,bold blue style status yellow,bold blue +style date white,underline black style entry white black style selected yellow,bold red # Use bold *and* underline, because we already bolded 'selected' above. -style running bold,underline -style date underline,bold +style running white,bold,underline black diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..23fbdc7 --- /dev/null +++ b/ui.c @@ -0,0 +1,666 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include +#include + +#include "ui.h" +#include "tts.h" +#include "style.h" +#include "str.h" + +WINDOW *titwin, *statwin, *listwin; +int in_curses; + +void +ui_init(void) +{ + initscr(); + in_curses = 1; + start_color(); +#ifdef HAVE_USE_DEFAULT_COLORS + use_default_colors(); +#endif + cbreak(); + noecho(); + nonl(); + nodelay(stdscr, TRUE); + + pair_content(0, &default_fg, &default_bg); + + refresh(); + + intrflush(stdscr, TRUE); + keypad(stdscr, TRUE); + leaveok(stdscr, TRUE); + + titwin = newwin(1, 0, 0, 0); + intrflush(titwin, FALSE); + keypad(titwin, TRUE); + leaveok(titwin, TRUE); + + statwin = newwin(1, 0, LINES - 1, 0); + intrflush(statwin, FALSE); + keypad(statwin, TRUE); + leaveok(statwin, TRUE); + + listwin = newwin(LINES - 2, 0, 1, 0); + intrflush(listwin, FALSE); + keypad(listwin, TRUE); + leaveok(listwin, TRUE); + + curs_set(0); +} + +/* + * Move the cursor to the next entry after an operation like mark or deleted. + * If there are no suitable entries after this one, move it backwards instead. + */ +void +cursadvance() +{ +entry_t *en; + + if (!curent) { + curent = TTS_TAILQ_FIRST(&entries); + return; + } + + /* + * Try to find the next suitable entry to move the cursor to. + */ + for (en = TTS_TAILQ_NEXT(curent, en_entries); en; en = TTS_TAILQ_NEXT(en, en_entries)) { + if (!showinv && en->en_flags.efl_invoiced) + continue; + curent = en; + if (!curent->en_flags.efl_visible) + pagestart++; + return; + } + + /* + * No entries; if the current entry is visible, stay here, otherwise + * try moving backwards instead. + */ + if (showinv || !curent->en_flags.efl_invoiced) + return; + + for (en = TTS_TAILQ_PREV(curent, entrylist, en_entries); en; + en = TTS_TAILQ_PREV(en, entrylist, en_entries)) { + if (!showinv && en->en_flags.efl_invoiced) + continue; + curent = en; + if (!curent->en_flags.efl_visible) + pagestart--; + return; + } + + /* + * Couldn't find any entries at all? + */ + curent = NULL; +} + +void +drawheader() +{ +wchar_t title[64]; + + swprintf(title, wsizeof(title), L"TTS %s - Type '?' for help", + tts_version); + wmove(titwin, 0, 0); + waddwstr(titwin, title); + + if (itime > 0) { + wchar_t str[128], *tm; + time_t passed = time(NULL) - itime; + + tm = maketime(passed, time_format); + swprintf(str, wsizeof(str), L" *** MARK INTERRUPT: %ls ***", tm); + free(tm); + + wattron(titwin, A_BOLD); + waddwstr(titwin, str); + wattroff(titwin, A_BOLD); + } + wclrtoeol(titwin); + wrefresh(titwin); +} + +void +vdrawstatus(msg, ap) + const wchar_t *msg; + va_list ap; +{ +wchar_t s[1024]; + vswprintf(s, wsizeof(s), msg, ap); + + wmove(statwin, 0, 0); + waddwstr(statwin, s); + wclrtoeol(statwin); + wrefresh(statwin); + time(&laststatus); +} + +void +drawstatus(const wchar_t *msg, ...) +{ +va_list ap; + va_start(ap, msg); + vdrawstatus(msg, ap); + va_end(ap); +} + +int +yesno(msg) + const wchar_t *msg; +{ +WINDOW *pwin; +wint_t c; + + pwin = newwin(1, COLS, LINES - 1, 0); + keypad(pwin, TRUE); + + wattron(pwin, A_BOLD); + wattr_on(pwin, style_fg(sy_status), NULL); + wbkgd(pwin, style_bg(sy_status)); + + wmove(pwin, 0, 0); + waddwstr(pwin, msg); + waddwstr(pwin, L" [y/N]? "); + wattroff(pwin, A_BOLD); + + while (input_char(pwin, &c) == ERR +#ifdef KEY_RESIZE + || (c == KEY_RESIZE) +#endif + ) + ; + + delwin(pwin); + wtouchln(statwin, 0, 1, 1); + wrefresh(statwin); + + return (c == 'Y' || c == 'y') ? 1 : 0; +} + +wchar_t * +prompt(msg, def, hist) + const wchar_t *msg, *def; + history_t *hist; +{ +WINDOW *pwin; +wchar_t input[256]; +size_t pos = 0; +histent_t *histpos = NULL; + + if (hist == NULL) + hist = prompthist; + + memset(input, 0, sizeof(input)); + if (def) { + wcsncpy(input, def, wsizeof(input) - 1); + pos = wcslen(input); + } + + pwin = newwin(1, COLS, LINES - 1, 0); + keypad(pwin, TRUE); + + wattr_on(pwin, style_fg(sy_status), NULL); + wbkgd(pwin, style_bg(sy_status)); + + wattron(pwin, A_BOLD); + wmove(pwin, 0, 0); + waddwstr(pwin, msg); + wattroff(pwin, A_BOLD); + + curs_set(1); + + for (;;) { + wint_t c; + int i, inpos; + wmove(pwin, 0, wcslen(msg) + 1); + for (i = 0; i < wcslen(input); i++) { + if (input[i] == L'\t') + waddwstr(pwin, L" "); + else { + wchar_t s[] = { input[i], '\0' }; + waddwstr(pwin, s); + } + } + i--; + + wclrtoeol(pwin); + for (i = 0, inpos = 0; i < wcslen(input) && i < pos; i++) + if (input[i] == L'\t') + inpos += 8; + else + inpos++; + + wmove(pwin, 0, wcslen(msg) + 1 + inpos); + wrefresh(pwin); + + if (input_char(pwin, &c) == ERR) + continue; + + switch (c) { + case '\n': + case '\r': + goto end; + + case KEY_BACKSPACE: + case 0x7F: + case 0x08: + if (pos) { + if (pos == wcslen(input)) + input[--pos] = 0; + else { + int i = wcslen(input); + pos--; + wmemcpy(input + pos, input + pos + 1, wcslen(input) - pos); + input[i] = 0; + } + } + break; + + case KEY_DC: + if (pos < wcslen(input)) { + int i = wcslen(input); + wmemcpy(input + pos, input + pos + 1, wcslen(input) - pos); + input[i] = 0; + } + break; + + case KEY_LEFT: + if (pos) + pos--; + break; + + case KEY_RIGHT: + if (pos < wcslen(input)) + pos++; + break; + + case KEY_HOME: + case 0x01: /* ^A */ + pos = 0; + break; + + case KEY_END: + case 0x05: /* ^E */ + pos = wcslen(input); + break; + + case 0x07: /* ^G */ + case 0x1B: /* ESC */ + curs_set(0); + delwin(pwin); + return NULL; + + case 0x15: /* ^U */ + input[0] = 0; + pos = 0; + break; + +#ifdef KEY_RESIZE + case KEY_RESIZE: + break; +#endif + + case KEY_UP: + if (histpos == NULL) { + if ((histpos = TTS_TAILQ_LAST(&hist->hi_ents, hentlist)) == NULL) { + beep(); + break; + } + } else { + if (TTS_TAILQ_PREV(histpos, hentlist, he_entries) == NULL) { + beep(); + break; + } else + histpos = TTS_TAILQ_PREV(histpos, hentlist, he_entries); + } + + + wcsncpy(input, histpos->he_text, wsizeof(input) - 1); + pos = wcslen(input); + break; + + case KEY_DOWN: + if (histpos == NULL) { + beep(); + break; + } + + if (TTS_TAILQ_NEXT(histpos, he_entries) == NULL) { + beep(); + break; + } else + histpos = TTS_TAILQ_NEXT(histpos, he_entries); + + + wcsncpy(input, histpos->he_text, wsizeof(input) - 1); + pos = wcslen(input); + break; + + default: + if (pos != wcslen(input)) { + wmemmove(input + pos + 1, input + pos, wcslen(input) - pos); + input[pos++] = c; + } else { + input[pos++] = c; + input[pos] = 0; + } + + break; + } + } +end: ; + + curs_set(0); + delwin(pwin); + wtouchln(statwin, 0, 1, 1); + wrefresh(statwin); + hist_add(hist, input); + return wcsdup(input); +} + +void +errbox(const wchar_t *msg, ...) +{ +va_list ap; + va_start(ap, msg); + verrbox(msg, ap); + va_end(ap); +} + +void +verrbox(msg, ap) + const wchar_t *msg; + va_list ap; +{ +wchar_t text[4096]; +WINDOW *ewin; + +#define ETITLE L" Error " +#define ECONT L" " +int width; +wint_t c; + + vswprintf(text, wsizeof(text), msg, ap); + width = wcslen(text); + + ewin = newwin(6, width + 4, + (LINES / 2) - ((1 + 2)/ 2), + (COLS / 2) - ((width + 2) / 2)); + leaveok(ewin, TRUE); + wborder(ewin, 0, 0, 0, 0, 0, 0, 0, 0); + + wattron(ewin, A_REVERSE | A_BOLD); + wmove(ewin, 0, (width / 2) - (wsizeof(ETITLE) - 1)/2); + waddwstr(ewin, ETITLE); + wattroff(ewin, A_REVERSE | A_BOLD); + + wmove(ewin, 2, 2); + waddwstr(ewin, text); + wattron(ewin, A_REVERSE | A_BOLD); + wmove(ewin, 4, (width / 2) - ((wsizeof(ECONT) - 1) / 2)); + waddwstr(ewin, ECONT); + wattroff(ewin, A_REVERSE | A_BOLD); + + for (;;) { + if (wget_wch(ewin, &c) == ERR) + continue; + if (c == '\r') + break; + } + + delwin(ewin); +} + +void +drawentries() +{ +int i, nlines; +int cline = 0; +time_t lastday = 0; +entry_t *en; +chtype oldbg; + + getmaxyx(listwin, nlines, i); + + TTS_TAILQ_FOREACH(en, &entries, en_entries) + en->en_flags.efl_visible = 0; + + en = TTS_TAILQ_FIRST(&entries); + for (i = 0; i < pagestart; i++) + if ((en = TTS_TAILQ_NEXT(en, en_entries)) == NULL) + return; + + for (; en; en = TTS_TAILQ_NEXT(en, en_entries)) { + time_t n; + wchar_t flags[10], stime[16], *p; + attr_t attrs = 0; + wchar_t *etime; + + if (!showinv && en->en_flags.efl_invoiced) + continue; + + oldbg = getbkgd(listwin); + + if (lastday != entry_day(en)) { + struct tm *lt; + wchar_t lbl[128]; + wchar_t *itime = maketime(entry_time_for_day(entry_day(en), 1, 0), time_format), + *ntime = maketime(entry_time_for_day(entry_day(en), 0, 0), time_format), + *btime = maketime(entry_time_for_day(entry_day(en), 2, bill_increment), time_format), + *ttime = maketime(entry_time_for_day(entry_day(en), 1, 0) + + entry_time_for_day(entry_day(en), 0, 0), time_format); + wchar_t hdrtext[256]; + int n = 0; + + oldbg = getbkgd(listwin); + wbkgdset(listwin, style_bg(sy_entry)); + wattr_on(listwin, style_fg(sy_entry), NULL); + + wmove(listwin, cline, 0); + wclrtoeol(listwin); + + wbkgdset(listwin, oldbg); + wattr_off(listwin, style_fg(sy_entry), NULL); + + if (++cline >= nlines) + break; + + lastday = entry_day(en); + lt = localtime(&lastday); + + wcsftime(lbl, wsizeof(lbl), L"%A, %d %B %Y", lt); + swprintf(hdrtext, wsizeof(hdrtext), L"%-30ls [", lbl); + + if (*itime) { + wcslcat(hdrtext, L"I:", wsizeof(hdrtext)); + wcslcat(hdrtext, itime, wsizeof(hdrtext)); + n++; + } + free(itime); + + if (*ntime) { + if (n++) + wcslcat(hdrtext, L" ", wsizeof(hdrtext)); + wcslcat(hdrtext, L"N:", wsizeof(hdrtext)); + wcslcat(hdrtext, ntime, wsizeof(hdrtext)); + } + free(ntime); + + if (*ttime) { + if (n++) + wcslcat(hdrtext, L" ", wsizeof(hdrtext)); + wcslcat(hdrtext, L"T:", wsizeof(hdrtext)); + wcslcat(hdrtext, ttime, wsizeof(hdrtext)); + } + free(ttime); + + if (*btime) { + if (n++) + wcslcat(hdrtext, L" ", wsizeof(hdrtext)); + wcslcat(hdrtext, L"B:", wsizeof(hdrtext)); + wcslcat(hdrtext, btime, wsizeof(hdrtext)); + } + free(btime); + + wcslcat(hdrtext, L"]", wsizeof(hdrtext)); + + wattr_on(listwin, style_fg(sy_date), NULL); + wbkgdset(listwin, style_bg(sy_date)); + wmove(listwin, cline, 0); + waddwstr(listwin, hdrtext); + wclrtoeol(listwin); + wattr_off(listwin, style_fg(sy_date), NULL); + wbkgdset(listwin, oldbg); + + if (++cline >= nlines) { + wbkgdset(listwin, oldbg); + wattr_off(listwin, style_fg(sy_date), NULL); + break; + } + + oldbg = getbkgd(listwin); + wbkgdset(listwin, style_bg(sy_entry)); + wattr_on(listwin, style_fg(sy_entry), NULL); + + wmove(listwin, cline, 0); + wclrtoeol(listwin); + + wbkgdset(listwin, oldbg); + wattr_off(listwin, style_fg(sy_entry), NULL); + + if (++cline >= nlines) + break; + } + + en->en_flags.efl_visible = 1; + wmove(listwin, cline, 0); + + attrs = style_fg(sy_entry); + + if (en->en_started && en == curent) + attrs = style_fg(sy_selected) | + (style_fg(sy_running) & ( + WA_STANDOUT | WA_UNDERLINE | + WA_REVERSE | WA_BLINK | WA_DIM | + WA_BOLD)); + else if (en->en_started) + attrs = style_fg(sy_running); + else if (en == curent) + attrs = style_fg(sy_selected); + + wbkgdset(listwin, ' ' | (attrs & ~WA_UNDERLINE)); + wattr_on(listwin, attrs, NULL); + + if (en == curent) { + waddwstr(listwin, L" -> "); + } else + waddwstr(listwin, L" "); + + n = en->en_secs; + if (en->en_started) + n += time(NULL) - en->en_started; + + etime = maketime(n, time_format); + swprintf(stime, wsizeof(stime), L"%8ls%c ", + *etime ? etime : L"0m", (itime && (en == running)) ? '*' : ' '); + free(etime); + waddwstr(listwin, stime); + + memset(flags, 0, sizeof(flags)); + p = flags; + + if (en->en_flags.efl_marked) + *p++ = 'M'; + else + *p++ = ' '; + + if (en->en_flags.efl_invoiced) + *p++ = 'I'; + else + *p++ = ' '; + + if (!en->en_flags.efl_nonbillable) + *p++ = 'B'; + else + *p++ = ' '; + + if (en->en_flags.efl_deleted) + *p++ = 'D'; + else + *p++ = ' '; + + if (*flags) { + wchar_t s[10]; + swprintf(s, wsizeof(s), L"%-5ls ", flags); + waddwstr(listwin, s); + } else + waddwstr(listwin, L" "); + + waddwstr(listwin, en->en_desc); + wclrtoeol(listwin); + wbkgdset(listwin, oldbg); + wattr_off(listwin, attrs, NULL); + + if (++cline >= nlines) + return; + } + + oldbg = getbkgd(listwin); + wattr_on(listwin, style_fg(sy_entry), NULL); + wbkgdset(listwin, style_bg(sy_entry)); + for (; cline < nlines; cline++) { + wmove(listwin, cline, 0); + wclrtoeol(listwin); + } + wattr_off(listwin, style_fg(sy_entry), NULL); + wbkgdset(listwin, oldbg); +} + +time_t +prduration(pr, def) + wchar_t *pr; + time_t def; +{ +wchar_t *defstr = NULL; +wchar_t *tstr; +time_t ret; + + defstr = maketime(def, TIMEFMT_FOR_EDIT(time_format)); + + if ((tstr = prompt(pr, defstr, NULL)) == NULL) { + free(defstr); + return -1; + } + + free(defstr); + + if (!*tstr) { + drawstatus(L"No duration entered"); + free(tstr); + return -1; + } + + if ((ret = parsetime(tstr)) == (time_t) -1) { + free(tstr); + drawstatus(L"Invalid time format."); + return -1; + } + + free(tstr); + + return ret; +} diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..a32602f --- /dev/null +++ b/ui.h @@ -0,0 +1,38 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_UI_H +#define TTS_UI_H + +#include + +#include "tts.h" +#include "tts_curses.h" +#include "wide.h" + +extern WINDOW *titwin, *statwin, *listwin; +extern int in_curses; +extern int showinv; + +void ui_init (void); + +void cursadvance (void); +void drawstatus (const wchar_t *msg, ...); +void vdrawstatus (const wchar_t *msg, va_list); +void drawheader (void); +void drawentries (void); + +wchar_t *prompt (wchar_t const *, wchar_t const *, history_t *); +time_t prduration (wchar_t *prompt, time_t def); +int yesno (wchar_t const *); +void errbox (wchar_t const *, ...); +void verrbox (wchar_t const *, va_list); + +#endif /* !TTS_UI_H */ diff --git a/variable.h b/variable.h new file mode 100644 index 0000000..691c9c1 --- /dev/null +++ b/variable.h @@ -0,0 +1,28 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_VARIABLE_H +#define TTS_VARIABLE_H + +#include "wide.h" + +typedef struct variable { + wchar_t const *va_name; + int va_type; + void *va_addr; +} variable_t; + +#define VTYPE_INT 1 +#define VTYPE_BOOL 2 +#define VTYPE_STRING 3 + +variable_t *find_variable(const wchar_t *name); + +#endif /* !TTS_VARIABLE_H */ diff --git a/wcslcpy.c b/wcslcpy.c new file mode 100644 index 0000000..d57cdd9 --- /dev/null +++ b/wcslcpy.c @@ -0,0 +1,99 @@ +/* $NetBSD: strlcpy.c,v 1.3 2007/06/04 18:19:27 christos Exp $ */ +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "config.h" + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns wcslen(src); if retval >= siz, truncation occurred. + */ +#ifndef HAVE_WCSLCPY +size_t +wcslcpy(dst, src, siz) + wchar_t *dst; + wchar_t const *src; + size_t siz; +{ +wchar_t *d = dst; +const wchar_t *s = src; +size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} +#endif + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= wcslen(dst)). + * Returns wcslen(src) + MIN(siz, wcslen(initial dst)). + * If retval >= siz, truncation occurred. + */ +#ifndef HAVE_WCSLCAT +size_t +wcslcat(wchar_t *dst, const wchar_t *src, size_t siz) +{ +wchar_t *d = dst; +const wchar_t *s = src; +size_t n = siz; +size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + wcslen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif + diff --git a/wide.c b/wide.c new file mode 100644 index 0000000..7e339c5 --- /dev/null +++ b/wide.c @@ -0,0 +1,26 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include "wide.h" +#include "tts_curses.h" + +#ifdef NEED_TTS_WGETCH +static int +tts_wgetch(win, d) + WINDOW *win; + int *d; +{ +int c; + if ((c = wgetch(win)) == ERR) + return ERR; + *d = c; + return OK; +} +#endif /* !NEED_TTS_WGETCH */ diff --git a/wide.h b/wide.h new file mode 100644 index 0000000..2ef92ab --- /dev/null +++ b/wide.h @@ -0,0 +1,24 @@ +/* + * TTS - track your time. + * Copyright (c) 2012-2014 Felicity Tarnell. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely. This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef TTS_WIDE_H +#define TTS_WIDE_H + +#include + +#include "config.h" +#include "tts_curses.h" + +#define wsizeof(s) (sizeof(s) / sizeof(wchar_t)) + +int input_char (WINDOW *, wint_t *); +void input_macro (wchar_t *); + +#endif /* !TTS_WIDE_H */