]> Joshua Wise's Git repositories - tdl.git/blame_incremental - add.c
Fall back on index for sort if the due date is the same, not just if both due dates...
[tdl.git] / add.c
... / ...
CommitLineData
1/*
2 $Header: /cvs/src/tdl/add.c,v 1.16.2.1 2004/01/07 00:09:05 richard Exp $
3
4 tdl - A console program for managing to-do lists
5 Copyright (C) 2001,2002,2003,2004,2005 Richard P. Curnow
6
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.
11
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.
16
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
20 */
21
22#include <assert.h>
23#include <ctype.h>
24#include "tdl.h"
25
26static 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)/*{{{*/
27{
28 struct node *parent = NULL;
29 struct node *nn;
30
31 if (parent_path) {
32 parent = lookup_node(parent_path, 0, NULL);
33 if (!parent) return -1;
34 } else {
35 struct node *narrow_top;
36 narrow_top = get_narrow_top();
37 if (narrow_top) {
38 parent = narrow_top;
39 } else {
40 /* If all else fails, i.e. new node is a top-level one. */
41 parent = NULL;
42 }
43 }
44
45 nn = new_node();
46 nn->text = new_string(child_text);
47 nn->arrived = (long) insert_time;
48 if (set_done) {
49 nn->done = (long) insert_time;
50 }
51 nn->required_by = required_by;
52
53 nn->priority = (parent && !set_priority) ? parent->priority
54 : new_priority;
55
56 prepend_child(nn, parent);
57
58 /* Clear done status of parents - they can't be any longer! */
59 if (!set_done) {
60 while (parent) {
61 parent->done = 0;
62 parent = parent->parent;
63 }
64 }
65
66 return 0;
67}
68/*}}}*/
69static char *make_composite(char *prefix, char *suffix)/*{{{*/
70{
71 int plen, slen;
72 int tlen;
73 char *result;
74 int suffix_is_dot;
75
76 plen = prefix ? strlen(prefix) : 0;
77 slen = suffix ? strlen(suffix) : 0;
78 suffix_is_dot = slen ? (!strcmp(suffix,".")) : 0;
79 tlen = plen + slen;
80 if (plen && slen) ++tlen; /* for internal '.' */
81 if (!plen && !slen) return NULL;
82 result = new_array(char, 1+tlen);
83 result[0] = '\0';
84 if (plen) {
85 strcat(result, prefix);
86 if (slen && !suffix_is_dot) strcat(result, ".");
87 }
88 if (slen && !suffix_is_dot) strcat(result, suffix);
89 return result;
90}
91/*}}}*/
92static int try_add_interactive(char *parent_path, int set_done)/*{{{*/
93{
94 char *text;
95 time_t insert_time;
96 int error = 0;
97 int blank;
98 int status;
99 char prompt[128];
100 char *prompt_base;
101 char *composite_index;
102
103 composite_index = make_composite(get_narrow_prefix(), parent_path);
104
105 prompt_base = set_done ? "log" : "add";
106 if (composite_index) {
107 sprintf(prompt, "%s (%s)> ", prompt_base, composite_index);
108 } else {
109 sprintf(prompt, "%s> ", prompt_base);
110 }
111 if (composite_index) free(composite_index);
112
113 do {
114 text = interactive_text(prompt, NULL, &blank, &error);
115 if (error < 0) return error;
116 if (!blank) {
117 time(&insert_time);
118 status = add_new_node(parent_path, set_done, 0, PRI_NORMAL, insert_time, 0, text);
119 free(text);
120 if (status < 0) return status;
121 }
122 } while (!blank);
123 return 0;
124}
125/*}}}*/
126static int could_be_index(char *x)/*{{{*/
127{
128 enum {AFTER_DIGIT, AFTER_PERIOD, AFTER_MINUS} state;
129 char *p;
130 if (x[0] == '.') return 1; /* To handle alphabetical matching */
131 state = AFTER_PERIOD;
132 for (p=x; *p; p++) {
133 switch (state) {
134 case AFTER_DIGIT:
135 if (isdigit(*p)) state = AFTER_DIGIT;
136 else if (*p == '-') state = AFTER_MINUS;
137 else if (*p == '.') state = AFTER_PERIOD;
138 else return 0;
139 break;
140 case AFTER_PERIOD:
141 if (isdigit(*p)) state = AFTER_DIGIT;
142 else if (*p == '-') state = AFTER_MINUS;
143 else return 0;
144 break;
145 case AFTER_MINUS:
146 if (isdigit(*p)) state = AFTER_DIGIT;
147 else return 0;
148 break;
149 }
150 }
151 return 1;
152}
153/*}}}*/
154static int process_add_internal(char **x, int set_done)/*{{{*/
155{
156 /* Expect 1 argument, the string to add. Need other options at some point. */
157 time_t insert_time;
158 int argc = count_args(x);
159 char *text = NULL;
160 char *parent_path = NULL;
161 enum Priority priority = PRI_NORMAL;
162 int set_priority = 0;
163 char *x0;
164 int error;
165 time_t required_by;
166
167 insert_time = time(NULL);
168 required_by = 0;
169
170 if ((argc > 1) && (x[0][0] == '@')) {
171 int error;
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;
177 argc--;
178 x++;
179 }
180
181 if ((argc > 1) && (x[0][0] == '+')) {
182 int error;
183 required_by = parse_date(x[0]+1, insert_time, 1, &error);
184 if (error < 0) return error;
185 argc--;
186 x++;
187 }
188
189 switch (argc) {
190 case 0:
191 return try_add_interactive(NULL, set_done);
192 break;
193 case 1:
194 if (could_be_index(x[0])) {
195 return try_add_interactive(x[0], set_done);
196 } else {
197 text = x[0];
198 }
199 break;
200 case 2:
201 text = x[1];
202 x0 = x[0];
203 if (isdigit(x0[0]) || (x0[0] == '.') || (x0[0] == '-') || (x0[0] == '+')) {
204 parent_path = x[0];
205 } else {
206 priority = parse_priority(x0, &error);
207 if (error < 0) return error;
208 set_priority = 1;
209 }
210 break;
211 case 3:
212 text = x[2];
213 priority = parse_priority(x[1], &error);
214 if (error < 0) return error;
215 set_priority = 1;
216 parent_path = x[0];
217 break;
218
219 default:
220 fprintf(stderr, "Usage : add [@<starting datespec>] [+<due datespec>] [<parent_index>] [<priority>] <entry_text>\n");
221 return -1;
222 break;
223 }
224
225 return add_new_node(parent_path, set_done, set_priority, priority, insert_time, required_by, text);
226
227 return 0;
228}
229/*}}}*/
230int process_add(char **x)/*{{{*/
231{
232 return process_add_internal(x, 0);
233}
234/*}}}*/
235int process_log(char **x)/*{{{*/
236{
237 return process_add_internal(x, 1);
238}
239/*}}}*/
240static void modify_tree_arrival_time(struct node *y, time_t new_time)/*{{{*/
241{
242 struct node *c;
243 for (c = y->kids.next; c != (struct node *) &y->kids; c = c->chain.next) {
244 c->arrived = new_time;
245 if (has_kids(c)) {
246 modify_tree_arrival_time(c, new_time);
247 }
248 }
249}
250/*}}}*/
251static int internal_postpone_open(char **x, time_t when)/*{{{*/
252{
253 struct node *n;
254 int do_descendents;
255
256 while (*x) {
257 do_descendents = include_descendents(*x); /* May modify *x */
258 n = lookup_node(*x, 0, NULL);
259 if (n) {
260 n->arrived = when;
261 if (do_descendents) modify_tree_arrival_time(n, when);
262 }
263 x++;
264 }
265 return 0;
266}
267/*}}}*/
268int process_postpone(char **x)/*{{{*/
269{
270 return internal_postpone_open(x, POSTPONED_TIME);
271}
272/*}}}*/
273int process_open(char **x)/*{{{*/
274{
275 return internal_postpone_open(x, time(NULL));
276}
277/*}}}*/
278int process_defer(char **x)/*{{{*/
279{
280 int argc;
281 time_t new_start_time;
282 int error;
283 char *date_start;
284
285 argc = count_args(x);
286 if (argc < 2) {
287 fprintf(stderr, "Usage: defer <datespec> <index>...\n");
288 return -1;
289 }
290
291 date_start = x[0];
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);
297}
298/*}}}*/
299int process_edit(char **x) /*{{{*/
300{
301 int argc;
302 struct node *n;
303
304 argc = count_args(x);
305
306 if ((argc < 1) || (argc > 2)) {
307 fprintf(stderr, "Usage: edit <path> [<new_text>]\n");
308 return -1;
309 }
310
311 n = lookup_node(x[0], 0, NULL);
312 if (!n) return -1;
313 if (argc == 2) {
314 free(n->text);
315 n->text = new_string(x[1]);
316 } else {
317 int error;
318 int is_blank;
319 char *new_text;
320 char prompt[128];
321 char *composite_index;
322
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;
329 if (!is_blank) {
330 free(n->text);
331 n->text = new_text; /* We own the pointer now */
332 }
333 }
334
335 return 0;
336}
337/*}}}*/
This page took 0.029197 seconds and 4 git commands to generate.