]> Joshua Wise's Git repositories - tdl.git/blob - util.c
Initial import of tdl-1.6-pre1
[tdl.git] / util.c
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
25 int count_args(char **x)/*{{{*/
26 {
27   int n = 0;
28   while (*x) {
29     n++;
30     x++;
31   }
32   return n;
33 }
34 /*}}}*/
35 int 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 /*}}}*/
50 static 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 /*}}}*/
62 struct 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 /*}}}*/
184 enum 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 /*}}}*/
224 void 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 /*}}}*/
235 void 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 /*}}}*/
246 int has_kids(struct node *x)/*{{{*/
247 {
248   return (x->kids.next != (struct node *) &x->kids);
249 }
250 /*}}}*/
251 struct 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 /*}}}*/
263 void free_node(struct node *x)/*{{{*/
264 {
265   /* FIXME : To be written */
266
267
268 }
269 /*}}}*/
270 void 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 /*}}}*/
278 void 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 /*}}}*/
286 void 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.037051 seconds and 4 git commands to generate.