]>
Commit | Line | Data |
---|---|---|
7024e37b JW |
1 | /* |
2 | $Header: /cvs/src/tdl/move.c,v 1.8.2.2 2004/01/07 00:09:05 richard Exp $ | |
3 | ||
4 | tdl - A console program for managing to-do lists | |
5 | Copyright (C) 2001-2004 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 "tdl.h" | |
23 | ||
24 | ||
25 | static int is_ancestor(struct node *anc, struct node *dec)/*{{{*/ | |
26 | { | |
27 | /* Check includes whether the two nodes are the same */ | |
28 | struct node *parent; | |
29 | for (parent = dec; parent != NULL; parent = parent->parent) { | |
30 | if (parent == anc) { | |
31 | return 1; | |
32 | } | |
33 | } | |
34 | return 0; | |
35 | } | |
36 | /*}}}*/ | |
37 | ||
38 | static int process_move_internal(char **x, int below_not_above, int into_parent)/*{{{*/ | |
39 | { | |
40 | /* x is the argument list | |
41 | * below_not_above is true to insert below x[0], false to insert above | |
42 | * into_parent means an implicit .0 is appended to x[0] to get the path | |
43 | */ | |
44 | ||
45 | int argc, i, n; | |
46 | struct links *insert_point; | |
47 | struct node **table; | |
48 | struct node *insert_parent, *insert_peer=NULL, *parent; | |
49 | ||
50 | char *option; | |
51 | ||
52 | option = below_not_above ? "below" : "above"; | |
53 | ||
54 | argc = count_args(x); | |
55 | if (argc < 2) { | |
56 | fprintf(stderr, "Usage: %s <index_to_insert_%s> <index_to_move> ...\n", | |
57 | option, option); | |
58 | return -1; | |
59 | } | |
60 | ||
61 | n = argc - 1; | |
62 | if (into_parent) { | |
63 | insert_parent = lookup_node(x[0], 0, NULL); | |
64 | if (!insert_parent) return -1; | |
65 | insert_point = &insert_parent->kids; | |
66 | } else { | |
67 | insert_peer = lookup_node(x[0], 1, &insert_parent); /* Allow final component to be zero */ | |
68 | insert_point = (struct links *) &insert_peer->chain; | |
69 | if (!insert_point) return -1; | |
70 | } | |
71 | table = new_array(struct node *, n); | |
72 | x++; | |
73 | ||
74 | /* Have to do the move in 2 passes, otherwise the indices of the entries | |
75 | could change in mid-lookup. */ | |
76 | for (i=0; i<n; i++) { | |
77 | table[i] = lookup_node(x[i], 0, NULL); /* Don't allow zero for this */ | |
78 | if (!table[i]) return -1; /* memory leak */ | |
79 | ||
80 | /* Check for an attempt to move a node onto one of its own descendents */ | |
81 | if (is_ancestor(table[i], insert_parent)) { | |
82 | fprintf(stderr, "Can't re-parent entry %s onto a descendent of itself\n", x[i]); | |
83 | return -1; | |
84 | } | |
85 | } | |
86 | ||
87 | for (i=0; i<n; i++) { | |
88 | /* Unlink from its current location */ | |
89 | struct node *prev, *next; | |
90 | ||
91 | if (table[i] == insert_peer) { | |
92 | fprintf(stderr, "Can't move %s relative to itself\n", x[0]); | |
93 | continue; | |
94 | } | |
95 | ||
96 | next = table[i]->chain.next; | |
97 | prev = table[i]->chain.prev; | |
98 | prev->chain.next = next; | |
99 | next->chain.prev = prev; | |
100 | ||
101 | (below_not_above ? append_node : prepend_node) (table[i], insert_point); | |
102 | if (into_parent) { | |
103 | table[i]->parent = insert_parent; | |
104 | } else { | |
105 | /* in this case 'insert_peer' is just the one we're putting things above | |
106 | * or below, i.e. the entries being moved will be siblings of it and will | |
107 | * share its parent. */ | |
108 | table[i]->parent = insert_peer->parent; | |
109 | } | |
110 | ||
111 | /* To insert the nodes in the command line order */ | |
112 | if (below_not_above) insert_point = &table[i]->chain; | |
113 | /* if inserting above something, the insertion point stays fixed */ | |
114 | ||
115 | /* Clear done status of insertion point and its ancestors */ | |
116 | if (table[i]->done == 0) { | |
117 | parent = insert_parent; | |
118 | while (parent) { | |
119 | parent->done = 0; | |
120 | parent = parent->parent; | |
121 | } | |
122 | } | |
123 | } | |
124 | ||
125 | return 0; | |
126 | } | |
127 | /*}}}*/ | |
128 | int process_above(char **x)/*{{{*/ | |
129 | { | |
130 | return process_move_internal(x, 0, 0); | |
131 | } | |
132 | /*}}}*/ | |
133 | int process_below(char **x)/*{{{*/ | |
134 | { | |
135 | return process_move_internal(x, 1, 0); | |
136 | } | |
137 | /*}}}*/ | |
138 | int process_into(char **x)/*{{{*/ | |
139 | { | |
140 | return process_move_internal(x, 0, 1); | |
141 | } | |
142 | /*}}}*/ |