Fall back on index for sort if the due date is the same, not just if both due dates...
[tdl.git] / util.c
CommitLineData
7024e37b
JW
1/*
2 $Header: /cvs/src/tdl/util.c,v 1.8.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 <ctype.h>
23#include "tdl.h"
24
25int count_args(char **x)/*{{{*/
26{
27 int n = 0;
28 while (*x) {
29 n++;
30 x++;
31 }
32 return n;
33}
34/*}}}*/
35int include_descendents(char *x)/*{{{*/
36{
37 /* Check if string ends in ... . If it does, truncate that off. */
38 int len;
39 int result = 0;
40 len = strlen(x);
41 if (len >= 4) {
42 if (!strcmp(x + (len-3), "...")) {
43 result = 1;
44 x[len-3] = 0;
45 }
46 }
47 return result;
48}
49/*}}}*/
50static char *ordinal(int n)/*{{{*/
51{
52 int nn;
53 nn = n % 10;
54 switch (nn) {
55 case 1: return "st";
56 case 2: return "nd";
57 case 3: return "rd";
58 default: return "th";
59 }
60}
61/*}}}*/
62struct node *lookup_node(char *path, int allow_zero_index, struct node **parent)/*{{{*/
63{
64 char *p = path;
65 int n, nc, idx, tidx, aidx, ncomp;
66 int direction;
67 struct links *x;
68 struct node *y = NULL;
69 struct node *narrow_top;
70
71 narrow_top = get_narrow_top();
72 if (narrow_top) {
73 /* Special case to allow user to do operations on the node to which the
74 * view is currently narrowed. (This doesn't apply to 'top' which is just a
75 * skeleton entry.) */
76 if (!strcmp(path, ".")) {
77 return narrow_top;
78 }
79 x = &(narrow_top->kids);
80 } else {
81 x = &top;
82 }
83
84 ncomp = 1;
85 if (parent) *parent = NULL;
86
87 /* Skip leading '.', if any. */
88 if (*p == '.') p++;
89
90 while (*p) {
91 if ((p[0] == '-') || isdigit(p[0])) {
92 n = sscanf(p, "%d%n", &idx, &nc);
93 if (n != 1) {
94 fprintf(stderr, "Bad path expression found, starting [%s]\n", p);
95 return NULL;
96 }
97 p += nc;
98
99 if (idx > 0) {
100 direction = 1;
101 aidx = idx;
102 } else if (idx < 0) {
103 direction = 0;
104 aidx = -idx;
105 } else {
106 if (allow_zero_index) {
107 if (*p) {
108 fprintf(stderr, "Zero index only allowed as last component\n");
109 return NULL;
110 } else {
111 /* This is a special cheat to allow inserting entries at
112 the start or end of a chain for the 'above' and
113 'below' commands */
114 return (struct node *) x;
115 }
116 } else {
117 fprintf(stderr, "Zero in index not allowed\n");
118 return NULL;
119 }
120 }
121
122 if (x->next == (struct node *) x) {
123 fprintf(stderr, "Path [%s] doesn't exist - tree not that deep\n", path);
124 return NULL;
125 }
126
127 for (y = direction ? x->next : x->prev, tidx = aidx; --tidx;) {
128
129 y = direction ? y->chain.next : y->chain.prev;
130
131 if (y == (struct node *) x) {
132 fprintf(stderr, "Can't find entry %d for %d%s component of path %s\n",
133 idx, ncomp, ordinal(ncomp), path);
134 return NULL;
135 }
136 }
137 } else {
138 /* Lookup by start of node text. */
139 char *dot;
140 int len;
141 struct node *match;
142 dot = strchr(p, '.');
143 if (!dot) { /* final component. */
144 len = strlen(p);
145 } else {
146 len = dot - p;
147 }
148 match = NULL;
149 for (y = x->next; y != (struct node *) x; y = y->chain.next) {
150 if (!strncasecmp(y->text, p, len)) {
151 if (match) {
152 fprintf(stderr, "Ambiguous match for %d%s component (",
153 ncomp, ordinal(ncomp));
154 fwrite(p, 1, len, stderr);
155 fprintf(stderr, ") of path %s\n", path);
156 return NULL;
157 }
158 match = y;
159 }
160 }
161 if (!match) {
162 fprintf(stderr, "Can't find entry for %d%s component (",
163 ncomp, ordinal(ncomp));
164 fwrite(p, 1, len, stderr);
165 fprintf(stderr, ") of path %s\n", path);
166 }
167
168 y = match;
169 p += len;
170 }
171
172 if (*p == '.') {
173 p++;
174 x = &y->kids;
175 if (parent) *parent = y;
176 }
177
178 ncomp++;
179 }
180
181 return y;
182}
183/*}}}*/
184enum Priority parse_priority(char *priority, int *error)/*{{{*/
185{
186 enum Priority result;
187 int is_digit;
188
189 if (!priority) {
190 *error = -1;
191 return PRI_UNKNOWN;
192 } else {
193
194 is_digit = isdigit(priority[0]);
195
196 if (is_digit) {
197 int value = atoi(priority);
198 result = (value >= PRI_URGENT) ? PRI_URGENT :
199 (value <= PRI_VERYLOW) ? PRI_VERYLOW :
200 (enum Priority) value;
201 } else {
202 int len = strlen(priority);
203 if (!strncmp(priority, "urgent", len)) {
204 result = PRI_URGENT;
205 } else if (!strncmp(priority, "high", len)) {
206 result = PRI_HIGH;
207 } else if (!strncmp(priority, "normal", len)) {
208 result = PRI_NORMAL;
209 } else if (!strncmp(priority, "low", len)) {
210 result = PRI_LOW;
211 } else if (!strncmp(priority, "verylow", len)) {
212 result = PRI_VERYLOW;
213 } else {
214 fprintf(stderr, "Can't parse priority '%s'\n", priority);
215 *error = -1;
216 return PRI_UNKNOWN; /* bogus */
217 }
218 }
219 }
220 *error = 0;
221 return result;
222}
223/*}}}*/
224void clear_flags(struct links *x)/*{{{*/
225{
226 struct node *y;
227 for (y = x->next; y != (struct node *) x; y = y->chain.next) {
228 y->flag = 0;
229 if (has_kids(y)) {
230 clear_flags(&y->kids);
231 }
232 }
233}
234/*}}}*/
235void mark_all_descendents(struct node *n)/*{{{*/
236{
237 struct node *y;
238 for (y = n->kids.next; y != (struct node *) &n->kids; y = y->chain.next) {
239 y->flag = 1;
240 if (has_kids(y)) {
241 mark_all_descendents(y);
242 }
243 }
244}
245/*}}}*/
246int has_kids(struct node *x)/*{{{*/
247{
248 return (x->kids.next != (struct node *) &x->kids);
249}
250/*}}}*/
251struct node *new_node(void)/*{{{*/
252{
253 struct node *result = new (struct node);
254 result->parent = NULL;
255 result->text = NULL;
256 result->priority = PRI_NORMAL;
257 result->arrived = result->required_by = result->done = 0U;
258 result->kids.next = result->kids.prev = (struct node *) &result->kids;
259 result->chain.next = result->chain.prev = (struct node *) &result->chain;
260 return result;
261}
262/*}}}*/
263void free_node(struct node *x)/*{{{*/
264{
265 /* FIXME : To be written */
266
267
268}
269/*}}}*/
270void append_node(struct node *n, struct links *l)/*{{{*/
271{
272 n->chain.next = l->next;
273 n->chain.prev = (struct node *) l;
274 l->next->chain.prev = n;
275 l->next = n;
276}
277/*}}}*/
278void prepend_node(struct node *n, struct links *l)/*{{{*/
279{
280 n->chain.prev = l->prev;
281 n->chain.next = (struct node *) l;
282 l->prev->chain.next = n;
283 l->prev = n;
284}
285/*}}}*/
286void prepend_child(struct node *child, struct node *parent)/*{{{*/
287{
288 child->parent = parent;
289 if (parent) {
290 prepend_node(child, &parent->kids);
291 } else {
292 struct node *narrow_top;
293 narrow_top = get_narrow_top();
294 prepend_node(child, narrow_top ? &narrow_top->kids : &top);
295 }
296}
297/*}}}*/
This page took 0.041671 seconds and 4 git commands to generate.