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, 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;
52 nn->priority = (parent && !set_priority) ? parent->priority
55 prepend_child(nn, parent);
57 /* Clear done status of parents - they can't be any longer! */
61 parent = parent->parent;
68 static char *make_composite(char *prefix, char *suffix)/*{{{*/
75 plen = prefix ? strlen(prefix) : 0;
76 slen = suffix ? strlen(suffix) : 0;
77 suffix_is_dot = slen ? (!strcmp(suffix,".")) : 0;
79 if (plen && slen) ++tlen; /* for internal '.' */
80 if (!plen && !slen) return NULL;
81 result = new_array(char, 1+tlen);
84 strcat(result, prefix);
85 if (slen && !suffix_is_dot) strcat(result, ".");
87 if (slen && !suffix_is_dot) strcat(result, suffix);
91 static int try_add_interactive(char *parent_path, int set_done)/*{{{*/
100 char *composite_index;
102 composite_index = make_composite(get_narrow_prefix(), parent_path);
104 prompt_base = set_done ? "log" : "add";
105 if (composite_index) {
106 sprintf(prompt, "%s (%s)> ", prompt_base, composite_index);
108 sprintf(prompt, "%s> ", prompt_base);
110 if (composite_index) free(composite_index);
113 text = interactive_text(prompt, NULL, &blank, &error);
114 if (error < 0) return error;
117 status = add_new_node(parent_path, set_done, 0, PRI_NORMAL, insert_time, text);
119 if (status < 0) return status;
125 static int could_be_index(char *x)/*{{{*/
127 enum {AFTER_DIGIT, AFTER_PERIOD, AFTER_MINUS} state;
129 if (x[0] == '.') return 1; /* To handle alphabetical matching */
130 state = AFTER_PERIOD;
134 if (isdigit(*p)) state = AFTER_DIGIT;
135 else if (*p == '-') state = AFTER_MINUS;
136 else if (*p == '.') state = AFTER_PERIOD;
140 if (isdigit(*p)) state = AFTER_DIGIT;
141 else if (*p == '-') state = AFTER_MINUS;
145 if (isdigit(*p)) state = AFTER_DIGIT;
153 static int process_add_internal(char **x, int set_done)/*{{{*/
155 /* Expect 1 argument, the string to add. Need other options at some point. */
157 int argc = count_args(x);
159 char *parent_path = NULL;
160 enum Priority priority = PRI_NORMAL;
161 int set_priority = 0;
165 insert_time = time(NULL);
167 if ((argc > 1) && (x[0][0] == '@')) {
169 /* For 'add', want date to be in the future.
170 * For 'log', want date to be in the past, as for 'done' */
171 int default_positive = set_done ? 0 : 1;
172 insert_time = parse_date(x[0]+1, insert_time, default_positive, &error);
173 if (error < 0) return error;
180 return try_add_interactive(NULL, set_done);
183 if (could_be_index(x[0])) {
184 return try_add_interactive(x[0], set_done);
192 if (isdigit(x0[0]) || (x0[0] == '.') || (x0[0] == '-') || (x0[0] == '+')) {
195 priority = parse_priority(x0, &error);
196 if (error < 0) return error;
202 priority = parse_priority(x[1], &error);
203 if (error < 0) return error;
209 fprintf(stderr, "Usage : add [@<datespec>] [<parent_index>] [<priority>] <entry_text>\n");
214 return add_new_node(parent_path, set_done, set_priority, priority, insert_time, text);
219 int process_add(char **x)/*{{{*/
221 return process_add_internal(x, 0);
224 int process_log(char **x)/*{{{*/
226 return process_add_internal(x, 1);
229 static void modify_tree_arrival_time(struct node *y, time_t new_time)/*{{{*/
232 for (c = y->kids.next; c != (struct node *) &y->kids; c = c->chain.next) {
233 c->arrived = new_time;
235 modify_tree_arrival_time(c, new_time);
240 static int internal_postpone_open(char **x, time_t when)/*{{{*/
246 do_descendents = include_descendents(*x); /* May modify *x */
247 n = lookup_node(*x, 0, NULL);
250 if (do_descendents) modify_tree_arrival_time(n, when);
257 int process_postpone(char **x)/*{{{*/
259 return internal_postpone_open(x, POSTPONED_TIME);
262 int process_open(char **x)/*{{{*/
264 return internal_postpone_open(x, time(NULL));
267 int process_defer(char **x)/*{{{*/
270 time_t new_start_time;
274 argc = count_args(x);
276 fprintf(stderr, "Usage: defer <datespec> <index>...\n");
281 new_start_time = time(NULL);
282 /* 'defer' always takes a date so the @ is optional. */
283 if (*date_start == '@') date_start++;
284 new_start_time = parse_date(date_start, new_start_time, 1, &error);
285 return internal_postpone_open(x+1, new_start_time);
288 int process_edit(char **x) /*{{{*/
293 argc = count_args(x);
295 if ((argc < 1) || (argc > 2)) {
296 fprintf(stderr, "Usage: edit <path> [<new_text>]\n");
300 n = lookup_node(x[0], 0, NULL);
304 n->text = new_string(x[1]);
310 char *composite_index;
312 composite_index = make_composite(get_narrow_prefix(), x[0]);
313 assert(composite_index);
314 sprintf(prompt, "edit (%s)> ", composite_index);
315 new_text = interactive_text(prompt, n->text, &is_blank, &error);
316 free(composite_index);
317 if (error < 0) return error;
320 n->text = new_text; /* We own the pointer now */