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 },
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to