Module Name: src
Committed By: apb
Date: Fri Apr 3 21:18:59 UTC 2009
Modified Files:
src/usr.sbin/mtree: create.c spec.c
Log Message:
Make "mtree -C" sort its output.
As the input is read from a specfile into a tree of linked lists,
keep each linked list sorted. The sort order is the same as that
already used by "mtree -c": directories sort after non-directories, but
otherwise names are sorted in the order used by strcmp().
To generate a diff of this commit:
cvs rdiff -u -r1.57 -r1.58 src/usr.sbin/mtree/create.c
cvs rdiff -u -r1.68 -r1.69 src/usr.sbin/mtree/spec.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.sbin/mtree/create.c
diff -u src/usr.sbin/mtree/create.c:1.57 src/usr.sbin/mtree/create.c:1.58
--- src/usr.sbin/mtree/create.c:1.57 Sun Feb 1 22:36:24 2009
+++ src/usr.sbin/mtree/create.c Fri Apr 3 21:18:59 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: create.c,v 1.57 2009/02/01 22:36:24 hubertf Exp $ */
+/* $NetBSD: create.c,v 1.58 2009/04/03 21:18:59 apb Exp $ */
/*-
* Copyright (c) 1989, 1993
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: create.c,v 1.57 2009/02/01 22:36:24 hubertf Exp $");
+__RCSID("$NetBSD: create.c,v 1.58 2009/04/03 21:18:59 apb Exp $");
#endif
#endif /* not lint */
@@ -384,6 +384,15 @@
return (0);
}
+/*
+ * dcmp --
+ * used as a comparison function passed to fts_open() to control
+ * the order in which fts_read() returns results. We make
+ * directories sort after non-directories, but otherwise sort in
+ * strcmp() order.
+ *
+ * Keep this in sync with nodecmp() in spec.c.
+ */
static int
dcmp(const FTSENT **a, const FTSENT **b)
{
Index: src/usr.sbin/mtree/spec.c
diff -u src/usr.sbin/mtree/spec.c:1.68 src/usr.sbin/mtree/spec.c:1.69
--- src/usr.sbin/mtree/spec.c:1.68 Sun Jan 18 12:09:38 2009
+++ src/usr.sbin/mtree/spec.c Fri Apr 3 21:18:59 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: spec.c,v 1.68 2009/01/18 12:09:38 lukem Exp $ */
+/* $NetBSD: spec.c,v 1.69 2009/04/03 21:18:59 apb Exp $ */
/*-
* Copyright (c) 1989, 1993
@@ -67,7 +67,7 @@
#if 0
static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95";
#else
-__RCSID("$NetBSD: spec.c,v 1.68 2009/01/18 12:09:38 lukem Exp $");
+__RCSID("$NetBSD: spec.c,v 1.69 2009/04/03 21:18:59 apb Exp $");
#endif
#endif /* not lint */
@@ -96,6 +96,8 @@
static void replacenode(NODE *, NODE *);
static void set(char *, NODE *);
static void unset(char *, NODE *);
+static void addchild(NODE *, NODE *);
+static int nodecmp(const NODE *, const NODE *);
#define REPLACEPTR(x,v) do { if ((x)) free((x)); (x) = (v); } while (0)
@@ -219,32 +221,11 @@
root->parent = root;
} else if (pathparent != NULL) {
/*
- * full path entry
+ * full path entry; add or replace
*/
centry->parent = pathparent;
- cur = pathparent->child;
- if (cur == NULL) {
- pathparent->child = centry;
- last = centry;
- } else {
- for (; cur != NULL; cur = cur->next) {
- if (strcmp(cur->name, centry->name)
- == 0) {
- /* existing entry; replace */
- replacenode(cur, centry);
- break;
- }
- if (cur->next == NULL) {
- /* last entry; add new */
- cur->next = centry;
- centry->prev = cur;
- break;
- }
- }
- last = cur;
- while (last->next != NULL)
- last = last->next;
- }
+ addchild(pathparent, centry);
+ last = centry;
} else if (strcmp(centry->name, ".") == 0) {
/*
* duplicate "." entry; always replace
@@ -252,19 +233,21 @@
replacenode(root, centry);
} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
/*
- * new relative child
- * (no duplicate check)
+ * new relative child in current dir;
+ * add or replace
*/
centry->parent = last;
- last = last->child = centry;
+ addchild(last, centry);
+ last = centry;
} else {
/*
- * relative entry, up one directory
- * (no duplicate check)
+ * new relative child in parent dir
+ * (after encountering ".." entry);
+ * add or replace
*/
centry->parent = last->parent;
- centry->prev = last;
- last = last->next = centry;
+ addchild(last->parent, centry);
+ last = centry;
}
}
return (root);
@@ -666,3 +649,85 @@
ip->flags &= ~parsekey(p, NULL);
}
}
+
+/*
+ * addchild --
+ * Add the centry node as a child of the pathparent node. If
+ * centry is a duplicate, call replacenode(). If centry is not
+ * a duplicate, insert it into the linked list referenced by
+ * pathparent->child. Keep the list sorted.
+ */
+static void
+addchild(NODE *pathparent, NODE *centry)
+{
+ NODE *cur, *insertpos;
+ int cmp;
+
+ cur = pathparent->child;
+ if (cur == NULL) {
+ /* centry is pathparent's first and only child node so far */
+ pathparent->child = centry;
+ return;
+ }
+
+ /*
+ * pathparent already has at least one other child, so add the
+ * centry node to the list.
+ *
+ * To keep the list sorted, the new centry node will be
+ * inserted just after the existing insertpos node, if any;
+ * otherwise it will be inserted at the start of the list.
+ */
+ insertpos = NULL;
+ for (; cur != NULL; cur = cur->next) {
+ cmp = nodecmp(centry, cur);
+ if (cmp == 0) {
+ /* existing entry; replace */
+ replacenode(cur, centry);
+ break;
+ } else if (cmp > 0) {
+ /* centry appears after cur in sort order */
+ insertpos = cur;
+ }
+ if (cmp < 0 || cur->next == NULL) {
+ /*
+ * centry appears before cur in sort order,
+ * or we reached the end of the list; insert
+ * centry either just after insertpos, or at the
+ * beginning of the list.
+ */
+ if (insertpos) {
+ centry->next = insertpos->next;
+ insertpos->next = centry;
+ if (centry->next)
+ centry->next->prev = centry;
+ } else {
+ centry->next = pathparent->child;
+ pathparent->child = centry;
+ }
+ break;
+ }
+ }
+ return;
+}
+
+/*
+ * nodecmp --
+ * used as a comparison function by addchild() to control the order
+ * in which entries appear within a list of sibling nodes. We make
+ * directories sort after non-directories, but otherwise sort in
+ * strcmp() order.
+ *
+ * Keep this in sync with dcmp() in create.c.
+ */
+static int
+nodecmp(const NODE *a, const NODE *b)
+{
+
+ if ((a->type & F_DIR) != 0) {
+ if ((b->type & F_DIR) == 0)
+ return 1;
+ } else if ((b->type & F_DIR) != 0)
+ return -1;
+ return strcmp(a->name, b->name);
+}