Compare commits
No commits in common. "master" and "v83.4" have entirely different histories.
35 changed files with 3132 additions and 7032 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -1,14 +0,0 @@
|
||||||
*.o
|
|
||||||
*.swp
|
|
||||||
*~
|
|
||||||
/Makefile
|
|
||||||
/config.h
|
|
||||||
/config.log
|
|
||||||
/config.status
|
|
||||||
/tts
|
|
||||||
/vers.c
|
|
||||||
/build
|
|
||||||
/autom4te.cache
|
|
||||||
/doconf
|
|
||||||
/bling_import.pl.old
|
|
||||||
/queue.h
|
|
||||||
32
Makefile.in
32
Makefile.in
|
|
@ -1,25 +1,13 @@
|
||||||
# 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@
|
VPATH = @top_srcdir@
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
MAKEDEPEND = @CC@ -M
|
CPPFLAGS = @CPPFLAGS@
|
||||||
CPPFLAGS = @CPPFLAGS@ -D_XOPEN_SOURCE_EXTENDED
|
|
||||||
CFLAGS = @CFLAGS@ -I@top_srcdir@ -I@top_builddir@
|
CFLAGS = @CFLAGS@ -I@top_srcdir@ -I@top_builddir@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
|
|
||||||
OBJS = tts.o wide.o entry.o ui.o functions.o commands.o bindings.o \
|
OBJS = tts.o
|
||||||
str.o style.o wcslcpy.o
|
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
|
|
@ -35,22 +23,8 @@ install:
|
||||||
.c.o:
|
.c.o:
|
||||||
${CC} ${CPPFLAGS} ${CFLAGS} -c $<
|
${CC} ${CPPFLAGS} ${CFLAGS} -c $<
|
||||||
|
|
||||||
.c.d:
|
|
||||||
$(MAKEDEPEND) $(CPPFLAGS) $(CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
vers.c: vers.c.sh configure.ac
|
vers.c: vers.c.sh configure.ac
|
||||||
sh @top_srcdir@/vers.c.sh @top_srcdir@/configure.ac
|
sh @top_srcdir@/vers.c.sh @top_srcdir@/configure.ac
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f tts ${OBJS} $(OBJS:.o=.d)
|
rm -f tts *.o
|
||||||
|
|
||||||
depend: $(OBJS:.o=.d)
|
|
||||||
sed '/^# Do not remove this line -- make depend needs it/,$$ d' \
|
|
||||||
<Makefile >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
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,8 @@
|
||||||
TTS - Time-tracking software
|
TTS - Time-tracking software
|
||||||
============================
|
============================
|
||||||
|
|
||||||
TTS is a simple, text-based (curses) time-tracking application. It allows you
|
TTS is a simple, text-based (curses) time-tracking application. For more
|
||||||
to track the time you spend working by client, project, etc. to allow accurate
|
details, see the website at <http://loreley.flyingparchment.org.uk/~felicity/pages/tts>.
|
||||||
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
|
|
||||||
----------
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
TTS has been tested on FreeBSD, NetBSD, Solaris, Cygwin and Linux, with the
|
TTS has been tested on FreeBSD, NetBSD, Solaris, Cygwin and Linux, with the
|
||||||
following caveats:
|
following caveats:
|
||||||
|
|
@ -34,8 +21,7 @@ TTS uses autoconf and can be built as follows:
|
||||||
|
|
||||||
After starting with 'tts', type '?' for help.
|
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 'a' to add a new entry, and enter its name. The timer starts running.
|
||||||
* Press space to toggle the timer on and off.
|
* Press space to toggle the timer on and off.
|
||||||
|
|
@ -48,9 +34,6 @@ Quick start
|
||||||
start the interrupt timer. When you're done with the other thing, press 'r'
|
start the interrupt timer. When you're done with the other thing, press 'r'
|
||||||
again to assign the interrupt time to a new entry.
|
again to assign the interrupt time to a new entry.
|
||||||
|
|
||||||
Contact
|
### Contact
|
||||||
-------
|
|
||||||
|
|
||||||
To report problems or request features, please use the GitHub issue tracker at
|
Send questions/comments/bugs/patches to <felicity@loreley.flyingparchment.org.uk>.
|
||||||
<https://github.com/ftarnell/tts/issues>. This requires that you have a GitHub
|
|
||||||
account.
|
|
||||||
10
aclocal.m4
vendored
10
aclocal.m4
vendored
|
|
@ -108,7 +108,7 @@
|
||||||
# HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the
|
# HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the
|
||||||
# library supports the X/Open Enhanced Curses definition. In particular,
|
# library supports the X/Open Enhanced Curses definition. In particular,
|
||||||
# the wide-character types attr_t, cchar_t and wint_t, the functions
|
# the wide-character types attr_t, cchar_t and wint_t, the functions
|
||||||
# wattr_set() and wget_wch() and the macros WA_BOLD and _XOPEN_CURSES
|
# wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES
|
||||||
# are checked. The Ncurses library does NOT conform to this definition,
|
# are checked. The Ncurses library does NOT conform to this definition,
|
||||||
# although NcursesW does.
|
# although NcursesW does.
|
||||||
#
|
#
|
||||||
|
|
@ -228,7 +228,7 @@ AC_DEFUN([AX_WITH_CURSES], [
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
int g = getattrs(stdscr);
|
int g = getattrs(stdscr);
|
||||||
|
|
@ -259,7 +259,7 @@ AC_DEFUN([AX_WITH_CURSES], [
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
int g = getattrs(stdscr);
|
int g = getattrs(stdscr);
|
||||||
|
|
@ -290,7 +290,7 @@ AC_DEFUN([AX_WITH_CURSES], [
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
int g = getattrs(stdscr);
|
int g = getattrs(stdscr);
|
||||||
|
|
@ -443,7 +443,7 @@ AC_DEFUN([AX_WITH_CURSES], [
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
initscr();
|
initscr();
|
||||||
|
|
|
||||||
194
bindings.c
194
bindings.c
|
|
@ -1,194 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdlib.h>
|
|
||||||
|
|
||||||
#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"<BREAK>" },
|
|
||||||
{ KEY_DOWN, L"<DOWN>" },
|
|
||||||
{ KEY_UP, L"<UP>" },
|
|
||||||
{ KEY_LEFT, L"<LEFT>" },
|
|
||||||
{ KEY_RIGHT, L"<RIGHT>" },
|
|
||||||
{ KEY_HOME, L"<HOME>" },
|
|
||||||
{ KEY_BACKSPACE, L"<BACKSPACE>" },
|
|
||||||
{ 0x7F, L"<BACKSPACE>" }, /* DEL */
|
|
||||||
{ KEY_F(0), L"<F0>" },
|
|
||||||
{ KEY_F(1), L"<F1>" },
|
|
||||||
{ KEY_F(2), L"<F2>" },
|
|
||||||
{ KEY_F(3), L"<F3>" },
|
|
||||||
{ KEY_F(4), L"<F4>" },
|
|
||||||
{ KEY_F(5), L"<F5>" },
|
|
||||||
{ KEY_F(6), L"<F6>" },
|
|
||||||
{ KEY_F(7), L"<F7>" },
|
|
||||||
{ KEY_F(8), L"<F8>" },
|
|
||||||
{ KEY_F(9), L"<F9>" },
|
|
||||||
{ KEY_F(10), L"<F10>" },
|
|
||||||
{ KEY_F(11), L"<F1l>" },
|
|
||||||
{ KEY_F(12), L"<F12>" },
|
|
||||||
{ KEY_F(13), L"<F13>" },
|
|
||||||
{ KEY_F(14), L"<F14>" },
|
|
||||||
{ KEY_F(15), L"<F15>" },
|
|
||||||
{ KEY_F(16), L"<F16>" },
|
|
||||||
{ KEY_F(17), L"<F17>" },
|
|
||||||
{ KEY_F(18), L"<F18>" },
|
|
||||||
{ KEY_F(19), L"<F19>" },
|
|
||||||
{ KEY_F(20), L"<F20>" },
|
|
||||||
{ KEY_F(21), L"<F21>" },
|
|
||||||
{ KEY_F(22), L"<F22>" },
|
|
||||||
{ KEY_F(23), L"<F23>" },
|
|
||||||
{ KEY_F(24), L"<F24>" },
|
|
||||||
{ KEY_NPAGE, L"<NEXT>" },
|
|
||||||
{ KEY_PPAGE, L"<PREV>" },
|
|
||||||
{ '\001', L"<CTRL-A>" },
|
|
||||||
{ '\002', L"<CTRL-B>" },
|
|
||||||
{ '\003', L"<CTRL-C>" },
|
|
||||||
{ '\004', L"<CTRL-D>" },
|
|
||||||
{ '\005', L"<CTRL-E>" },
|
|
||||||
{ '\006', L"<CTRL-F>" },
|
|
||||||
{ '\007', L"<CTRL-G>" },
|
|
||||||
{ '\010', L"<CTRL-H>" },
|
|
||||||
{ '\011', L"<CTRL-I>" },
|
|
||||||
{ '\011', L"<TAB>" },
|
|
||||||
{ '\012', L"<CTRL-J>" },
|
|
||||||
{ '\013', L"<CTRL-K>" },
|
|
||||||
{ '\014', L"<CTRL-L>" },
|
|
||||||
{ '\015', L"<CTRL-N>" },
|
|
||||||
{ '\016', L"<CTRL-O>" },
|
|
||||||
{ '\017', L"<CTRL-P>" },
|
|
||||||
{ '\020', L"<CTRL-Q>" },
|
|
||||||
{ '\021', L"<CTRL-R>" },
|
|
||||||
{ '\022', L"<CTRL-S>" },
|
|
||||||
{ '\023', L"<CTRL-T>" },
|
|
||||||
{ '\024', L"<CTRL-U>" },
|
|
||||||
{ '\025', L"<CTRL-V>" },
|
|
||||||
{ '\026', L"<CTRL-W>" },
|
|
||||||
{ '\027', L"<CTRL-X>" },
|
|
||||||
{ '\030', L"<CTRL-Y>" },
|
|
||||||
{ '\031', L"<CTRL-Z>" },
|
|
||||||
{ ' ', L"<SPACE>" },
|
|
||||||
{ KEY_ENTER, L"<ENTER>" },
|
|
||||||
{ KEY_BACKSPACE, L"<BACKSPACE>" },
|
|
||||||
{ KEY_DC, L"<DELETE>" }
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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"<CTRL-C>", 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"<SPACE>", L"startstop", 0);
|
|
||||||
bind_key(L"e", L"edit-desc", 0);
|
|
||||||
bind_key(L"\\", L"edit-time", 0);
|
|
||||||
bind_key(L"<TAB>", 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"<UP>", L"prev", 0);
|
|
||||||
bind_key(L"<DOWN>", 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);
|
|
||||||
}
|
|
||||||
40
bindings.h
40
bindings.h
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
use strict;
|
use strict;
|
||||||
use LWP::Protocol::https;
|
|
||||||
use LWP::UserAgent;
|
use LWP::UserAgent;
|
||||||
use URI::Escape qw/uri_escape/;
|
use URI::Escape qw/uri_escape/;
|
||||||
use POSIX qw/strftime/;
|
use POSIX qw/strftime/;
|
||||||
|
|
@ -90,7 +89,7 @@ while (<INF>) {
|
||||||
if ($res->is_success) {
|
if ($res->is_success) {
|
||||||
my $resp = decode_json($res->content);
|
my $resp = decode_json($res->content);
|
||||||
if (defined($resp->{description})) {
|
if (defined($resp->{description})) {
|
||||||
print "Failed to Bling [$desc]: " . $resp->{description} . "\n";
|
print "Failed to Bling [$desc]: " . $resp->description . "\n";
|
||||||
} else {
|
} else {
|
||||||
if ($flags eq "-") {
|
if ($flags eq "-") {
|
||||||
$flags = "i";
|
$flags = "i";
|
||||||
|
|
|
||||||
157
commands.c
157
commands.c
|
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdlib.h>
|
|
||||||
|
|
||||||
#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 <item> <foreground> [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 <key> <function>");
|
|
||||||
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 <key> <def>");
|
|
||||||
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 <variable> <value>");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
33
commands.h
33
commands.h
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdarg.h>
|
|
||||||
|
|
||||||
#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 */
|
|
||||||
1558
config.guess
vendored
1558
config.guess
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -24,9 +24,6 @@
|
||||||
/* Define to 1 if you have the `IORegisterForSystemPower' function. */
|
/* Define to 1 if you have the `IORegisterForSystemPower' function. */
|
||||||
#undef HAVE_IOREGISTERFORSYSTEMPOWER
|
#undef HAVE_IOREGISTERFORSYSTEMPOWER
|
||||||
|
|
||||||
/* Define to 1 if you have the `m' library (-lm). */
|
|
||||||
#undef HAVE_LIBM
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <memory.h> header file. */
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
#undef HAVE_MEMORY_H
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
|
@ -72,12 +69,6 @@
|
||||||
/* Define to 1 if you have the `use_default_colors' function. */
|
/* Define to 1 if you have the `use_default_colors' function. */
|
||||||
#undef HAVE_USE_DEFAULT_COLORS
|
#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. */
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
#undef PACKAGE_BUGREPORT
|
#undef PACKAGE_BUGREPORT
|
||||||
|
|
||||||
|
|
|
||||||
1788
config.sub
vendored
1788
config.sub
vendored
File diff suppressed because it is too large
Load diff
229
configure
vendored
229
configure
vendored
|
|
@ -1,8 +1,8 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for TTS D.84.1.
|
# Generated by GNU Autoconf 2.69 for RT/TTS T.83.4.
|
||||||
#
|
#
|
||||||
# Report bugs to <ft@le-fay.org>.
|
# Report bugs to <felicity@loreley.flyingparchment.org.uk>.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
# 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: In particular, zsh $ZSH_VERSION has bugs and should"
|
||||||
$as_echo "$0: be upgraded to zsh 4.3.4 or later."
|
$as_echo "$0: be upgraded to zsh 4.3.4 or later."
|
||||||
else
|
else
|
||||||
$as_echo "$0: Please tell bug-autoconf@gnu.org and ft@le-fay.org
|
$as_echo "$0: Please tell bug-autoconf@gnu.org and
|
||||||
$0: about your system, including any error possibly output
|
$0: felicity@loreley.flyingparchment.org.uk about your
|
||||||
$0: before this message. Then install a modern shell, or
|
$0: system, including any error possibly output before this
|
||||||
$0: manually run the script under such a shell if you do
|
$0: message. Then install a modern shell, or manually run
|
||||||
$0: have one."
|
$0: the script under such a shell if you do have one."
|
||||||
fi
|
fi
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -578,11 +578,11 @@ MFLAGS=
|
||||||
MAKEFLAGS=
|
MAKEFLAGS=
|
||||||
|
|
||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='TTS'
|
PACKAGE_NAME='RT/TTS'
|
||||||
PACKAGE_TARNAME='tts'
|
PACKAGE_TARNAME='rt-tts'
|
||||||
PACKAGE_VERSION='D.84.1'
|
PACKAGE_VERSION='T.83.4'
|
||||||
PACKAGE_STRING='TTS D.84.1'
|
PACKAGE_STRING='RT/TTS T.83.4'
|
||||||
PACKAGE_BUGREPORT='ft@le-fay.org'
|
PACKAGE_BUGREPORT='felicity@loreley.flyingparchment.org.uk'
|
||||||
PACKAGE_URL=''
|
PACKAGE_URL=''
|
||||||
|
|
||||||
ac_unique_file="tts.c"
|
ac_unique_file="tts.c"
|
||||||
|
|
@ -638,14 +638,6 @@ CPPFLAGS
|
||||||
LDFLAGS
|
LDFLAGS
|
||||||
CFLAGS
|
CFLAGS
|
||||||
CC
|
CC
|
||||||
host_os
|
|
||||||
host_vendor
|
|
||||||
host_cpu
|
|
||||||
host
|
|
||||||
build_os
|
|
||||||
build_vendor
|
|
||||||
build_cpu
|
|
||||||
build
|
|
||||||
target_alias
|
target_alias
|
||||||
host_alias
|
host_alias
|
||||||
build_alias
|
build_alias
|
||||||
|
|
@ -1240,7 +1232,7 @@ if test "$ac_init_help" = "long"; then
|
||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# 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.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures TTS D.84.1 to adapt to many kinds of systems.
|
\`configure' configures RT/TTS T.83.4 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
|
|
@ -1288,7 +1280,7 @@ Fine tuning of the installation directories:
|
||||||
--infodir=DIR info documentation [DATAROOTDIR/info]
|
--infodir=DIR info documentation [DATAROOTDIR/info]
|
||||||
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
|
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
|
||||||
--mandir=DIR man documentation [DATAROOTDIR/man]
|
--mandir=DIR man documentation [DATAROOTDIR/man]
|
||||||
--docdir=DIR documentation root [DATAROOTDIR/doc/tts]
|
--docdir=DIR documentation root [DATAROOTDIR/doc/rt-tts]
|
||||||
--htmldir=DIR html documentation [DOCDIR]
|
--htmldir=DIR html documentation [DOCDIR]
|
||||||
--dvidir=DIR dvi documentation [DOCDIR]
|
--dvidir=DIR dvi documentation [DOCDIR]
|
||||||
--pdfdir=DIR pdf documentation [DOCDIR]
|
--pdfdir=DIR pdf documentation [DOCDIR]
|
||||||
|
|
@ -1296,16 +1288,12 @@ Fine tuning of the installation directories:
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
cat <<\_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
|
_ACEOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of TTS D.84.1:";;
|
short | recursive ) echo "Configuration of RT/TTS T.83.4:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
|
|
@ -1329,7 +1317,7 @@ Some influential environment variables:
|
||||||
Use these variables to override the choices made by `configure' or to help
|
Use these variables to override the choices made by `configure' or to help
|
||||||
it to find libraries and programs with nonstandard names/locations.
|
it to find libraries and programs with nonstandard names/locations.
|
||||||
|
|
||||||
Report bugs to <ft@le-fay.org>.
|
Report bugs to <felicity@loreley.flyingparchment.org.uk>.
|
||||||
_ACEOF
|
_ACEOF
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
fi
|
fi
|
||||||
|
|
@ -1392,7 +1380,7 @@ fi
|
||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
TTS configure D.84.1
|
RT/TTS configure T.83.4
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
|
|
@ -1664,9 +1652,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: 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:${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 "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
|
||||||
( $as_echo "## ---------------------------- ##
|
( $as_echo "## ------------------------------------------------------ ##
|
||||||
## Report this to ft@le-fay.org ##
|
## Report this to felicity@loreley.flyingparchment.org.uk ##
|
||||||
## ---------------------------- ##"
|
## ------------------------------------------------------ ##"
|
||||||
) | sed "s/^/$as_me: WARNING: /" >&2
|
) | sed "s/^/$as_me: WARNING: /" >&2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -1761,7 +1749,7 @@ cat >config.log <<_ACEOF
|
||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by TTS $as_me D.84.1, which was
|
It was created by RT/TTS $as_me T.83.4, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
|
|
@ -2113,122 +2101,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||||
ac_config_headers="$ac_config_headers config.h"
|
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_ext=c
|
||||||
ac_cpp='$CPP $CPPFLAGS'
|
ac_cpp='$CPP $CPPFLAGS'
|
||||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||||
|
|
@ -3018,6 +2890,35 @@ 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_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
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),
|
# Find a good install program. We prefer a C program (faster),
|
||||||
# so one script is as good as another. But avoid the broken or
|
# so one script is as good as another. But avoid the broken or
|
||||||
# incompatible versions:
|
# incompatible versions:
|
||||||
|
|
@ -3219,7 +3120,7 @@ main ()
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
int g = getattrs(stdscr);
|
int g = getattrs(stdscr);
|
||||||
|
|
@ -3283,7 +3184,7 @@ main ()
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
int g = getattrs(stdscr);
|
int g = getattrs(stdscr);
|
||||||
|
|
@ -3347,7 +3248,7 @@ main ()
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
int g = getattrs(stdscr);
|
int g = getattrs(stdscr);
|
||||||
|
|
@ -3711,7 +3612,7 @@ main ()
|
||||||
chtype a = A_BOLD;
|
chtype a = A_BOLD;
|
||||||
int b = KEY_LEFT;
|
int b = KEY_LEFT;
|
||||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||||
attr_t d = WA_BOLD;
|
attr_t d = WA_NORMAL;
|
||||||
cchar_t e;
|
cchar_t e;
|
||||||
wint_t f;
|
wint_t f;
|
||||||
initscr();
|
initscr();
|
||||||
|
|
@ -3870,20 +3771,14 @@ fi
|
||||||
|
|
||||||
LIBS=$ax_saved_LIBS
|
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"
|
oLIBS="$LIBS"
|
||||||
LIBS="$LIBS $CURSES_LIB"
|
LIBS="$LIBS $CURSES_LIB"
|
||||||
for ac_func in use_default_colors wcslcpy wcslcat
|
for ac_func in use_default_colors
|
||||||
do :
|
do :
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
ac_fn_c_check_func "$LINENO" "use_default_colors" "ac_cv_func_use_default_colors"
|
||||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
if test "x$ac_cv_func_use_default_colors" = xyes; then :
|
||||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
#define HAVE_USE_DEFAULT_COLORS 1
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
@ -4348,7 +4243,7 @@ fi
|
||||||
|
|
||||||
|
|
||||||
oLDFLAGS="$LDFLAGS"
|
oLDFLAGS="$LDFLAGS"
|
||||||
LDFLAGS="$LDFLAGS -framework IOKit"
|
LDFLAGS="$LDFLAGS -framework CoreFoundation -framework IOKit"
|
||||||
for ac_func in IORegisterForSystemPower
|
for ac_func in IORegisterForSystemPower
|
||||||
do :
|
do :
|
||||||
ac_fn_c_check_func "$LINENO" "IORegisterForSystemPower" "ac_cv_func_IORegisterForSystemPower"
|
ac_fn_c_check_func "$LINENO" "IORegisterForSystemPower" "ac_cv_func_IORegisterForSystemPower"
|
||||||
|
|
@ -4871,7 +4766,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by TTS $as_me D.84.1, which was
|
This file was extended by RT/TTS $as_me T.83.4, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
|
|
@ -4927,13 +4822,13 @@ $config_files
|
||||||
Configuration headers:
|
Configuration headers:
|
||||||
$config_headers
|
$config_headers
|
||||||
|
|
||||||
Report bugs to <ft@le-fay.org>."
|
Report bugs to <felicity@loreley.flyingparchment.org.uk>."
|
||||||
|
|
||||||
_ACEOF
|
_ACEOF
|
||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
TTS config.status D.84.1
|
RT/TTS config.status T.83.4
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|
|
||||||
26
configure.ac
26
configure.ac
|
|
@ -1,35 +1,15 @@
|
||||||
AC_PREREQ([2.69])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([TTS], [D.84.1], [ft@le-fay.org])
|
AC_INIT([RT/TTS], [T.83.4], [felicity@loreley.flyingparchment.org.uk])
|
||||||
AC_CONFIG_SRCDIR([tts.c])
|
AC_CONFIG_SRCDIR([tts.c])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
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_CC
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
|
||||||
AX_WITH_CURSES
|
AX_WITH_CURSES
|
||||||
AS_IF([test "x$ax_cv_curses" != xyes], [
|
|
||||||
AC_ERROR([XSI/SVR4 curses is required to compile TTS])
|
|
||||||
])
|
|
||||||
oLIBS="$LIBS"
|
oLIBS="$LIBS"
|
||||||
LIBS="$LIBS $CURSES_LIB"
|
LIBS="$LIBS $CURSES_LIB"
|
||||||
AC_CHECK_FUNCS([use_default_colors wcslcpy wcslcat])
|
AC_CHECK_FUNCS([use_default_colors])
|
||||||
LIBS="$oLIBS"
|
LIBS="$oLIBS"
|
||||||
|
|
||||||
AC_CHECK_HEADERS([IOKit/pwr_mgt/IOPMLib.h])
|
AC_CHECK_HEADERS([IOKit/pwr_mgt/IOPMLib.h])
|
||||||
|
|
@ -37,7 +17,7 @@ AC_CHECK_HEADERS([IOKit/pwr_mgt/IOPMLib.h])
|
||||||
AC_CHECK_LIB(m, round)
|
AC_CHECK_LIB(m, round)
|
||||||
|
|
||||||
oLDFLAGS="$LDFLAGS"
|
oLDFLAGS="$LDFLAGS"
|
||||||
LDFLAGS="$LDFLAGS -framework IOKit"
|
LDFLAGS="$LDFLAGS -framework CoreFoundation -framework IOKit"
|
||||||
AC_CHECK_FUNCS([IORegisterForSystemPower], [], [LDFLAGS="$oLDFLAGS"])
|
AC_CHECK_FUNCS([IORegisterForSystemPower], [], [LDFLAGS="$oLDFLAGS"])
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
|
|
|
||||||
124
entry.c
124
entry.c
|
|
@ -1,124 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
59
entry.h
59
entry.h
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <time.h>
|
|
||||||
|
|
||||||
#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 */
|
|
||||||
761
functions.c
761
functions.c
|
|
@ -1,761 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdlib.h>
|
|
||||||
|
|
||||||
#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 (<ENTER> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
51
functions.h
51
functions.h
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
611
queue.h
Normal file
611
queue.h
Normal file
|
|
@ -0,0 +1,611 @@
|
||||||
|
/*-
|
||||||
|
* 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 */
|
||||||
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
|
Before Width: | Height: | Size: 116 KiB |
277
str.c
277
str.c
|
|
@ -1,277 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stddef.h>
|
|
||||||
#include <wctype.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
36
str.h
36
str.h
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdlib.h>
|
|
||||||
|
|
||||||
#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 */
|
|
||||||
146
style.c
146
style.c
|
|
@ -1,146 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
54
style.h
54
style.h
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
163
tailq.h
163
tailq.h
|
|
@ -1,163 +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_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 */
|
|
||||||
78
tts.h
78
tts.h
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <signal.h>
|
|
||||||
|
|
||||||
#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 */
|
|
||||||
30
tts_curses.h
30
tts_curses.h
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <ncursesw/curses.h>
|
|
||||||
#elif defined HAVE_NCURSESW_H
|
|
||||||
# include <ncursesw.h>
|
|
||||||
#elif defined HAVE_NCURSES_CURSES_H
|
|
||||||
# include <ncurses/curses.h>
|
|
||||||
#elif defined HAVE_NCURSES_H
|
|
||||||
# include <ncurses.h>
|
|
||||||
#elif defined HAVE_CURSES_H
|
|
||||||
# include <curses.h>
|
|
||||||
#else
|
|
||||||
# error "SVR4 or XSI compatible curses header file required"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !TTS_CURSES_H */
|
|
||||||
26
ttsrc.sample
26
ttsrc.sample
|
|
@ -11,15 +11,6 @@
|
||||||
#set mark_advance 1
|
#set mark_advance 1
|
||||||
#set delete_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
|
#### Billing options
|
||||||
#
|
#
|
||||||
# If set, show billable time in each daily summary.
|
# If set, show billable time in each daily summary.
|
||||||
|
|
@ -42,7 +33,7 @@
|
||||||
|
|
||||||
#set bill_advance 0
|
#set bill_advance 0
|
||||||
|
|
||||||
#### Bindings and macros
|
#### Bindings
|
||||||
#
|
#
|
||||||
# Use the 'bind' command to (re)define keybindings. Type '?' while TTS is
|
# Use the 'bind' command to (re)define keybindings. Type '?' while TTS is
|
||||||
# running for a full list of key bindings.
|
# running for a full list of key bindings.
|
||||||
|
|
@ -54,17 +45,6 @@
|
||||||
bind j next
|
bind j next
|
||||||
bind k prev
|
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
|
#### Styling
|
||||||
#
|
#
|
||||||
# You can style UI elements with the 'style' command. Its syntax is:
|
# You can style UI elements with the 'style' command. Its syntax is:
|
||||||
|
|
@ -121,8 +101,8 @@ bind k prev
|
||||||
#
|
#
|
||||||
style header yellow,bold blue
|
style header yellow,bold blue
|
||||||
style status yellow,bold blue
|
style status yellow,bold blue
|
||||||
style date white,underline black
|
|
||||||
style entry white black
|
style entry white black
|
||||||
style selected yellow,bold red
|
style selected yellow,bold red
|
||||||
# Use bold *and* underline, because we already bolded 'selected' above.
|
# Use bold *and* underline, because we already bolded 'selected' above.
|
||||||
style running white,bold,underline black
|
style running bold,underline
|
||||||
|
style date underline,bold
|
||||||
|
|
|
||||||
666
ui.c
666
ui.c
|
|
@ -1,666 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#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" <OK> "
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
38
ui.h
38
ui.h
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdarg.h>
|
|
||||||
|
|
||||||
#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 */
|
|
||||||
28
variable.h
28
variable.h
|
|
@ -1,28 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
99
wcslcpy.c
99
wcslcpy.c
|
|
@ -1,99 +0,0 @@
|
||||||
/* $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 <Todd.Miller@courtesan.com>
|
|
||||||
*
|
|
||||||
* 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 <sys/types.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
26
wide.c
26
wide.c
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
24
wide.h
24
wide.h
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <wchar.h>
|
|
||||||
|
|
||||||
#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 */
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue