Index: include/err.h =================================================================== --- include/err.h +++ include/err.h @@ -59,6 +59,9 @@ void vwarnx(const char *, __va_list) __printflike(1, 0); void err_set_file(void *); void err_set_exit(void (*)(int)); +#ifdef __BLOCKS__ +void err_set_exit_b(void (^)(int)); +#endif /* __BLOCKS__ */ __END_DECLS #endif /* !_ERR_H_ */ Index: include/fts.h =================================================================== --- include/fts.h +++ include/fts.h @@ -44,8 +44,12 @@ int fts_rfd; /* fd for root */ __size_t fts_pathlen; /* sizeof(path) */ __size_t fts_nitems; /* elements in the sort array */ - int (*fts_compar) /* compare function */ - (const struct _ftsent * const *, const struct _ftsent * const *); + union { + int (*fts_compar) /* compare function */ + (const struct _ftsent * const *, + const struct _ftsent * const *); + void *fts_compar_b; /* compare block */ + }; #define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ #define FTS_LOGICAL 0x002 /* logical walk */ @@ -59,6 +63,7 @@ #define FTS_NAMEONLY 0x100 /* (private) child names only */ #define FTS_STOP 0x200 /* (private) unrecoverable error */ +#define FTS_COMPAR_B 0x400 /* (private) use block compare */ int fts_options; /* fts_open options, global flags */ void *fts_clientptr; /* thunk for sort function */ } FTS; @@ -128,6 +133,10 @@ #define fts_get_stream(ftsent) ((ftsent)->fts_fts) FTS *fts_open(char * const *, int, int (*)(const FTSENT * const *, const FTSENT * const *)); +#ifdef __BLOCKS__ +FTS *fts_open_b(char * const *, int, + int (^)(const FTSENT * const *, const FTSENT * const *)); +#endif /* __BLOCKS__ */ FTSENT *fts_read(FTS *); int fts_set(FTS *, FTSENT *, int); void fts_set_clientptr(FTS *, void *); Index: include/glob.h =================================================================== --- include/glob.h +++ include/glob.h @@ -51,8 +51,12 @@ size_t gl_offs; /* Reserved at beginning of gl_pathv. */ int gl_flags; /* Copy of flags parameter to glob. */ char **gl_pathv; /* List of paths matching pattern. */ - /* Copy of errfunc parameter to glob. */ - int (*gl_errfunc)(const char *, int); + /* Copy of errfunc/errblock parameter to + glob/glob_b.*/ + union { + int (*gl_errfunc)(const char *, int); + void *gl_errblk; + }; /* * Alternate filesystem access methods for glob; replacement @@ -92,6 +96,8 @@ #define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ #define GLOB_LIMIT 0x1000 /* limit number of returned paths */ +#define _GLOB_ERRBLK 0x80000000 /* (private) err callback is block */ + /* source compatibility, these are the old names */ #define GLOB_MAXPATH GLOB_LIMIT #define GLOB_ABEND GLOB_ABORTED @@ -100,6 +106,10 @@ __BEGIN_DECLS int glob(const char * __restrict, int, int (*)(const char *, int), glob_t * __restrict); +#ifdef __BLOCKS__ +int glob_b(const char * __restrict, int, + int (^)(const char *, int), glob_t * __restrict); +#endif /* __BLOCKS__ */ void globfree(glob_t *); __END_DECLS Index: lib/libc/gen/Makefile.inc =================================================================== --- lib/libc/gen/Makefile.inc +++ lib/libc/gen/Makefile.inc @@ -319,6 +319,7 @@ dlopen.3 dlfunc.3 \ dlopen.3 dlsym.3 MLINKS+=err.3 err_set_exit.3 \ + err.3 err_set_exit_b.3 \ err.3 err_set_file.3 \ err.3 errc.3 \ err.3 errx.3 \ @@ -349,6 +350,7 @@ MLINKS+=fts.3 fts_children.3 \ fts.3 fts_close.3 \ fts.3 fts_open.3 \ + fts.3 fts_open_b.3 \ fts.3 fts_read.3 \ fts.3 fts_set.3 \ fts.3 fts_set_clientptr.3 \ @@ -413,7 +415,8 @@ getutxent.3 setutxdb.3 \ getutxent.3 setutxent.3 \ getutxent.3 utmpx.3 -MLINKS+=glob.3 globfree.3 +MLINKS+=glob.3 globfree.3 \ + glob.3 glob_b.3 MLINKS+=isgreater.3 isgreaterequal.3 \ isgreater.3 isless.3 \ isgreater.3 islessequal.3 \ Index: lib/libc/gen/Symbol.map =================================================================== --- lib/libc/gen/Symbol.map +++ lib/libc/gen/Symbol.map @@ -410,6 +410,9 @@ }; FBSD_1.4 { + err_set_exit_b; + fts_open_b; + glob_b; scandir_b; }; Index: lib/libc/gen/err.3 =================================================================== --- lib/libc/gen/err.3 +++ lib/libc/gen/err.3 @@ -28,7 +28,7 @@ .\" From: @(#)err.3 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd March 29, 2012 +.Dd May 5, 2014 .Dt ERR 3 .Os .Sh NAME @@ -45,6 +45,7 @@ .Nm warnx , .Nm vwarnx , .Nm err_set_exit , +.Nm err_set_exit_b , .Nm err_set_file .Nd formatted error messages .Sh LIBRARY @@ -54,7 +55,9 @@ .Ft void .Fn err "int eval" "const char *fmt" "..." .Ft void -.Fn err_set_exit "void (*exitf)(int)" +.Fn err_set_exit "void (*exitfunc)(int)" +.Ft void +.Fn err_set_exit_b "void (^exitblock)(int)" .Ft void .Fn err_set_file "void *vfp" .Ft void @@ -163,9 +166,21 @@ function can be used to specify a function which is called before .Xr exit 3 to perform any necessary cleanup; passing a null function pointer for -.Va exitf +.Va exitfunc resets the hook to do nothing. The +.Fn err_set_exit_b +function is like +.Fn err_set_exit , +except it takes the block pointer, +.Va exitblock , +instead of a function pointer. +Note that the +.Fn Block_copy +function is used by +.Fn err_set_exit_b +to make a copy in case the block is freed or goes out of scope. +The .Fn err_set_file function sets the output stream used by the other functions. Its @@ -243,3 +258,8 @@ .Fn warnc functions first appeared in .Fx 3.0 . +The +.Fn err_set_exit_b +function first appeared in Mac OS X. This implementation was +created by Stacey Son for +.Fx 11.0 . Index: lib/libc/gen/err.c =================================================================== --- lib/libc/gen/err.c +++ lib/libc/gen/err.c @@ -40,12 +40,14 @@ #include #include #include +#include "block_abi.h" #include "un-namespace.h" #include "libc_private.h" static FILE *err_file; /* file to use for error output */ static void (*err_exit)(int); +typedef DECLARE_BLOCK(void, err_exit_block_t, int); /* * This is declared to take a `void *' so that the caller is not required @@ -67,6 +69,17 @@ err_exit = ef; } +/* + * Register a block to be executed at error exit. + */ +void +err_set_exit_b(err_exit_block_t block) +{ + + if (_Block_copy != 0) + err_exit = (void(*)(int))GET_BLOCK_FUNCTION(_Block_copy(block)); +} + __weak_reference(_err, err); void Index: lib/libc/gen/fts.3 =================================================================== --- lib/libc/gen/fts.3 +++ lib/libc/gen/fts.3 @@ -28,7 +28,7 @@ .\" @(#)fts.3 8.5 (Berkeley) 4/16/94 .\" $FreeBSD$ .\" -.Dd January 12, 2014 +.Dd May 5, 2014 .Dt FTS 3 .Os .Sh NAME @@ -40,6 +40,8 @@ .In fts.h .Ft FTS * .Fn fts_open "char * const *path_argv" "int options" "int (*compar)(const FTSENT * const *, const FTSENT * const *)" +.Ft FTS * +.Fn fts_open_b "char * const *path_argv" "int options" "int (^compar)(const FTSENT * const *, const FTSENT * const *)" .Ft FTSENT * .Fn fts_read "FTS *ftsp" .Ft FTSENT * @@ -62,7 +64,9 @@ file hierarchies. A simple overview is that the .Fn fts_open -function returns a +and +.Fn fts_open_b +functions return a .Dq handle on a file hierarchy, which is then supplied to the other @@ -189,6 +193,8 @@ .Ql ..\& which was not specified as a file name to .Fn fts_open +or +.Fn fts_open_b (see .Dv FTS_SEEDOT ) . .It Dv FTS_DP @@ -237,6 +243,8 @@ The path for the file relative to the root of the traversal. This path contains the path specified to .Fn fts_open +or +.Fn fts_open_b as a prefix. .It Fa fts_pathlen The length of the string referenced by @@ -521,6 +529,17 @@ .Fa path_argv for the root paths, and in the order listed in the directory for everything else. +.Sh FTS_OPEN_B +The +.Fn fts_open_b +is a block-based version of +.Fn fts_open +where +.Fa compar +is a block pointer that is passed to +.Xr qsort_b 3 +instead of +.Xr qsort 3 . .Sh FTS_READ The .Fn fts_read @@ -775,7 +794,8 @@ .Xr chdir 2 , .Xr stat 2 , .Xr ftw 3 , -.Xr qsort 3 +.Xr qsort 3 , +.Xr qsort_b 3 .Sh HISTORY The .Nm @@ -791,10 +811,17 @@ principally to provide for alternative interfaces to the .Nm functionality using different data structures. +The +.Fn fts_open_b +function first appeared in Mac OS X. +This implementation was created by Stacey Son for +.Fx 11.0 . .Sh BUGS The .Fn fts_open -function will automatically set the +and +.Fn fts_open_b +functions will automatically set the .Dv FTS_NOCHDIR option if the .Dv FTS_LOGICAL Index: lib/libc/gen/fts.c =================================================================== --- lib/libc/gen/fts.c +++ lib/libc/gen/fts.c @@ -50,10 +50,15 @@ #include #include #include +#include "block_abi.h" #include "un-namespace.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_build(FTS *, int); static void fts_lfree(FTSENT *); @@ -109,37 +114,16 @@ 0 }; -FTS * -fts_open(argv, options, compar) +static FTS * +_fts_open_common(argv, priv) char * const *argv; - int options; - int (*compar)(const FTSENT * const *, const FTSENT * const *); -{ struct _fts_private *priv; - FTS *sp; +{ + FTS *sp = &priv->ftsp_fts; FTSENT *p, *root; FTSENT *parent, *tmp; 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. */ tmp = NULL; @@ -177,7 +161,7 @@ * If comparison routine supplied, traverse in sorted * order; otherwise traverse in the order specified. */ - if (compar) { + if (sp->fts_compar) { p->fts_link = root; root = p; } else { @@ -190,7 +174,7 @@ } } } - if (compar && nitems > 1) + if (sp->fts_compar && nitems > 1) root = fts_sort(sp, root, nitems); /* @@ -223,6 +207,66 @@ 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 fts_load(FTS *sp, FTSENT *p) { @@ -274,6 +318,11 @@ free(sp->fts_array); 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. */ if (!ISSET(FTS_NOCHDIR)) { saved_errno = fchdir(sp->fts_rfd) ? errno : 0; @@ -970,6 +1019,17 @@ 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 * fts_sort(FTS *sp, FTSENT *head, size_t nitems) { @@ -992,7 +1052,11 @@ } for (ap = sp->fts_array, p = head; p; p = p->fts_link) *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) ap[0]->fts_link = ap[1]; ap[0]->fts_link = NULL; Index: lib/libc/gen/glob.3 =================================================================== --- lib/libc/gen/glob.3 +++ lib/libc/gen/glob.3 @@ -30,11 +30,12 @@ .\" @(#)glob.3 8.3 (Berkeley) 4/16/94 .\" $FreeBSD$ .\" -.Dd December 20, 2011 +.Dd May 5, 2014 .Dt GLOB 3 .Os .Sh NAME .Nm glob , +.Nm glob_b , .Nm globfree .Nd generate pathnames matching a pattern .Sh LIBRARY @@ -43,6 +44,8 @@ .In glob.h .Ft int .Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *, int)" "glob_t * restrict pglob" +.Ft int +.Fn glob_b "const char * restrict pattern" "int flags" "int (^errblock)(const char *, int)" "glob_t * restrict pglob" .Ft void .Fn globfree "glob_t *pglob" .Sh DESCRIPTION @@ -72,7 +75,7 @@ is a pointer to a pathname pattern to be expanded. The .Fn glob -argument +function matches all accessible pathnames against the pattern and creates a list of the pathnames that match. In order to have access to a pathname, @@ -88,7 +91,7 @@ .Pp The .Fn glob -argument +function stores the number of matched pathnames into the .Fa gl_pathc field, and a pointer to a list of pointers to pathnames into the @@ -323,6 +326,12 @@ .Fa errfunc returns zero, the error is ignored. .Pp +.Fn glob_b +is a block-based version of +.Fn glob . +where the error callback is the block pointer, +.Fa errblock . +.Pp The .Fn globfree function frees any space associated with @@ -332,7 +341,9 @@ .Sh RETURN VALUES On successful completion, .Fn glob -returns zero. +and +.Fn glob_b +return zero. In addition the fields of .Fa pglob contain the values described below: @@ -341,12 +352,16 @@ contains the total number of matched pathnames so far. This includes other matches from previous invocations of .Fn glob +or +.Fn glob_b if .Dv GLOB_APPEND was specified. .It Fa gl_matchc contains the number of matched pathnames in the current invocation of -.Fn glob . +.Fn glob +or +.Fn glob_b . .It Fa gl_flags contains a copy of the .Fa flags @@ -369,6 +384,8 @@ .Pp If .Fn glob +or +.Fn glob_b terminates due to an error, it sets errno and returns one of the following non-zero constants, which are defined in the include file @@ -452,6 +469,11 @@ .Fn globfree functions first appeared in .Bx 4.4 . +The +.Fn glob_b +function first appeared in Mac OS X. +This implementation was created by Stacey Son for +.Fx 11.0 . .Sh BUGS Patterns longer than .Dv MAXPATHLEN @@ -459,7 +481,9 @@ .Pp The .Fn glob -argument +or +.Fn glob_b +function may fail and set errno for any of the errors specified for the library routines .Xr stat 2 , Index: lib/libc/gen/glob.c =================================================================== --- lib/libc/gen/glob.c +++ lib/libc/gen/glob.c @@ -92,8 +92,12 @@ #include #include +#include "block_abi.h" #include "collate.h" +/* errblock_t */ +typedef DECLARE_BLOCK(int, errblock_t, const char *, int); + /* * glob(3) expansion limits. Stop the expansion if any of these limits * is reached. This caps the runtime in the face of DoS attacks. See @@ -189,9 +193,9 @@ static void qprintf(const char *, Char *); #endif -int -glob(const char * __restrict pattern, int flags, - int (*errfunc)(const char *, int), glob_t * __restrict pglob) +static int +_glob_common(const char * __restrict pattern, int flags, + glob_t * __restrict pglob) { struct glob_limit limit = { 0, 0, 0, 0, 0 }; const char *patnext; @@ -212,8 +216,6 @@ if (limit.l_path_lim == 0) limit.l_path_lim = GLOB_LIMIT_PATH; } - pglob->gl_flags = flags & ~GLOB_MAGCHAR; - pglob->gl_errfunc = errfunc; pglob->gl_matchc = 0; bufnext = patbuf; @@ -258,6 +260,28 @@ return (glob0(patbuf, pglob, &limit)); } +int +glob(const char * __restrict pattern, int flags, + int (*errfunc)(const char *, int), glob_t * __restrict pglob) +{ + + pglob->gl_flags = flags & ~(GLOB_MAGCHAR | _GLOB_ERRBLK); + pglob->gl_errfunc = errfunc; + return (_glob_common(pattern, flags, pglob)); +} + +int +glob_b(const char * __restrict pattern, int flags, errblock_t errblock, + glob_t * __restrict pglob) +{ + + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_flags |= _GLOB_ERRBLK; + pglob->gl_errblk = (void *)errblock; + + return (_glob_common(pattern, flags, pglob)); +} + /* * Expand recursively a glob {} pattern. When there is no more expansion * invoke the standard globbing routine to glob the rest of the magic @@ -649,6 +673,7 @@ DIR *dirp; int err; char buf[MAXPATHLEN]; + int (*errfunc)(const char *, int); /* * The readdirfunc declaration can't be prototyped, because it is @@ -668,7 +693,13 @@ if (pglob->gl_errfunc) { if (g_Ctoc(pathbuf, buf, sizeof(buf))) return (GLOB_ABORTED); - if (pglob->gl_errfunc(buf, errno) || +printf("glob3: %p %d\n", buf, errno); + if (pglob->gl_flags & _GLOB_ERRBLK) + errfunc = (int (*)(const char *, int)) + GET_BLOCK_FUNCTION(pglob->gl_errblk); + else + errfunc = pglob->gl_errfunc; + if ((*errfunc)(buf, errno) || pglob->gl_flags & GLOB_ERR) return (GLOB_ABORTED); } Index: lib/libc/include/block_abi.h =================================================================== --- lib/libc/include/block_abi.h +++ lib/libc/include/block_abi.h @@ -61,3 +61,9 @@ int reserved;\ void (*invoke)(void *, ...);\ }*)(void*)x)->invoke) + +/* + * _Block_copy() and _Block_release() are provided by libBlocksRuntime. + */ +__attribute__((__weak__)) void *_Block_copy(void *); +__attribute__((__weak__)) void _Block_release(void *);