Extending find(1) to support -printf
Jeremy Chadwick
koitsu at FreeBSD.org
Fri Sep 5 10:12:54 UTC 2008
I've been working on $SUBJECT for the past few hours, and have managed
to implement a very crude subset of GNU find's features:
http://www.gnu.org/software/findutils/manual/html_node/find_html/Format-Directives.html#Format-Directives
I've implemented %f and %p (which appear identical to GNU find), and
some escaped characters.
Things I need help with, as string parsing in C has never been my forte
(which will become quite obvious):
1) Getting %h to behave like GNU find. The GNU find code is
significantly different than ours. As it stands, %h is broken.
2) find . -printf '\' results in odd output (SHELL=/usr/local/bin/bash
on my box). Not sure why this is happening, but it's a big concern.
3) Security issues. I believe use of a large number of formatting
variables could exceed the calloc()'d buffer (of MAXPATHLEN), causing
a segfault at bare minimum. I'm not sure how to work around this.
Also, some folks on #bsdports asked why I was bothering with this in the
first place: mutt supports backticks to run shell commands inside of
a muttrc file. See "Building a list of mailboxes on the fly" below:
http://wiki.mutt.org/?ConfigTricks
Note the find ... -printf '%h ' method. I can accomplish (just
about) the same using `echo $HOME/Maildir/*`, but if I want to
exclude an entry, I can't use | grep -v, because mutt doesn't support
pipes within backticks. :-)
--
| Jeremy Chadwick jdc at parodius.com |
| Parodius Networking http://www.parodius.com/ |
| UNIX Systems Administrator Mountain View, CA, USA |
| Making life hard for others since 1977. PGP: 4BD6C0CB |
diff -ruN find.orig/extern.h find/extern.h
--- find.orig/extern.h 2006-05-14 13:23:00.000000000 -0700
+++ find/extern.h 2008-09-04 20:55:17.000000000 -0700
@@ -73,6 +73,7 @@
creat_f c_nouser;
creat_f c_perm;
creat_f c_print;
+creat_f c_printf;
creat_f c_regex;
creat_f c_simple;
creat_f c_size;
@@ -107,6 +108,7 @@
exec_f f_perm;
exec_f f_print;
exec_f f_print0;
+exec_f f_printf;
exec_f f_prune;
exec_f f_regex;
exec_f f_size;
diff -ruN find.orig/function.c find/function.c
--- find.orig/function.c 2006-05-27 11:27:41.000000000 -0700
+++ find/function.c 2008-09-05 03:01:36.000000000 -0700
@@ -1272,6 +1272,86 @@
/* c_print0 is the same as c_print */
/*
+ * -printf functions --
+ *
+ * Always true, manipulates output based on printf()-like
+ * formatting characters.
+ */
+int
+f_printf(PLAN *plan, FTSENT *entry)
+{
+ char *scan;
+ char *outptr;
+ char *outidx;
+
+ if ((outptr = calloc(MAXPATHLEN, 1)) == NULL)
+ err(1, NULL);
+
+ outidx = outptr;
+
+ for (scan = plan->c_data; *scan; scan++) {
+ if (*scan == '%') {
+ if (scan[1] == 0) {
+ errx(1, "missing format character");
+ }
+ else if (scan[1] == '%') {
+ *outidx++ = '%';
+ }
+ else if (scan[1] == 'f') {
+ strcpy(outidx, entry->fts_name);
+ outidx += entry->fts_namelen;
+ }
+ /* XXX - needs to behave like GNU find %h */
+ /*
+ else if (scan[1] == 'h') {
+ strcpy(outidx, entry->fts_path);
+ outidx += entry->fts_pathlen;
+ }
+ */
+ else if (scan[1] == 'p') {
+ strcpy(outidx, entry->fts_path);
+ outidx += entry->fts_pathlen;
+ }
+ scan++;
+ }
+ else if (*scan == '\\') {
+ if (scan[1] == '\\') {
+ *outidx++ = '\\';
+ }
+ else if (scan[1] == 'n') {
+ *outidx++ = '\n';
+ }
+ else if (scan[1] == 't') {
+ *outidx++ = '\t';
+ }
+ scan++;
+ }
+ else {
+ *outidx++ = *scan;
+ }
+ }
+
+ (void)printf(outptr);
+ free(outptr);
+ return 1;
+}
+
+PLAN *
+c_printf(OPTION *option, char ***argvp)
+{
+ char *argstring;
+ PLAN *new;
+
+ argstring = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+ isoutput = 1;
+
+ new = palloc(option);
+ new->c_data = argstring;
+ return new;
+}
+
+/*
* -prune functions --
*
* Prune a portion of the hierarchy.
diff -ruN find.orig/option.c find/option.c
--- find.orig/option.c 2006-04-05 16:06:11.000000000 -0700
+++ find/option.c 2008-09-04 20:48:18.000000000 -0700
@@ -128,6 +128,7 @@
{ "-perm", c_perm, f_perm, 0 },
{ "-print", c_print, f_print, 0 },
{ "-print0", c_print, f_print0, 0 },
+ { "-printf", c_printf, f_printf, 0 },
{ "-prune", c_simple, f_prune, 0 },
{ "-regex", c_regex, f_regex, 0 },
{ "-size", c_size, f_size, 0 },
More information about the freebsd-hackers
mailing list