/* $Header: /cvs/src/tdl/move.c,v 1.8.2.2 2004/01/07 00:09:05 richard Exp $ tdl - A console program for managing to-do lists Copyright (C) 2001-2004 Richard P. Curnow This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "tdl.h" static int is_ancestor(struct node *anc, struct node *dec)/*{{{*/ { /* Check includes whether the two nodes are the same */ struct node *parent; for (parent = dec; parent != NULL; parent = parent->parent) { if (parent == anc) { return 1; } } return 0; } /*}}}*/ static int process_move_internal(char **x, int below_not_above, int into_parent)/*{{{*/ { /* x is the argument list * below_not_above is true to insert below x[0], false to insert above * into_parent means an implicit .0 is appended to x[0] to get the path */ int argc, i, n; struct links *insert_point; struct node **table; struct node *insert_parent, *insert_peer=NULL, *parent; char *option; option = below_not_above ? "below" : "above"; argc = count_args(x); if (argc < 2) { fprintf(stderr, "Usage: %s ...\n", option, option); return -1; } n = argc - 1; if (into_parent) { insert_parent = lookup_node(x[0], 0, NULL); if (!insert_parent) return -1; insert_point = &insert_parent->kids; } else { insert_peer = lookup_node(x[0], 1, &insert_parent); /* Allow final component to be zero */ insert_point = (struct links *) &insert_peer->chain; if (!insert_point) return -1; } table = new_array(struct node *, n); x++; /* Have to do the move in 2 passes, otherwise the indices of the entries could change in mid-lookup. */ for (i=0; ichain.next; prev = table[i]->chain.prev; prev->chain.next = next; next->chain.prev = prev; (below_not_above ? append_node : prepend_node) (table[i], insert_point); if (into_parent) { table[i]->parent = insert_parent; } else { /* in this case 'insert_peer' is just the one we're putting things above * or below, i.e. the entries being moved will be siblings of it and will * share its parent. */ table[i]->parent = insert_peer->parent; } /* To insert the nodes in the command line order */ if (below_not_above) insert_point = &table[i]->chain; /* if inserting above something, the insertion point stays fixed */ /* Clear done status of insertion point and its ancestors */ if (table[i]->done == 0) { parent = insert_parent; while (parent) { parent->done = 0; parent = parent->parent; } } } return 0; } /*}}}*/ int process_above(char **x)/*{{{*/ { return process_move_internal(x, 0, 0); } /*}}}*/ int process_below(char **x)/*{{{*/ { return process_move_internal(x, 1, 0); } /*}}}*/ int process_into(char **x)/*{{{*/ { return process_move_internal(x, 0, 1); } /*}}}*/