]> Joshua Wise's Git repositories - tdl.git/blame - add.c
Initial import of tdl-1.6-pre1
[tdl.git] / add.c
CommitLineData
7024e37b
JW
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, 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
52 nn->priority = (parent && !set_priority) ? parent->priority
53 : new_priority;
54
55 prepend_child(nn, parent);
56
57 /* Clear done status of parents - they can't be any longer! */
58 if (!set_done) {
59 while (parent) {
60 parent->done = 0;
61 parent = parent->parent;
62 }
63 }
64
65 return 0;
66}
67/*}}}*/
68static char *make_composite(char *prefix, char *suffix)/*{{{*/
69{
70 int plen, slen;
71 int tlen;
72 char *result;
73 int suffix_is_dot;
74
75 plen = prefix ? strlen(prefix) : 0;
76 slen = suffix ? strlen(suffix) : 0;
77 suffix_is_dot = slen ? (!strcmp(suffix,".")) : 0;
78 tlen = plen + slen;
79 if (plen && slen) ++tlen; /* for internal '.' */
80 if (!plen && !slen) return NULL;
81 result = new_array(char, 1+tlen);
82 result[0] = '\0';
83 if (plen) {
84 strcat(result, prefix);
85 if (slen && !suffix_is_dot) strcat(result, ".");
86 }
87 if (slen && !suffix_is_dot) strcat(result, suffix);
88 return result;
89}
90/*}}}*/
91static int try_add_interactive(char *parent_path, int set_done)/*{{{*/
92{
93 char *text;
94 time_t insert_time;
95 int error = 0;
96 int blank;
97 int status;
98 char prompt[128];
99 char *prompt_base;
100 char *composite_index;
101
102 composite_index = make_composite(get_narrow_prefix(), parent_path);
103
104 prompt_base = set_done ? "log" : "add";
105 if (composite_index) {
106 sprintf(prompt, "%s (%s)> ", prompt_base, composite_index);
107 } else {
108 sprintf(prompt, "%s> ", prompt_base);
109 }
110 if (composite_index) free(composite_index);
111
112 do {
113 text = interactive_text(prompt, NULL, &blank, &error);
114 if (error < 0) return error;
115 if (!blank) {
116 time(&insert_time);
117 status = add_new_node(parent_path, set_done, 0, PRI_NORMAL, insert_time, text);
118 free(text);
119 if (status < 0) return status;
120 }
121 } while (!blank);
122 return 0;
123}
124/*}}}*/
125static int could_be_index(char *x)/*{{{*/
126{
127 enum {AFTER_DIGIT, AFTER_PERIOD, AFTER_MINUS} state;
128 char *p;
129 if (x[0] == '.') return 1; /* To handle alphabetical matching */
130 state = AFTER_PERIOD;
131 for (p=x; *p; p++) {
132 switch (state) {
133 case AFTER_DIGIT:
134 if (isdigit(*p)) state = AFTER_DIGIT;
135 else if (*p == '-') state = AFTER_MINUS;
136 else if (*p == '.') state = AFTER_PERIOD;
137 else return 0;
138 break;
139 case AFTER_PERIOD:
140 if (isdigit(*p)) state = AFTER_DIGIT;
141 else if (*p == '-') state = AFTER_MINUS;
142 else return 0;
143 break;
144 case AFTER_MINUS:
145 if (isdigit(*p)) state = AFTER_DIGIT;
146 else return 0;
147 break;
148 }
149 }
150 return 1;
151}
152/*}}}*/
153static int process_add_internal(char **x, int set_done)/*{{{*/
154{
155 /* Expect 1 argument, the string to add. Need other options at some point. */
156 time_t insert_time;
157 int argc = count_args(x);
158 char *text = NULL;
159 char *parent_path = NULL;
160 enum Priority priority = PRI_NORMAL;
161 int set_priority = 0;
162 char *x0;
163 int error;
164
165 insert_time = time(NULL);
166
167 if ((argc > 1) && (x[0][0] == '@')) {
168 int error;
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;
174 argc--;
175 x++;
176 }
177
178 switch (argc) {
179 case 0:
180 return try_add_interactive(NULL, set_done);
181 break;
182 case 1:
183 if (could_be_index(x[0])) {
184 return try_add_interactive(x[0], set_done);
185 } else {
186 text = x[0];
187 }
188 break;
189 case 2:
190 text = x[1];
191 x0 = x[0];
192 if (isdigit(x0[0]) || (x0[0] == '.') || (x0[0] == '-') || (x0[0] == '+')) {
193 parent_path = x[0];
194 } else {
195 priority = parse_priority(x0, &error);
196 if (error < 0) return error;
197 set_priority = 1;
198 }
199 break;
200 case 3:
201 text = x[2];
202 priority = parse_priority(x[1], &error);
203 if (error < 0) return error;
204 set_priority = 1;
205 parent_path = x[0];
206 break;
207
208 default:
209 fprintf(stderr, "Usage : add [@<datespec>] [<parent_index>] [<priority>] <entry_text>\n");
210 return -1;
211 break;
212 }
213
214 return add_new_node(parent_path, set_done, set_priority, priority, insert_time, text);
215
216 return 0;
217}
218/*}}}*/
219int process_add(char **x)/*{{{*/
220{
221 return process_add_internal(x, 0);
222}
223/*}}}*/
224int process_log(char **x)/*{{{*/
225{
226 return process_add_internal(x, 1);
227}
228/*}}}*/
229static void modify_tree_arrival_time(struct node *y, time_t new_time)/*{{{*/
230{
231 struct node *c;
232 for (c = y->kids.next; c != (struct node *) &y->kids; c = c->chain.next) {
233 c->arrived = new_time;
234 if (has_kids(c)) {
235 modify_tree_arrival_time(c, new_time);
236 }
237 }
238}
239/*}}}*/
240static int internal_postpone_open(char **x, time_t when)/*{{{*/
241{
242 struct node *n;
243 int do_descendents;
244
245 while (*x) {
246 do_descendents = include_descendents(*x); /* May modify *x */
247 n = lookup_node(*x, 0, NULL);
248 if (n) {
249 n->arrived = when;
250 if (do_descendents) modify_tree_arrival_time(n, when);
251 }
252 x++;
253 }
254 return 0;
255}
256/*}}}*/
257int process_postpone(char **x)/*{{{*/
258{
259 return internal_postpone_open(x, POSTPONED_TIME);
260}
261/*}}}*/
262int process_open(char **x)/*{{{*/
263{
264 return internal_postpone_open(x, time(NULL));
265}
266/*}}}*/
267int process_defer(char **x)/*{{{*/
268{
269 int argc;
270 time_t new_start_time;
271 int error;
272 char *date_start;
273
274 argc = count_args(x);
275 if (argc < 2) {
276 fprintf(stderr, "Usage: defer <datespec> <index>...\n");
277 return -1;
278 }
279
280 date_start = x[0];
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);
286}
287/*}}}*/
288int process_edit(char **x) /*{{{*/
289{
290 int argc;
291 struct node *n;
292
293 argc = count_args(x);
294
295 if ((argc < 1) || (argc > 2)) {
296 fprintf(stderr, "Usage: edit <path> [<new_text>]\n");
297 return -1;
298 }
299
300 n = lookup_node(x[0], 0, NULL);
301 if (!n) return -1;
302 if (argc == 2) {
303 free(n->text);
304 n->text = new_string(x[1]);
305 } else {
306 int error;
307 int is_blank;
308 char *new_text;
309 char prompt[128];
310 char *composite_index;
311
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;
318 if (!is_blank) {
319 free(n->text);
320 n->text = new_text; /* We own the pointer now */
321 }
322 }
323
324 return 0;
325}
326/*}}}*/
This page took 0.045999 seconds and 4 git commands to generate.