2 $Header: /cvs/src/tdl/add.c,v 1.16.2.1 2004/01/07 00:09:05 richard Exp $
4 tdl - A console program for managing to-do lists
5 Copyright (C) 2001,2002,2003,2004,2005 Richard P. Curnow
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
26 static int add_new_node(char *parent_path, int set_done, int set_priority, enum Priority new_priority, time_t insert_time, time_t required_by, char *child_text)/*{{{*/
28 struct node *parent = NULL;
32 parent = lookup_node(parent_path, 0, NULL);
33 if (!parent) return -1;
35 struct node *narrow_top;
36 narrow_top = get_narrow_top();
40 /* If all else fails, i.e. new node is a top-level one. */
46 nn->text = new_string(child_text);
47 nn->arrived = (long) insert_time;
49 nn->done = (long) insert_time;
51 nn->required_by = required_by;
53 nn->priority = (parent && !set_priority) ? parent->priority
56 prepend_child(nn, parent);
58 /* Clear done status of parents - they can't be any longer! */
62 parent = parent->parent;
69 static char *make_composite(char *prefix, char *suffix)/*{{{*/
76 plen = prefix ? strlen(prefix) : 0;
77 slen = suffix ? strlen(suffix) : 0;
78 suffix_is_dot = slen ? (!strcmp(suffix,".")) : 0;
80 if (plen && slen) ++tlen; /* for internal '.' */
81 if (!plen && !slen) return NULL;
82 result = new_array(char, 1+tlen);
85 strcat(result, prefix);
86 if (slen && !suffix_is_dot) strcat(result, ".");
88 if (slen && !suffix_is_dot) strcat(result, suffix);
92 static int try_add_interactive(char *parent_path, int set_done)/*{{{*/
101 char *composite_index;
103 composite_index = make_composite(get_narrow_prefix(), parent_path);
105 prompt_base = set_done ? "log" : "add";
106 if (composite_index) {
107 sprintf(prompt, "%s (%s)> ", prompt_base, composite_index);
109 sprintf(prompt, "%s> ", prompt_base);
111 if (composite_index) free(composite_index);
114 text = interactive_text(prompt, NULL, &blank, &error);
115 if (error < 0) return error;
118 status = add_new_node(parent_path, set_done, 0, PRI_NORMAL, insert_time, 0, text);
120 if (status < 0) return status;
126 static int could_be_index(char *x)/*{{{*/
128 enum {AFTER_DIGIT, AFTER_PERIOD, AFTER_MINUS} state;
130 if (x[0] == '.') return 1; /* To handle alphabetical matching */
131 state = AFTER_PERIOD;
135 if (isdigit(*p)) state = AFTER_DIGIT;
136 else if (*p == '-') state = AFTER_MINUS;
137 else if (*p == '.') state = AFTER_PERIOD;
141 if (isdigit(*p)) state = AFTER_DIGIT;
142 else if (*p == '-') state = AFTER_MINUS;
146 if (isdigit(*p)) state = AFTER_DIGIT;
154 static int process_add_internal(char **x, int set_done)/*{{{*/
156 /* Expect 1 argument, the string to add. Need other options at some point. */
158 int argc = count_args(x);
160 char *parent_path = NULL;
161 enum Priority priority = PRI_NORMAL;
162 int set_priority = 0;
167 insert_time = time(NULL);
170 if ((argc > 1) && (x[0][0] == '@')) {
172 /* For 'add', want date to be in the future.
173 * For 'log', want date to be in the past, as for 'done' */
174 int default_positive = set_done ? 0 : 1;
175 insert_time = parse_date(x[0]+1, insert_time, default_positive, &error);
176 if (error < 0) return error;
181 if ((argc > 1) && (x[0][0] == '+')) {
183 required_by = parse_date(x[0]+1, insert_time, 1, &error);
184 if (error < 0) return error;
191 return try_add_interactive(NULL, set_done);
194 if (could_be_index(x[0])) {
195 return try_add_interactive(x[0], set_done);
203 if (isdigit(x0[0]) || (x0[0] == '.') || (x0[0] == '-') || (x0[0] == '+')) {
206 priority = parse_priority(x0, &error);
207 if (error < 0) return error;
213 priority = parse_priority(x[1], &error);
214 if (error < 0) return error;
220 fprintf(stderr, "Usage : add [@<starting datespec>] [+<due datespec>] [<parent_index>] [<priority>] <entry_text>\n");
225 return add_new_node(parent_path, set_done, set_priority, priority, insert_time, required_by, text);
230 int process_add(char **x)/*{{{*/
232 return process_add_internal(x, 0);
235 int process_log(char **x)/*{{{*/
237 return process_add_internal(x, 1);
240 static void modify_tree_arrival_time(struct node *y, time_t new_time)/*{{{*/
243 for (c = y->kids.next; c != (struct node *) &y->kids; c = c->chain.next) {
244 c->arrived = new_time;
246 modify_tree_arrival_time(c, new_time);
251 static int internal_postpone_open(char **x, time_t when)/*{{{*/
257 do_descendents = include_descendents(*x); /* May modify *x */
258 n = lookup_node(*x, 0, NULL);
261 if (do_descendents) modify_tree_arrival_time(n, when);
268 int process_postpone(char **x)/*{{{*/
270 return internal_postpone_open(x, POSTPONED_TIME);
273 int process_open(char **x)/*{{{*/
275 return internal_postpone_open(x, time(NULL));
278 int process_defer(char **x)/*{{{*/
281 time_t new_start_time;
285 argc = count_args(x);
287 fprintf(stderr, "Usage: defer <datespec> <index>...\n");
292 new_start_time = time(NULL);
293 /* 'defer' always takes a date so the @ is optional. */
294 if (*date_start == '@') date_start++;
295 new_start_time = parse_date(date_start, new_start_time, 1, &error);
296 return internal_postpone_open(x+1, new_start_time);
299 int process_edit(char **x) /*{{{*/
304 argc = count_args(x);
306 if ((argc < 1) || (argc > 2)) {
307 fprintf(stderr, "Usage: edit <path> [<new_text>]\n");
311 n = lookup_node(x[0], 0, NULL);
315 n->text = new_string(x[1]);
321 char *composite_index;
323 composite_index = make_composite(get_narrow_prefix(), x[0]);
324 assert(composite_index);
325 sprintf(prompt, "edit (%s)> ", composite_index);
326 new_text = interactive_text(prompt, n->text, &is_blank, &error);
327 free(composite_index);
328 if (error < 0) return error;
331 n->text = new_text; /* We own the pointer now */