Fall back on index for sort if the due date is the same, not just if both due dates...
[tdl.git] / move.c
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 /*}}}*/
This page took 0.02365 seconds and 4 git commands to generate.