From owner-freebsd-hackers@FreeBSD.ORG Fri Sep 5 10:12:54 2008 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 482721065672 for ; Fri, 5 Sep 2008 10:12:54 +0000 (UTC) (envelope-from jdc@koitsu.dyndns.org) Received: from QMTA07.emeryville.ca.mail.comcast.net (qmta07.emeryville.ca.mail.comcast.net [76.96.30.64]) by mx1.freebsd.org (Postfix) with ESMTP id 2FB008FC1B for ; Fri, 5 Sep 2008 10:12:54 +0000 (UTC) (envelope-from jdc@koitsu.dyndns.org) Received: from OMTA01.emeryville.ca.mail.comcast.net ([76.96.30.11]) by QMTA07.emeryville.ca.mail.comcast.net with comcast id AxkX1a00b0EPchoA7yCtdX; Fri, 05 Sep 2008 10:12:53 +0000 Received: from koitsu.dyndns.org ([67.180.253.227]) by OMTA01.emeryville.ca.mail.comcast.net with comcast id AyCt1a0024v8bD78MyCtx7; Fri, 05 Sep 2008 10:12:53 +0000 X-Authority-Analysis: v=1.0 c=1 a=mDV3o1hIAAAA:8 a=d-pe6f8hAAAA:8 a=QycZ5dHgAAAA:8 a=Mz5a3wwlWe91LHh15DEA:9 a=D3htHCIYvMoiOQUTshUA:7 a=GrxJ2iga8-3bqyOpsyTwt2a2q2UA:4 a=EoioJ0NPDVgA:10 a=CWfAmLVWKswA:10 Received: by icarus.home.lan (Postfix, from userid 1000) id 27EB717B81A; Fri, 5 Sep 2008 03:12:53 -0700 (PDT) Date: Fri, 5 Sep 2008 03:12:53 -0700 From: Jeremy Chadwick To: freebsd-hackers@freebsd.org Message-ID: <20080905101253.GA53396@icarus.home.lan> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) Subject: Extending find(1) to support -printf X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 05 Sep 2008 10:12:54 -0000 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 },