Changeset View
Changeset View
Standalone View
Standalone View
lib/libc/gen/fts.c
Context not available. | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "block_abi.h" | |||||
#include "un-namespace.h" | #include "un-namespace.h" | ||||
#include "gen-private.h" | #include "gen-private.h" | ||||
/* fts_block_t */ | |||||
typedef DECLARE_BLOCK(int, fts_block_t, const FTSENT * const *, | |||||
const FTSENT * const *); | |||||
static FTSENT *fts_alloc(FTS *, char *, size_t); | static FTSENT *fts_alloc(FTS *, char *, size_t); | ||||
theraven: We should move these declarations into block_abi.h and not have them copied into every file… | |||||
Done Inline ActionsI will move them. FWIW, I changed them to the expanded form as a reminder that we still don't have __weak_symbol. Currently __weak is still the only option in cdefs.h. pfg: I will move them. FWIW, I changed them to the expanded form as a reminder that we still don't… | |||||
static FTSENT *fts_build(FTS *, int); | static FTSENT *fts_build(FTS *, int); | ||||
static void fts_lfree(FTSENT *); | static void fts_lfree(FTSENT *); | ||||
Context not available. | |||||
0 | 0 | ||||
}; | }; | ||||
FTS * | static FTS * | ||||
fts_open(argv, options, compar) | _fts_open_common(argv, priv) | ||||
char * const *argv; | char * const *argv; | ||||
int options; | struct _fts_private *priv; | ||||
int (*compar)(const FTSENT * const *, const FTSENT * const *); | |||||
{ | { | ||||
struct _fts_private *priv; | FTS *sp = &priv->ftsp_fts; | ||||
FTS *sp; | |||||
FTSENT *p, *root; | FTSENT *p, *root; | ||||
FTSENT *parent, *tmp; | FTSENT *parent, *tmp; | ||||
size_t len, nitems; | size_t len, nitems; | ||||
/* Options check. */ | |||||
if (options & ~FTS_OPTIONMASK) { | |||||
errno = EINVAL; | |||||
return (NULL); | |||||
} | |||||
/* fts_open() requires at least one path */ | |||||
if (*argv == NULL) { | |||||
errno = EINVAL; | |||||
return (NULL); | |||||
} | |||||
/* Allocate/initialize the stream. */ | |||||
if ((priv = calloc(1, sizeof(*priv))) == NULL) | |||||
return (NULL); | |||||
sp = &priv->ftsp_fts; | |||||
sp->fts_compar = compar; | |||||
sp->fts_options = options; | |||||
/* Shush, GCC. */ | /* Shush, GCC. */ | ||||
tmp = NULL; | tmp = NULL; | ||||
Context not available. | |||||
* If comparison routine supplied, traverse in sorted | * If comparison routine supplied, traverse in sorted | ||||
* order; otherwise traverse in the order specified. | * order; otherwise traverse in the order specified. | ||||
*/ | */ | ||||
if (compar) { | if (sp->fts_compar) { | ||||
p->fts_link = root; | p->fts_link = root; | ||||
root = p; | root = p; | ||||
} else { | } else { | ||||
Context not available. | |||||
} | } | ||||
} | } | ||||
} | } | ||||
if (compar && nitems > 1) | if (sp->fts_compar && nitems > 1) | ||||
root = fts_sort(sp, root, nitems); | root = fts_sort(sp, root, nitems); | ||||
/* | /* | ||||
Context not available. | |||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static int | |||||
_fts_open_argcheck(char * const *argv, int options) | |||||
{ | |||||
/* | |||||
* Check for illegal options and for at least one path. | |||||
*/ | |||||
if (options & ~FTS_OPTIONMASK || *argv == NULL) | |||||
return (EINVAL); | |||||
return (0); | |||||
} | |||||
FTS * | |||||
fts_open(char * const *argv, int options, int (*compar)(const FTSENT * const *, | |||||
const FTSENT * const *)) | |||||
{ | |||||
FTS *sp; | |||||
struct _fts_private *priv; | |||||
/* Check arguments. */ | |||||
if ((errno = _fts_open_argcheck(argv, options)) != 0) | |||||
return (NULL); | |||||
/* Allocate/initialize the stream. */ | |||||
if ((priv = calloc(1, sizeof(*priv))) == NULL) | |||||
return (NULL); | |||||
sp = &priv->ftsp_fts; | |||||
sp->fts_compar = compar; | |||||
sp->fts_options = options; | |||||
return (_fts_open_common(argv, priv)); | |||||
} | |||||
FTS * | |||||
fts_open_b(char * const *argv, int options, fts_block_t compar) | |||||
{ | |||||
FTS *sp; | |||||
struct _fts_private *priv; | |||||
/* Check arguments. */ | |||||
if ((errno = _fts_open_argcheck(argv, options)) != 0) | |||||
return (NULL); | |||||
/* Check to make sure we have the block runtime. */ | |||||
if (_Block_copy == 0) { | |||||
errno = ENOSYS; | |||||
return (NULL); | |||||
} | |||||
/* Allocate/initialize the stream. */ | |||||
if ((priv = calloc(1, sizeof(*priv))) == NULL) | |||||
return (NULL); | |||||
sp = &priv->ftsp_fts; | |||||
sp->fts_compar_b = _Block_copy(compar); | |||||
sp->fts_options = options | FTS_COMPAR_B; | |||||
return (_fts_open_common(argv, priv)); | |||||
} | |||||
static void | static void | ||||
fts_load(FTS *sp, FTSENT *p) | fts_load(FTS *sp, FTSENT *p) | ||||
{ | { | ||||
Context not available. | |||||
free(sp->fts_array); | free(sp->fts_array); | ||||
free(sp->fts_path); | free(sp->fts_path); | ||||
/* Free block pointer, if any. */ | |||||
if (ISSET(FTS_COMPAR_B) && sp->fts_compar_b != NULL && | |||||
_Block_release != 0) | |||||
_Block_release(sp->fts_compar_b); | |||||
/* Return to original directory, save errno if necessary. */ | /* Return to original directory, save errno if necessary. */ | ||||
if (!ISSET(FTS_NOCHDIR)) { | if (!ISSET(FTS_NOCHDIR)) { | ||||
saved_errno = fchdir(sp->fts_rfd) ? errno : 0; | saved_errno = fchdir(sp->fts_rfd) ? errno : 0; | ||||
Not Done Inline ActionsPlease can we have an assert for _Block_release != 0 if sp->fts_compar_b != NULL? This will only happen if _Block_copy exists but _Block_release doesn't, which means that something's badly wrong. Ideally, we'd do the _Block_release != 0 check up on line 261, so we never get into this situation in the first place. theraven: Please can we have an assert for _Block_release != 0 if sp->fts_compar_b != NULL? This will… | |||||
Context not available. | |||||
return (*parent->fts_compar)(a, b); | return (*parent->fts_compar)(a, b); | ||||
} | } | ||||
static int | |||||
fts_compar_b(void *thunk, const void *a, const void *b) | |||||
{ | |||||
FTS *sp = (FTS *)thunk; | |||||
int (*funcp)(const void *, const void *); | |||||
funcp = (int (*)(const void *, const void *)) | |||||
GET_BLOCK_FUNCTION(sp->fts_compar_b); | |||||
return (*funcp)(a, b); | |||||
} | |||||
static FTSENT * | static FTSENT * | ||||
fts_sort(FTS *sp, FTSENT *head, size_t nitems) | fts_sort(FTS *sp, FTSENT *head, size_t nitems) | ||||
{ | { | ||||
Context not available. | |||||
} | } | ||||
for (ap = sp->fts_array, p = head; p; p = p->fts_link) | for (ap = sp->fts_array, p = head; p; p = p->fts_link) | ||||
*ap++ = p; | *ap++ = p; | ||||
qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); | if (ISSET(FTS_COMPAR_B)) | ||||
qsort_r(sp->fts_array, nitems, sizeof(FTSENT *), | |||||
sp->fts_compar_b, fts_compar_b); | |||||
else | |||||
qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); | |||||
for (head = *(ap = sp->fts_array); --nitems; ++ap) | for (head = *(ap = sp->fts_array); --nitems; ++ap) | ||||
Not Done Inline ActionsIs there a reason not to use qsort_b here? theraven: Is there a reason not to use qsort_b here? | |||||
ap[0]->fts_link = ap[1]; | ap[0]->fts_link = ap[1]; | ||||
ap[0]->fts_link = NULL; | ap[0]->fts_link = NULL; | ||||
Context not available. |
We should move these declarations into block_abi.h and not have them copied into every file that uses them. We should also use __weak_symbol, rather than the expanded form of the attribute.