=================================================================== RCS file: /cvs/mandoc/compat_fts.c,v retrieving revision 1.11 retrieving revision 1.12 diff -u -p -r1.11 -r1.12 --- mandoc/compat_fts.c 2016/10/18 23:13:25 1.11 +++ mandoc/compat_fts.c 2016/10/18 23:58:12 1.12 @@ -6,8 +6,8 @@ int dummy; #else -/* $Id: compat_fts.c,v 1.11 2016/10/18 23:13:25 schwarze Exp $ */ -/* $OpenBSD: compat_fts.c,v 1.11 2016/10/18 23:13:25 schwarze Exp $ */ +/* $Id: compat_fts.c,v 1.12 2016/10/18 23:58:12 schwarze Exp $ */ +/* $OpenBSD: compat_fts.c,v 1.12 2016/10/18 23:58:12 schwarze Exp $ */ /*- * Copyright (c) 1990, 1993, 1994 @@ -59,6 +59,7 @@ static void fts_load(FTS *, FTSENT *); static size_t fts_maxarglen(char * const *); static void fts_padjust(FTS *, FTSENT *); static int fts_palloc(FTS *, size_t); +static FTSENT *fts_sort(FTS *, FTSENT *, int); static unsigned short fts_stat(FTS *, FTSENT *); #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) @@ -77,7 +78,8 @@ static unsigned short fts_stat(FTS *, FTSENT *); #define SET(opt) (sp->fts_options |= (opt)) FTS * -fts_open(char * const *argv, int options, void *dummy) +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) { FTS *sp; FTSENT *p, *root; @@ -99,6 +101,7 @@ fts_open(char * const *argv, int options, void *dummy) /* Allocate/initialize the stream */ if ((sp = calloc(1, sizeof(FTS))) == NULL) return (NULL); + sp->fts_compar = compar; sp->fts_options = options; /* @@ -126,14 +129,25 @@ fts_open(char * const *argv, int options, void *dummy) if (p->fts_info == FTS_DOT) p->fts_info = FTS_D; - p->fts_link = NULL; - if (root == NULL) - tmp = root = p; - else { - tmp->fts_link = p; - tmp = p; + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } } } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); /* * Allocate a dummy pointer and make fts_read think that we've just @@ -203,6 +217,7 @@ fts_close(FTS *sp) /* Free up child linked list, sort array, path buffer, stream ptr.*/ if (sp->fts_child) fts_lfree(sp->fts_child); + free(sp->fts_array); free(sp->fts_path); free(sp); @@ -490,6 +505,10 @@ mem1: saved_errno = errno; cur->fts_info = FTS_DP; return (NULL); } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); return (head); } @@ -544,6 +563,40 @@ fts_stat(FTS *sp, FTSENT *p) if (S_ISREG(sbp->st_mode)) return (FTS_F); return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, int nitems) +{ + FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + struct _ftsent **a; + + sp->fts_nitems = nitems + 40; + if ((a = reallocarray(sp->fts_array, + sp->fts_nitems, sizeof(FTSENT *))) == NULL) { + free(sp->fts_array); + sp->fts_array = NULL; + sp->fts_nitems = 0; + return (head); + } + sp->fts_array = a; + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); } static FTSENT *